Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
2f6d7c1b34
|
@ -1293,7 +1293,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
|
|||
flush_workqueue(ar->hw->workqueue);
|
||||
|
||||
cancel_delayed_work_sync(&ar->tx_janitor);
|
||||
#ifdef CONFIG_AR9170_LEDS
|
||||
cancel_delayed_work_sync(&ar->led_work);
|
||||
#endif
|
||||
cancel_work_sync(&ar->filter_config_work);
|
||||
cancel_work_sync(&ar->beacon_work);
|
||||
mutex_lock(&ar->mutex);
|
||||
|
|
|
@ -18,6 +18,6 @@ config ATH9K_DEBUG
|
|||
Say Y, if you need ath9k to display debug messages.
|
||||
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
|
||||
|
|
|
@ -190,12 +190,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
#define ATH_AGGR_MIN_QDEPTH 2
|
||||
#define ATH_AMPDU_SUBFRAME_DEFAULT 32
|
||||
#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_MAX 4096
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
|
||||
#define IEEE80211_WEP_IVLEN 3
|
||||
#define IEEE80211_WEP_KIDLEN 1
|
||||
#define IEEE80211_WEP_CRCLEN 4
|
||||
|
@ -240,7 +237,6 @@ struct ath_txq {
|
|||
spinlock_t axq_lock;
|
||||
u32 axq_depth;
|
||||
u8 axq_aggr_depth;
|
||||
u32 axq_totalqueued;
|
||||
bool stopped;
|
||||
bool axq_tx_inprogress;
|
||||
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_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
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,
|
||||
u16 tid, u16 *ssn);
|
||||
int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn);
|
||||
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);
|
||||
|
||||
/********/
|
||||
|
@ -576,6 +572,7 @@ struct ath_softc {
|
|||
u32 keymax;
|
||||
DECLARE_BITMAP(keymap, ATH_KEYMAX);
|
||||
u8 splitmic;
|
||||
bool ps_enabled;
|
||||
unsigned long ps_usecount;
|
||||
enum ath9k_int imask;
|
||||
enum ath9k_ht_extprotspacing ht_extprotspacing;
|
||||
|
|
|
@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
|
|||
"NF calibrated [ctl] [chain 1] is %d\n", 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),
|
||||
AR_PHY_CH2_MINCCA_PWR);
|
||||
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);
|
||||
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),
|
||||
AR_PHY_CH2_EXT_MINCCA_PWR);
|
||||
if (nf & 0x100)
|
||||
|
@ -613,7 +613,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
|
||||
if (AR_SREV_9285(ah))
|
||||
chainmask = 0x9;
|
||||
else if (AR_SREV_9280(ah))
|
||||
else if (AR_SREV_9280(ah) || AR_SREV_9287(ah))
|
||||
chainmask = 0x1B;
|
||||
else
|
||||
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))
|
||||
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_hw_getnf(ah, chan);
|
||||
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;
|
||||
} else {
|
||||
if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
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);
|
||||
if (!AR_SREV_9287_10_OR_LATER(ah))
|
||||
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 */
|
||||
|
@ -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)) {
|
||||
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);
|
||||
if (!AR_SREV_9287_10_OR_LATER(ah))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -486,6 +486,83 @@ static const struct file_operations fops_wiphy = {
|
|||
.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)
|
||||
{
|
||||
|
@ -529,6 +606,13 @@ int ath9k_init_debug(struct ath_softc *sc)
|
|||
if (!sc->debug.debugfs_wiphy)
|
||||
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;
|
||||
err:
|
||||
ath9k_exit_debug(sc);
|
||||
|
@ -537,6 +621,7 @@ err:
|
|||
|
||||
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_rcstat);
|
||||
debugfs_remove(sc->debug.debugfs_interrupt);
|
||||
|
|
|
@ -35,6 +35,15 @@ enum ATH_DEBUG {
|
|||
|
||||
#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
|
||||
|
||||
/**
|
||||
|
@ -87,9 +96,45 @@ struct ath_rc_stats {
|
|||
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_interrupt_stats istats;
|
||||
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
|
||||
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
|
||||
};
|
||||
|
||||
struct ath9k_debug {
|
||||
|
@ -100,6 +145,7 @@ struct ath9k_debug {
|
|||
struct dentry *debugfs_interrupt;
|
||||
struct dentry *debugfs_rcstat;
|
||||
struct dentry *debugfs_wiphy;
|
||||
struct dentry *debugfs_xmit;
|
||||
struct ath_stats stats;
|
||||
};
|
||||
|
||||
|
@ -110,6 +156,8 @@ int ath9k_debug_create_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_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,
|
||||
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,
|
||||
int xretries, int retries, u8 per)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -100,6 +100,8 @@
|
|||
#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) && \
|
||||
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_S 2
|
||||
|
@ -176,6 +178,57 @@
|
|||
|
||||
#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 {
|
||||
EEP_NFTHRESH_5,
|
||||
EEP_NFTHRESH_2,
|
||||
|
@ -199,7 +252,11 @@ enum eeprom_param {
|
|||
EEP_OL_PWRCTRL,
|
||||
EEP_RC_CHAIN_MASK,
|
||||
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 {
|
||||
|
@ -368,6 +425,65 @@ struct modal_eep_4k_header {
|
|||
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
|
||||
} __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 {
|
||||
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
|
@ -402,6 +518,29 @@ struct cal_ctl_edges {
|
|||
} __packed;
|
||||
#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_edges
|
||||
ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
|
||||
|
@ -461,6 +600,27 @@ struct ar5416_eeprom_4k {
|
|||
u8 padding;
|
||||
} __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 {
|
||||
REG_EXT_JAPAN_MIDBAND = 1,
|
||||
REG_EXT_FCC_DFS_HT40 = 2,
|
||||
|
@ -480,6 +640,7 @@ struct ath9k_country_entry {
|
|||
enum ath9k_eep_map {
|
||||
EEP_MAP_DEFAULT = 0x0,
|
||||
EEP_MAP_4KBITS,
|
||||
EEP_MAP_AR9287,
|
||||
EEP_MAP_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -380,6 +380,9 @@ static const char *ath9k_hw_devname(u16 devid)
|
|||
return "Atheros 9280";
|
||||
case AR9285_DEVID_PCIE:
|
||||
return "Atheros 9285";
|
||||
case AR5416_DEVID_AR9287_PCI:
|
||||
case AR5416_DEVID_AR9287_PCIE:
|
||||
return "Atheros 9287";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -475,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
|
|||
|
||||
ah->gbeacon_rate = 0;
|
||||
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
|
||||
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) &&
|
||||
(ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
|
||||
(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,
|
||||
"Mac Chip Rev 0x%02x.%x is not supported by "
|
||||
"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;
|
||||
if (AR_SREV_9280_10_OR_LATER(ah))
|
||||
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,
|
||||
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)
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
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_PCIE:
|
||||
case AR9285_DEVID_PCIE:
|
||||
case AR5416_DEVID_AR9287_PCI:
|
||||
case AR5416_DEVID_AR9287_PCIE:
|
||||
ah = ath9k_hw_do_attach(devid, sc, error);
|
||||
break;
|
||||
default:
|
||||
|
@ -1341,10 +1391,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
|
|||
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);
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
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);
|
||||
if (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);
|
||||
|
||||
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_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"
|
||||
};
|
||||
|
||||
if (ah->power_mode == mode)
|
||||
return status;
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
|
||||
modes[ah->power_mode], modes[mode]);
|
||||
|
||||
|
@ -2783,10 +2868,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
|
|||
if (++sc->ps_usecount != 1)
|
||||
goto unlock;
|
||||
|
||||
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
|
||||
sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
|
||||
ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
|
||||
}
|
||||
ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
|
||||
|
||||
unlock:
|
||||
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)
|
||||
goto unlock;
|
||||
|
||||
if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
|
||||
!(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
|
||||
SC_OP_WAIT_FOR_CAB |
|
||||
SC_OP_WAIT_FOR_PSPOLL_DATA |
|
||||
SC_OP_WAIT_FOR_TX_ACK)))
|
||||
ath9k_hw_setpower_nolock(sc->sc_ah,
|
||||
sc->sc_ah->restore_mode);
|
||||
if (sc->ps_enabled &&
|
||||
!(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
|
||||
SC_OP_WAIT_FOR_CAB |
|
||||
SC_OP_WAIT_FOR_PSPOLL_DATA |
|
||||
SC_OP_WAIT_FOR_TX_ACK)))
|
||||
ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
|
||||
|
||||
unlock:
|
||||
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)
|
||||
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;
|
||||
else if (AR_SREV_9280_10_OR_LATER(ah))
|
||||
return MS_REG_READ(AR928X, gpio) != 0;
|
||||
|
|
|
@ -42,6 +42,9 @@
|
|||
#define AR_SUBVENDOR_ID_NEW_A 0x7065
|
||||
#define AR5416_MAGIC 0x19641014
|
||||
|
||||
#define AR5416_DEVID_AR9287_PCI 0x002D
|
||||
#define AR5416_DEVID_AR9287_PCIE 0x002E
|
||||
|
||||
/* Register read/write primitives */
|
||||
#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
|
||||
#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
|
||||
|
@ -400,6 +403,7 @@ struct ath_hw {
|
|||
union {
|
||||
struct ar5416_eeprom_def def;
|
||||
struct ar5416_eeprom_4k map4k;
|
||||
struct ar9287_eeprom_t map9287;
|
||||
} eeprom;
|
||||
const struct eeprom_ops *eep_ops;
|
||||
enum ath9k_eep_map eep_map;
|
||||
|
@ -417,7 +421,6 @@ struct ath_hw {
|
|||
|
||||
enum nl80211_iftype opmode;
|
||||
enum ath9k_power_mode power_mode;
|
||||
enum ath9k_power_mode restore_mode;
|
||||
|
||||
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
|
||||
struct ar5416Stats stats;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,8 +17,6 @@
|
|||
#include <linux/nl80211.h>
|
||||
#include "ath9k.h"
|
||||
|
||||
#define ATH_PCI_VERSION "0.1"
|
||||
|
||||
static char *dev_info = "ath9k";
|
||||
|
||||
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) {
|
||||
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);
|
||||
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
|
||||
an->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
@ -499,8 +497,7 @@ static void ath9k_tasklet(unsigned long data)
|
|||
if (status & ATH9K_INT_TX)
|
||||
ath_tx_tasklet(sc);
|
||||
|
||||
if ((status & ATH9K_INT_TSFOOR) &&
|
||||
(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
|
||||
if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
|
||||
/*
|
||||
* TSF sync does not look correct; remain awake to sync with
|
||||
* 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,
|
||||
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;
|
||||
|
||||
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_DSSSCCK40;
|
||||
|
||||
ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
|
||||
ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
|
||||
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
|
||||
|
||||
/* set up supported mcs set */
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
|
@ -2003,7 +1998,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (sc->hw->conf.flags & IEEE80211_CONF_PS) {
|
||||
if (sc->ps_enabled) {
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
/*
|
||||
* 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_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
|
||||
sc->ps_enabled = true;
|
||||
} else {
|
||||
sc->ps_enabled = false;
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
|
@ -2671,19 +2667,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
|||
case IEEE80211_AMPDU_RX_STOP:
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
ret = ath_tx_aggr_start(sc, sta, tid, ssn);
|
||||
if (ret < 0)
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Unable to start TX aggregation\n");
|
||||
else
|
||||
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ath_tx_aggr_start(sc, sta, tid, ssn);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
ret = ath_tx_aggr_stop(sc, sta, tid);
|
||||
if (ret < 0)
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Unable to stop TX aggregation\n");
|
||||
|
||||
ath_tx_aggr_stop(sc, sta, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
|
@ -2761,7 +2749,8 @@ static struct {
|
|||
{ AR_SREV_VERSION_9100, "9100" },
|
||||
{ AR_SREV_VERSION_9160, "9160" },
|
||||
{ AR_SREV_VERSION_9280, "9280" },
|
||||
{ AR_SREV_VERSION_9285, "9285" }
|
||||
{ AR_SREV_VERSION_9285, "9285" },
|
||||
{ AR_SREV_VERSION_9287, "9287" }
|
||||
};
|
||||
|
||||
static struct {
|
||||
|
|
|
@ -25,6 +25,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
|
|||
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
|
||||
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
|
||||
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
|
||||
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
|
||||
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -375,6 +375,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
|
|||
#define AR_PHY_CHAN_INFO_GAIN 0x9CFC
|
||||
|
||||
#define AR_PHY_MODE 0xA200
|
||||
#define AR_PHY_MODE_ASYNCFIFO 0x80
|
||||
#define AR_PHY_MODE_AR2133 0x08
|
||||
#define AR_PHY_MODE_AR5111 0x00
|
||||
#define AR_PHY_MODE_AR5112 0x08
|
||||
|
|
|
@ -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 list_head *bf_head);
|
||||
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct ath_txq *txq,
|
||||
struct list_head *bf_q,
|
||||
int txok, int sendbar);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -220,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
|
|||
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 ieee80211_hdr *hdr;
|
||||
|
||||
bf->bf_state.bf_type |= BUF_RETRY;
|
||||
bf->bf_retries++;
|
||||
TX_STAT_INC(txq->axq_qnum, a_retries);
|
||||
|
||||
skb = bf->bf_mpdu;
|
||||
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) &&
|
||||
ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
|
||||
if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
|
||||
ath_tx_set_retry(sc, bf);
|
||||
ath_tx_set_retry(sc, txq, bf);
|
||||
txpending = 1;
|
||||
} else {
|
||||
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_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
|
||||
} else {
|
||||
/* retry the un-acked ones */
|
||||
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;
|
||||
ath_tx_rc_status(bf, ds, nbad,
|
||||
0, false);
|
||||
ath_tx_complete_buf(sc, bf, &bf_head,
|
||||
0, 0);
|
||||
ath_tx_complete_buf(sc, bf, txq,
|
||||
&bf_head, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -455,7 +458,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
|||
struct ieee80211_tx_rate *rates;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
u32 max_4ms_framelen, frmlen;
|
||||
u16 aggr_limit, legacy = 0, maxampdu;
|
||||
u16 aggr_limit, legacy = 0;
|
||||
int i;
|
||||
|
||||
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)
|
||||
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).
|
||||
* The IE, however can hold upto 65536, which shows up here
|
||||
* as zero. Ignore 65536 since we are constrained by hw.
|
||||
*/
|
||||
maxampdu = tid->an->maxampdu;
|
||||
if (maxampdu)
|
||||
aggr_limit = min(aggr_limit, maxampdu);
|
||||
if (tid->an->maxampdu)
|
||||
aggr_limit = min(aggr_limit, tid->an->maxampdu);
|
||||
|
||||
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
|
||||
* 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,
|
||||
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;
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
u32 nsymbits, nsymbols, mpdudensity;
|
||||
u32 nsymbits, nsymbols;
|
||||
u16 minlen;
|
||||
u8 rc, flags, rix;
|
||||
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
|
||||
* required minimum length for subframe. Take into account
|
||||
* 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
|
||||
* is needed.
|
||||
*/
|
||||
if (mpdudensity == 0)
|
||||
|
||||
if (tid->an->mpdudensity == 0)
|
||||
return ndelim;
|
||||
|
||||
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;
|
||||
|
||||
if (half_gi)
|
||||
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
|
||||
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
|
||||
else
|
||||
nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
|
||||
nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
|
||||
|
||||
if (nsymbols == 0)
|
||||
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,
|
||||
struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid,
|
||||
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;
|
||||
|
||||
} while (!list_empty(&tid->buf_q));
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -690,30 +691,26 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
txq->axq_aggr_depth++;
|
||||
ath_tx_txqaddbuf(sc, txq, &bf_q);
|
||||
TX_STAT_INC(txq->axq_qnum, a_aggr);
|
||||
|
||||
} while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
|
||||
status != ATH_AGGR_BAW_CLOSED);
|
||||
}
|
||||
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
{
|
||||
struct ath_atx_tid *txtid;
|
||||
struct ath_node *an;
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
if (sc->sc_flags & SC_OP_TXAGGR) {
|
||||
txtid = ATH_AN_2_TID(an, tid);
|
||||
txtid->state |= AGGR_ADDBA_PROGRESS;
|
||||
ath_tx_pause_tid(sc, txtid);
|
||||
*ssn = txtid->seq_start;
|
||||
}
|
||||
|
||||
return 0;
|
||||
txtid = ATH_AN_2_TID(an, tid);
|
||||
txtid->state |= AGGR_ADDBA_PROGRESS;
|
||||
ath_tx_pause_tid(sc, txtid);
|
||||
*ssn = txtid->seq_start;
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
if (txtid->state & AGGR_CLEANUP)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
|
||||
txtid->state &= ~AGGR_ADDBA_PROGRESS;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
|
@ -756,8 +753,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
|||
txtid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
ath_tx_flush_tid(sc, txtid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
txq->axq_depth = 0;
|
||||
txq->axq_aggr_depth = 0;
|
||||
txq->axq_totalqueued = 0;
|
||||
txq->axq_linkbuf = NULL;
|
||||
txq->axq_tx_inprogress = false;
|
||||
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))
|
||||
ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
|
||||
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);
|
||||
|
@ -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);
|
||||
txq->axq_depth++;
|
||||
txq->axq_totalqueued++;
|
||||
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
|
||||
|
||||
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->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:
|
||||
|
@ -1281,6 +1275,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
|
|||
bf->bf_lastbf = bf;
|
||||
ath_buf_set_rate(sc, bf);
|
||||
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,
|
||||
|
@ -1294,6 +1289,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
|
|||
bf->bf_nframes = 1;
|
||||
ath_buf_set_rate(sc, bf);
|
||||
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)
|
||||
|
@ -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,
|
||||
struct ath_txq *txq,
|
||||
struct list_head *bf_q,
|
||||
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;
|
||||
int tx_flags = 0;
|
||||
|
||||
|
||||
if (sendbar)
|
||||
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);
|
||||
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
|
||||
|
@ -2026,7 +2023,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
if (bf_isampdu(bf))
|
||||
ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
|
||||
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);
|
||||
|
||||
|
@ -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,
|
||||
tx_complete_work.work);
|
||||
|
|
|
@ -450,7 +450,7 @@ static struct country_code_to_enum_rd allCountries[] = {
|
|||
{CTRY_SWITZERLAND, ETSI1_WORLD, "CH"},
|
||||
{CTRY_SYRIA, NULL1_WORLD, "SY"},
|
||||
{CTRY_TAIWAN, APL3_FCCA, "TW"},
|
||||
{CTRY_THAILAND, NULL1_WORLD, "TH"},
|
||||
{CTRY_THAILAND, FCC3_WORLD, "TH"},
|
||||
{CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"},
|
||||
{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
|
||||
{CTRY_TURKEY, ETSI3_WORLD, "TR"},
|
||||
|
|
|
@ -9,6 +9,9 @@ config IWLWIFI
|
|||
config IWLWIFI_LEDS
|
||||
bool "Enable LED support in iwlagn and iwl3945 drivers"
|
||||
depends on IWLWIFI
|
||||
default y
|
||||
---help---
|
||||
Select this if you want LED support.
|
||||
|
||||
config IWLWIFI_SPECTRUM_MEASUREMENT
|
||||
bool "Enable Spectrum Measurement in iwlagn driver"
|
||||
|
|
|
@ -55,13 +55,88 @@
|
|||
#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
|
||||
#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 = {
|
||||
.name = "1000 Series BGN",
|
||||
.fw_name_pre = IWL1000_FW_PRE,
|
||||
.ucode_api_max = IWL1000_UCODE_API_MAX,
|
||||
.ucode_api_min = IWL1000_UCODE_API_MIN,
|
||||
.sku = IWL_SKU_G|IWL_SKU_N,
|
||||
.ops = &iwl5000_ops,
|
||||
.ops = &iwl1000_ops,
|
||||
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
||||
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
||||
|
|
|
@ -79,11 +79,10 @@ static const struct {
|
|||
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
|
||||
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
|
||||
|
||||
static int iwl3945_led_cmd_callback(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd,
|
||||
struct sk_buff *skb)
|
||||
static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
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,
|
||||
.len = sizeof(struct iwl_led_cmd),
|
||||
.data = led_cmd,
|
||||
.meta.flags = CMD_ASYNC,
|
||||
.meta.u.callback = iwl3945_led_cmd_callback,
|
||||
.flags = CMD_ASYNC,
|
||||
.callback = iwl3945_led_cmd_callback,
|
||||
};
|
||||
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
|
|
|
@ -749,8 +749,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
|
|||
/* Unmap tx_cmd */
|
||||
if (counter)
|
||||
pci_unmap_single(dev,
|
||||
pci_unmap_addr(&txq->cmd[index]->meta, mapping),
|
||||
pci_unmap_len(&txq->cmd[index]->meta, len),
|
||||
pci_unmap_addr(&txq->meta[index], mapping),
|
||||
pci_unmap_len(&txq->meta[index], len),
|
||||
PCI_DMA_TODEVICE);
|
||||
|
||||
/* 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:
|
||||
*
|
||||
*/
|
||||
void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_hdr *hdr, int sta_id, int tx_id)
|
||||
void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
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 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 = {
|
||||
.id = REPLY_RXON_ASSOC,
|
||||
.len = sizeof(rxon_assoc),
|
||||
.meta.flags = CMD_WANT_SKB,
|
||||
.flags = CMD_WANT_SKB,
|
||||
.data = &rxon_assoc,
|
||||
};
|
||||
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)
|
||||
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) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
priv->alloc_rxb_skb--;
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
dev_kfree_skb_any(cmd.reply_skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -254,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv,
|
|||
struct iwl_tx_queue *txq);
|
||||
extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
|
||||
struct iwl3945_frame *frame, u8 rate);
|
||||
void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_hdr *hdr,
|
||||
int sta_id, int tx_id);
|
||||
void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct ieee80211_tx_info *info,
|
||||
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_set_txpower(struct iwl_priv *priv, s8 power);
|
||||
extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
|
||||
|
|
|
@ -776,7 +776,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
|
|||
static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* 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;
|
||||
iwl_tt_handler(priv);
|
||||
set_bit(STATUS_TEMPERATURE, &priv->status);
|
||||
|
||||
if (!priv->disable_tx_power_cal &&
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
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);
|
||||
}
|
||||
|
||||
static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
|
||||
u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_eeprom_calib_hdr {
|
||||
u8 version;
|
||||
|
@ -436,7 +436,7 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
|
|||
.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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static int iwl5000_load_ucode(struct iwl_priv *priv)
|
||||
int iwl5000_load_ucode(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -658,7 +658,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void iwl5000_init_alive_start(struct iwl_priv *priv)
|
||||
void iwl5000_init_alive_start(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -734,7 +734,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
|
|||
sizeof(coex_cmd), &coex_cmd);
|
||||
}
|
||||
|
||||
static int iwl5000_alive_notify(struct iwl_priv *priv)
|
||||
int iwl5000_alive_notify(struct iwl_priv *priv)
|
||||
{
|
||||
u32 a;
|
||||
unsigned long flags;
|
||||
|
@ -821,7 +821,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
|
|||
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) ||
|
||||
(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
|
||||
*/
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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 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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -1048,7 +1048,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
|
|||
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)
|
||||
{
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
@ -1312,13 +1312,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 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 */
|
||||
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 */
|
||||
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) &&
|
||||
(addr < IWL50_RTC_DATA_UPPER_BOUND);
|
||||
|
@ -1381,7 +1381,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
|
|||
|
||||
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;
|
||||
u8 tx_ant_cfg_cmd;
|
||||
|
@ -1401,10 +1401,11 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv)
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void iwl5000_temperature(struct iwl_priv *priv)
|
||||
void iwl5000_temperature(struct iwl_priv *priv)
|
||||
{
|
||||
/* store temperature from statistics (in Celsius) */
|
||||
priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
|
||||
iwl_tt_handler(priv);
|
||||
}
|
||||
|
||||
static void iwl5150_temperature(struct iwl_priv *priv)
|
||||
|
|
|
@ -61,6 +61,63 @@
|
|||
#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
|
||||
#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 = {
|
||||
.get_hcmd_size = iwl5000_get_hcmd_size,
|
||||
.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 = {
|
||||
.ucode = &iwl5000_ucode,
|
||||
.lib = &iwl5000_lib,
|
||||
.lib = &iwl6000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
.utils = &iwl6000_hcmd_utils,
|
||||
};
|
||||
|
|
|
@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
struct sk_buff *skb,
|
||||
struct ieee80211_sta *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);
|
||||
|
||||
|
||||
|
@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
int ret = 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 (; ;) {
|
||||
lq_sta->action_counter++;
|
||||
switch (tbl->action) {
|
||||
|
@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
u8 update_search_tbl_counter = 0;
|
||||
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 (;;) {
|
||||
lq_sta->action_counter++;
|
||||
switch (tbl->action) {
|
||||
|
@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
|||
u8 update_search_tbl_counter = 0;
|
||||
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 (;;) {
|
||||
lq_sta->action_counter++;
|
||||
switch (tbl->action) {
|
||||
|
@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
|||
int ret;
|
||||
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 (;;) {
|
||||
lq_sta->action_counter++;
|
||||
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.
|
||||
*/
|
||||
|
@ -2098,6 +2140,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
|
||||
if (!((1 << index) & rate_scale_index_msk)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2149,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
tbl->expected_tpt[index] + 64) / 128));
|
||||
|
||||
/* 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;
|
||||
* no need to send new link quality command, since we're
|
||||
* 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) ||
|
||||
(current_tpt > (100 * tbl->expected_tpt[low]))))
|
||||
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) {
|
||||
case -1:
|
||||
/* Decrease starting rate, update uCode's rate table */
|
||||
|
@ -2308,15 +2364,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
|
||||
lq_update:
|
||||
/* Replace uCode's rate table for the destination station. */
|
||||
if (update_lq) {
|
||||
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);
|
||||
if (update_lq)
|
||||
rate = rs_update_rate_tbl(priv, lq_sta,
|
||||
tbl, index, is_green);
|
||||
|
||||
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:
|
||||
* 1) Not changing rates right now
|
||||
|
@ -2373,7 +2429,8 @@ lq_update:
|
|||
* have been tried and compared, stay in this best modulation
|
||||
* mode for a while before next round of mode comparisons. */
|
||||
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) &&
|
||||
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
|
||||
(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);
|
||||
}
|
||||
|
||||
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_scale_tbl_info tbl_type;
|
||||
|
|
|
@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
|
|||
/* Unmap tx_cmd */
|
||||
if (num_tbs)
|
||||
pci_unmap_single(dev,
|
||||
pci_unmap_addr(&txq->cmd[index]->meta, mapping),
|
||||
pci_unmap_len(&txq->cmd[index]->meta, len),
|
||||
pci_unmap_addr(&txq->meta[index], mapping),
|
||||
pci_unmap_len(&txq->meta[index], len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
/* 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;
|
||||
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
|
||||
unsigned long status = priv->status;
|
||||
unsigned long reg_flags;
|
||||
|
||||
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
|
||||
(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);
|
||||
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
|
||||
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)
|
||||
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));
|
||||
|
||||
iwl_power_initialize(priv);
|
||||
iwl_tt_initialize(priv);
|
||||
return 0;
|
||||
|
||||
out_remove_sysfs:
|
||||
|
@ -3067,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|||
iwl_down(priv);
|
||||
}
|
||||
|
||||
iwl_tt_exit(priv);
|
||||
|
||||
/* make sure we flush any pending irq or
|
||||
* tasklet for the driver
|
||||
*/
|
||||
|
|
|
@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
|
|||
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_PHY_CALIBRATION_CMD,
|
||||
.meta.flags = CMD_SIZE_HUGE,
|
||||
.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
|
||||
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 = {
|
||||
.id = SENSITIVITY_CMD,
|
||||
.len = sizeof(struct iwl_sensitivity_cmd),
|
||||
.meta.flags = CMD_ASYNC,
|
||||
.flags = CMD_ASYNC,
|
||||
.data = &cmd,
|
||||
};
|
||||
|
||||
|
|
|
@ -2413,6 +2413,13 @@ struct iwl_ct_kill_config {
|
|||
__le32 critical_temperature_R;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 1000, and 6x00 */
|
||||
struct iwl_ct_kill_throttling_config {
|
||||
__le32 critical_temperature_exit;
|
||||
__le32 reserved;
|
||||
__le32 critical_temperature_enter;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/******************************************************************************
|
||||
* (8)
|
||||
* Scan Commands, Responses, Notifications:
|
||||
|
|
|
@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
|
|||
if (!sta_ht_inf->ht_supported)
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (priv->disable_ht40)
|
||||
return 0;
|
||||
#endif
|
||||
return iwl_is_channel_extension(priv, priv->band,
|
||||
le16_to_cpu(priv->staging_rxon.channel),
|
||||
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, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *desc_lookup_text[] = {
|
||||
"OK",
|
||||
|
@ -1496,6 +1499,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
|
|||
iwl_print_event_log(priv, 0, next_entry, mode);
|
||||
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* 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;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_STATISTICS_CMD,
|
||||
.meta.flags = flags,
|
||||
.flags = flags,
|
||||
.len = sizeof(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)
|
||||
{
|
||||
struct iwl_ct_kill_config cmd;
|
||||
struct iwl_ct_kill_throttling_config adv_cmd;
|
||||
unsigned long flags;
|
||||
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,
|
||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
priv->power_data.ct_kill_toggle = false;
|
||||
|
||||
cmd.critical_temperature_R =
|
||||
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
||||
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
|
||||
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,
|
||||
sizeof(cmd), &cmd);
|
||||
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,
|
||||
.len = sizeof(u32),
|
||||
.data = &flags,
|
||||
.meta.flags = meta_flag,
|
||||
.flags = meta_flag,
|
||||
};
|
||||
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
|
|
|
@ -446,9 +446,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
|
|||
u16 len, const void *data);
|
||||
int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
|
||||
const void *data,
|
||||
int (*callback)(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd,
|
||||
struct sk_buff *skb));
|
||||
void (*callback)(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb));
|
||||
|
||||
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
|
||||
|
||||
|
|
|
@ -84,9 +84,11 @@ struct iwl_debugfs {
|
|||
struct dentry *file_status;
|
||||
struct dentry *file_interrupt;
|
||||
struct dentry *file_qos;
|
||||
struct dentry *file_thermal_throttling;
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
struct dentry *file_led;
|
||||
#endif
|
||||
struct dentry *file_disable_ht40;
|
||||
} dbgfs_data_files;
|
||||
struct dir_rf_files {
|
||||
struct dentry *file_disable_sensitivity;
|
||||
|
|
|
@ -618,6 +618,84 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
|
|||
}
|
||||
#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_WRITE_FILE_OPS(log_event);
|
||||
DEBUGFS_READ_FILE_OPS(nvm);
|
||||
|
@ -631,6 +709,8 @@ DEBUGFS_READ_FILE_OPS(qos);
|
|||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
DEBUGFS_READ_FILE_OPS(led);
|
||||
#endif
|
||||
DEBUGFS_READ_FILE_OPS(thermal_throttling);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
|
||||
|
||||
/*
|
||||
* 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
|
||||
DEBUGFS_ADD_FILE(led, data);
|
||||
#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_chain_noise, rf,
|
||||
&priv->disable_chain_noise_cal);
|
||||
|
@ -709,6 +791,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
|||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
|
||||
#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->dbgfs_rf_files.file_disable_sensitivity);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
|
||||
|
|
|
@ -63,6 +63,8 @@ extern struct iwl_cfg iwl6050_2agn_cfg;
|
|||
extern struct iwl_cfg iwl6050_3agn_cfg;
|
||||
extern struct iwl_cfg iwl1000_bgn_cfg;
|
||||
|
||||
struct iwl_tx_queue;
|
||||
|
||||
/* shared structures from iwl-5000.c */
|
||||
extern struct iwl_mod_params iwl50_mod_params;
|
||||
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);
|
||||
extern int iwl5000_calc_rssi(struct iwl_priv *priv,
|
||||
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 */
|
||||
#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.
|
||||
* This may be because we're:
|
||||
|
@ -120,6 +150,31 @@ struct iwl_rx_mem_buffer {
|
|||
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
|
||||
*
|
||||
|
@ -147,7 +202,8 @@ struct iwl_tx_info {
|
|||
* struct iwl_tx_queue - Tx Queue for DMA
|
||||
* @q: generic Rx/Tx queue descriptor
|
||||
* @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
|
||||
* @txb: array of per-TFD driver data
|
||||
* @need_update: indicates need to update read/write index
|
||||
|
@ -162,7 +218,8 @@ struct iwl_tx_info {
|
|||
struct iwl_tx_queue {
|
||||
struct iwl_queue q;
|
||||
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;
|
||||
u8 need_update;
|
||||
u8 sched_retry;
|
||||
|
@ -299,35 +356,16 @@ enum {
|
|||
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
|
||||
|
||||
/**
|
||||
* struct iwl_cmd
|
||||
* struct iwl_device_cmd
|
||||
*
|
||||
* 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
|
||||
* (which is relatively huge; space is allocated separately).
|
||||
*/
|
||||
struct iwl_cmd {
|
||||
struct iwl_cmd_meta meta; /* driver data */
|
||||
struct iwl_device_cmd {
|
||||
struct iwl_cmd_header hdr; /* uCode API */
|
||||
union {
|
||||
u32 flags;
|
||||
|
@ -339,17 +377,20 @@ struct iwl_cmd {
|
|||
} __attribute__ ((packed)) cmd;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
|
||||
|
||||
|
||||
struct iwl_host_cmd {
|
||||
u8 id;
|
||||
u16 len;
|
||||
struct iwl_cmd_meta meta;
|
||||
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
|
||||
*/
|
||||
|
@ -450,8 +491,16 @@ union iwl_ht_rate_supp {
|
|||
};
|
||||
|
||||
#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 {
|
||||
/* self configuration data */
|
||||
|
@ -630,6 +679,8 @@ struct iwl_hw_params {
|
|||
u32 max_data_size;
|
||||
u32 max_bsm_size;
|
||||
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;
|
||||
const struct iwl_sensitivity_ranges *sens;
|
||||
};
|
||||
|
@ -1113,6 +1164,7 @@ struct iwl_priv {
|
|||
/* debugging info */
|
||||
u32 framecnt_to_us;
|
||||
atomic_t restrict_refcnt;
|
||||
bool disable_ht40;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/* debugfs */
|
||||
struct iwl_debugfs *dbgfs;
|
||||
|
|
|
@ -103,22 +103,23 @@ EXPORT_SYMBOL(get_cmd_string);
|
|||
|
||||
#define HOST_COMPLETE_TIMEOUT (HZ / 2)
|
||||
|
||||
static int iwl_generic_cmd_callback(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd, struct sk_buff *skb)
|
||||
static void iwl_generic_cmd_callback(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = NULL;
|
||||
|
||||
if (!skb) {
|
||||
IWL_ERR(priv, "Error: Response NULL in %s.\n",
|
||||
get_cmd_string(cmd->hdr.cmd));
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = (struct iwl_rx_packet *)skb->data;
|
||||
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
|
||||
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
|
@ -127,29 +128,26 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
|
|||
case SENSITIVITY_CMD:
|
||||
IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
|
||||
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
|
||||
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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. */
|
||||
BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
|
||||
BUG_ON(cmd->flags & CMD_WANT_SKB);
|
||||
|
||||
/* Assign a generic callback if one is not provided */
|
||||
if (!cmd->meta.u.callback)
|
||||
cmd->meta.u.callback = iwl_generic_cmd_callback;
|
||||
if (!cmd->callback)
|
||||
cmd->callback = iwl_generic_cmd_callback;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EBUSY;
|
||||
|
@ -168,10 +166,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
int cmd_idx;
|
||||
int ret;
|
||||
|
||||
BUG_ON(cmd->meta.flags & CMD_ASYNC);
|
||||
BUG_ON(cmd->flags & CMD_ASYNC);
|
||||
|
||||
/* 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)) {
|
||||
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);
|
||||
|
||||
if (cmd->meta.flags & CMD_WANT_SKB)
|
||||
cmd->meta.source = &cmd->meta;
|
||||
|
||||
cmd_idx = iwl_enqueue_hcmd(priv, cmd);
|
||||
if (cmd_idx < 0) {
|
||||
ret = cmd_idx;
|
||||
|
@ -222,7 +217,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
ret = -EIO;
|
||||
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",
|
||||
get_cmd_string(cmd->id));
|
||||
ret = -EIO;
|
||||
|
@ -233,20 +228,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
goto out;
|
||||
|
||||
cancel:
|
||||
if (cmd->meta.flags & CMD_WANT_SKB) {
|
||||
struct iwl_cmd *qcmd;
|
||||
|
||||
/* Cancel the CMD_WANT_SKB flag for the cmd in the
|
||||
if (cmd->flags & CMD_WANT_SKB) {
|
||||
/*
|
||||
* Cancel the CMD_WANT_SKB flag for the cmd in the
|
||||
* TX cmd queue. Otherwise in case the cmd comes
|
||||
* in later, it will possibly set an invalid
|
||||
* address (cmd->meta.source). */
|
||||
qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
|
||||
qcmd->meta.flags &= ~CMD_WANT_SKB;
|
||||
* address (cmd->meta.source).
|
||||
*/
|
||||
priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
|
||||
~CMD_WANT_SKB;
|
||||
}
|
||||
fail:
|
||||
if (cmd->meta.u.skb) {
|
||||
dev_kfree_skb_any(cmd->meta.u.skb);
|
||||
cmd->meta.u.skb = NULL;
|
||||
if (cmd->reply_skb) {
|
||||
dev_kfree_skb_any(cmd->reply_skb);
|
||||
cmd->reply_skb = NULL;
|
||||
}
|
||||
out:
|
||||
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)
|
||||
{
|
||||
if (cmd->meta.flags & CMD_ASYNC)
|
||||
if (cmd->flags & CMD_ASYNC)
|
||||
return iwl_send_cmd_async(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,
|
||||
u8 id, u16 len, const void *data,
|
||||
int (*callback)(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd,
|
||||
struct sk_buff *skb))
|
||||
void (*callback)(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = id,
|
||||
|
@ -287,8 +282,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
|
|||
.data = data,
|
||||
};
|
||||
|
||||
cmd.meta.flags |= CMD_ASYNC;
|
||||
cmd.meta.u.callback = callback;
|
||||
cmd.flags |= CMD_ASYNC;
|
||||
cmd.callback = callback;
|
||||
|
||||
return iwl_send_cmd_async(priv, &cmd);
|
||||
}
|
||||
|
|
|
@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
|
|||
.id = REPLY_LEDS_CMD,
|
||||
.len = sizeof(struct iwl_led_cmd),
|
||||
.data = led_cmd,
|
||||
.meta.flags = CMD_ASYNC,
|
||||
.meta.u.callback = NULL,
|
||||
.flags = CMD_ASYNC,
|
||||
.callback = NULL,
|
||||
};
|
||||
u32 reg;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-debug.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}
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
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);
|
||||
int ret = 0;
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
u16 uninitialized_var(final_mode);
|
||||
bool update_chains;
|
||||
|
||||
|
@ -223,6 +264,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
|||
if (setting->power_disabled)
|
||||
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) &&
|
||||
((setting->power_mode != final_mode) || force)) {
|
||||
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);
|
||||
|
||||
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 */
|
||||
void iwl_power_initialize(struct iwl_priv *priv)
|
||||
{
|
||||
|
|
|
@ -33,6 +33,84 @@
|
|||
|
||||
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 {
|
||||
IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
|
||||
IWL_POWER_INDEX_1,
|
||||
|
@ -59,10 +137,25 @@ struct iwl_power_mgr {
|
|||
u8 power_mode;
|
||||
u8 user_power_setting; /* set by user through sysfs */
|
||||
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_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);
|
||||
|
||||
#endif /* __iwl_power_setting_h__ */
|
||||
|
|
|
@ -115,7 +115,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
|
|||
struct iwl_rx_packet *res;
|
||||
struct iwl_host_cmd 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
|
||||
|
@ -132,7 +132,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
|
|||
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) {
|
||||
/* The scan abort will return 1 for success or
|
||||
* 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--;
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
dev_kfree_skb_any(cmd.reply_skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
|
|||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SCAN_CMD,
|
||||
.len = sizeof(struct iwl_scan_cmd),
|
||||
.meta.flags = CMD_SIZE_HUGE,
|
||||
.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
struct iwl_scan_cmd *scan;
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
|
|
|
@ -97,8 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
|
|||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
}
|
||||
|
||||
static int iwl_add_sta_callback(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd, struct sk_buff *skb)
|
||||
static void iwl_add_sta_callback(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_rx_packet *res = NULL;
|
||||
struct iwl_addsta_cmd *addsta =
|
||||
|
@ -107,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
|
|||
|
||||
if (!skb) {
|
||||
IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
res = (struct iwl_rx_packet *)skb->data;
|
||||
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
|
||||
res->hdr.flags);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We didn't cache the SKB; let the caller free it */
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)];
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_ADD_STA,
|
||||
.meta.flags = flags,
|
||||
.flags = flags,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
cmd.meta.u.callback = iwl_add_sta_callback;
|
||||
cmd.callback = iwl_add_sta_callback;
|
||||
else
|
||||
cmd.meta.flags |= CMD_WANT_SKB;
|
||||
cmd.flags |= CMD_WANT_SKB;
|
||||
|
||||
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
|
||||
ret = iwl_send_cmd(priv, &cmd);
|
||||
|
@ -154,7 +152,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
|
|||
if (ret || (flags & CMD_ASYNC))
|
||||
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) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
|
||||
res->hdr.flags);
|
||||
|
@ -175,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
|
|||
}
|
||||
|
||||
priv->alloc_rxb_skb--;
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
dev_kfree_skb_any(cmd.reply_skb);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int iwl_remove_sta_callback(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd, struct sk_buff *skb)
|
||||
static void iwl_remove_sta_callback(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_rx_packet *res = NULL;
|
||||
struct iwl_rem_sta_cmd *rm_sta =
|
||||
|
@ -334,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
|
|||
|
||||
if (!skb) {
|
||||
IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
res = (struct iwl_rx_packet *)skb->data;
|
||||
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
|
||||
res->hdr.flags);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
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,
|
||||
|
@ -368,7 +364,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
|
|||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_REMOVE_STA,
|
||||
.len = sizeof(struct iwl_rem_sta_cmd),
|
||||
.meta.flags = flags,
|
||||
.flags = flags,
|
||||
.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);
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
cmd.meta.u.callback = iwl_remove_sta_callback;
|
||||
cmd.callback = iwl_remove_sta_callback;
|
||||
else
|
||||
cmd.meta.flags |= CMD_WANT_SKB;
|
||||
cmd.flags |= CMD_WANT_SKB;
|
||||
ret = iwl_send_cmd(priv, &cmd);
|
||||
|
||||
if (ret || (flags & CMD_ASYNC))
|
||||
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) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
|
||||
res->hdr.flags);
|
||||
|
@ -406,7 +402,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
|
|||
}
|
||||
|
||||
priv->alloc_rxb_skb--;
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
dev_kfree_skb_any(cmd.reply_skb);
|
||||
|
||||
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 = {
|
||||
.id = REPLY_WEPKEY,
|
||||
.data = wep_cmd,
|
||||
.meta.flags = CMD_ASYNC,
|
||||
.flags = CMD_ASYNC,
|
||||
};
|
||||
|
||||
memset(wep_cmd, 0, cmd_size +
|
||||
|
@ -930,7 +926,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
|
|||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_TX_LINK_QUALITY_CMD,
|
||||
.len = sizeof(struct iwl_link_quality_cmd),
|
||||
.meta.flags = flags,
|
||||
.flags = flags,
|
||||
.data = lq,
|
||||
};
|
||||
|
||||
|
|
|
@ -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))
|
||||
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 */
|
||||
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);
|
||||
txq->txb = NULL;
|
||||
|
||||
/* deallocate arrays */
|
||||
kfree(txq->cmd);
|
||||
kfree(txq->meta);
|
||||
txq->cmd = NULL;
|
||||
txq->meta = NULL;
|
||||
|
||||
/* 0-fill queue descriptor structure */
|
||||
memset(txq, 0, sizeof(*txq));
|
||||
}
|
||||
|
@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
|
|||
if (q->n_bd == 0)
|
||||
return;
|
||||
|
||||
len = sizeof(struct iwl_cmd) * q->n_window;
|
||||
len = sizeof(struct iwl_device_cmd) * q->n_window;
|
||||
len += IWL_MAX_SCAN_SIZE;
|
||||
|
||||
/* 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 ret;
|
||||
int actual_slots = slots_num;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* space is needed.
|
||||
*/
|
||||
len = sizeof(struct iwl_cmd);
|
||||
for (i = 0; i <= slots_num; i++) {
|
||||
if (i == slots_num) {
|
||||
if (txq_id == IWL_CMD_QUEUE_NUM)
|
||||
len += IWL_MAX_SCAN_SIZE;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (txq_id == IWL_CMD_QUEUE_NUM)
|
||||
actual_slots++;
|
||||
|
||||
txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
|
||||
GFP_KERNEL);
|
||||
txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
|
||||
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);
|
||||
if (!txq->cmd[i])
|
||||
|
@ -364,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
|||
|
||||
return 0;
|
||||
err:
|
||||
for (i = 0; i < slots_num; i++) {
|
||||
for (i = 0; i < actual_slots; 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;
|
||||
}
|
||||
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 iwl_tx_queue *txq;
|
||||
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;
|
||||
int swq_id, txq_id;
|
||||
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 */
|
||||
out_cmd = txq->cmd[q->write_ptr];
|
||||
out_meta = &txq->meta[q->write_ptr];
|
||||
tx_cmd = &out_cmd->cmd.tx;
|
||||
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
|
||||
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,
|
||||
&out_cmd->hdr, len,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
|
||||
pci_unmap_len_set(&out_cmd->meta, len, len);
|
||||
pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
|
||||
pci_unmap_len_set(out_meta, len, len);
|
||||
/* Add buffer containing Tx command and MAC(!) header to TFD's
|
||||
* first entry */
|
||||
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_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;
|
||||
unsigned long flags;
|
||||
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
|
||||
* we will need to increase the size of the TFD entries */
|
||||
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
|
||||
!(cmd->meta.flags & CMD_SIZE_HUGE));
|
||||
!(cmd->flags & CMD_SIZE_HUGE));
|
||||
|
||||
if (iwl_is_rfkill(priv)) {
|
||||
IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
|
||||
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");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
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_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;
|
||||
memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
|
||||
memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
|
||||
|
||||
/* 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.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
|
||||
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;
|
||||
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;
|
||||
|
||||
|
||||
|
@ -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,
|
||||
fix_size, PCI_DMA_BIDIRECTIONAL);
|
||||
pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
|
||||
pci_unmap_len_set(&out_cmd->meta, len, fix_size);
|
||||
pci_unmap_addr_set(out_meta, mapping, phys_addr);
|
||||
pci_unmap_len_set(out_meta, len, fix_size);
|
||||
|
||||
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
|
||||
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_addr(&txq->cmd[cmd_idx]->meta, mapping),
|
||||
pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
|
||||
pci_unmap_addr(&txq->meta[cmd_idx], mapping),
|
||||
pci_unmap_len(&txq->meta[cmd_idx], len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
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 cmd_index;
|
||||
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
|
||||
* 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,
|
||||
priv->txq[IWL_CMD_QUEUE_NUM].q.read_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;
|
||||
}
|
||||
|
||||
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
|
||||
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. */
|
||||
if (cmd->meta.flags & CMD_WANT_SKB) {
|
||||
cmd->meta.source->u.skb = rxb->skb;
|
||||
rxb->skb = NULL;
|
||||
} else if (cmd->meta.u.callback &&
|
||||
!cmd->meta.u.callback(priv, cmd, rxb->skb))
|
||||
if (meta->flags & CMD_WANT_SKB) {
|
||||
meta->source->reply_skb = rxb->skb;
|
||||
rxb->skb = NULL;
|
||||
} else if (meta->callback)
|
||||
meta->callback(priv, cmd, rxb->skb);
|
||||
|
||||
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);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct iwl_cmd *cmd,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct sk_buff *skb_frag,
|
||||
int sta_id)
|
||||
{
|
||||
|
@ -403,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
|
|||
* handle build REPLY_TX command notification.
|
||||
*/
|
||||
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_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 iwl_tx_queue *txq = 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 txcmd_phys;
|
||||
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 */
|
||||
out_cmd = txq->cmd[idx];
|
||||
out_meta = &txq->meta[idx];
|
||||
tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
|
||||
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
|
||||
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);
|
||||
/* we do not map meta data ... so we can safely access address to
|
||||
* provide to unmap command*/
|
||||
pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
|
||||
pci_unmap_len_set(&out_cmd->meta, len, len);
|
||||
pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
|
||||
pci_unmap_len_set(out_meta, len, len);
|
||||
|
||||
/* Add buffer containing Tx command and MAC(!) header to TFD's
|
||||
* first entry */
|
||||
|
@ -753,7 +755,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
|
|||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
|
||||
.data = (void *)&spectrum,
|
||||
.meta.flags = CMD_WANT_SKB,
|
||||
.flags = CMD_WANT_SKB,
|
||||
};
|
||||
u32 add_time = le64_to_cpu(params->start_time);
|
||||
int rc;
|
||||
|
@ -794,7 +796,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
|
|||
if (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) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
|
||||
rc = -EIO;
|
||||
|
@ -817,7 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
|
|||
break;
|
||||
}
|
||||
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
dev_kfree_skb_any(cmd.reply_skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -2717,7 +2719,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
|
|||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SCAN_CMD,
|
||||
.len = sizeof(struct iwl3945_scan_cmd),
|
||||
.meta.flags = CMD_SIZE_HUGE,
|
||||
.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
int rc = 0;
|
||||
struct iwl3945_scan_cmd *scan;
|
||||
|
|
|
@ -2,7 +2,6 @@ config IWM
|
|||
tristate "Intel Wireless Multicomm 3200 WiFi driver"
|
||||
depends on MMC && WLAN_80211 && EXPERIMENTAL
|
||||
depends on CFG80211
|
||||
select WIRELESS_EXT
|
||||
select FW_LOADER
|
||||
help
|
||||
The Intel Wireless Multicomm 3200 hardware is a combo
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
obj-$(CONFIG_IWM) := iwmc3200wifi.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
|
||||
|
|
|
@ -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_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,
|
||||
struct iwm_if_ops *if_ops);
|
||||
void iwm_if_free(struct iwm_priv *iwm);
|
||||
|
|
|
@ -121,7 +121,6 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
|||
}
|
||||
|
||||
ndev->netdev_ops = &iwm_netdev_ops;
|
||||
ndev->wireless_handlers = &iwm_iw_handler_def;
|
||||
ndev->ieee80211_ptr = wdev;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
||||
wdev->netdev = ndev;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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)
|
||||
*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;
|
||||
|
||||
*queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
|
||||
|
|
|
@ -1511,9 +1511,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev)
|
|||
struct pcmcia_device *link = local->finder;
|
||||
struct status __iomem *p = local->sram + STATUS_BASE;
|
||||
|
||||
if (local == (ray_dev_t *) NULL)
|
||||
return (iw_stats *) NULL;
|
||||
|
||||
local->wstats.status = local->card_status;
|
||||
#ifdef WIRELESS_SPY
|
||||
if ((local->spy_data.spy_number > 0)
|
||||
|
|
|
@ -124,7 +124,7 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
|
|||
}
|
||||
|
||||
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 *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
|
||||
* active setting. If that has happened we can quit.
|
||||
*/
|
||||
ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx);
|
||||
ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx);
|
||||
ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx);
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -156,11 +156,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
|||
* The latter is required since we need to recalibrate the
|
||||
* 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);
|
||||
|
||||
memcpy(active, ant, sizeof(*ant));
|
||||
memcpy(active, &ant, sizeof(ant));
|
||||
|
||||
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
|
||||
|
|
|
@ -88,7 +88,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
|
|||
struct rt2x00_intf *intf,
|
||||
struct ieee80211_bss_conf *conf);
|
||||
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
||||
struct antenna_setup *ant);
|
||||
struct antenna_setup ant);
|
||||
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_conf *conf,
|
||||
const unsigned int changed_flags);
|
||||
|
|
|
@ -173,7 +173,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
|
|||
if (ant->flags & ANTENNA_TX_DIVERSITY)
|
||||
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)
|
||||
|
@ -213,7 +213,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
|
|||
if (ant->flags & ANTENNA_TX_DIVERSITY)
|
||||
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)
|
||||
|
|
|
@ -378,7 +378,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
|
||||
rt2x00lib_config_antenna(rt2x00dev,
|
||||
&rt2x00dev->default_ant);
|
||||
rt2x00dev->default_ant);
|
||||
|
||||
/* Turn RX back on */
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
|
||||
|
|
|
@ -802,6 +802,31 @@ struct ieee80211_ht_cap {
|
|||
#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03
|
||||
#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
|
||||
*
|
||||
|
|
|
@ -262,6 +262,9 @@
|
|||
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
|
||||
* %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_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -336,6 +339,8 @@ enum nl80211_commands {
|
|||
NL80211_CMD_ROAM,
|
||||
NL80211_CMD_DISCONNECT,
|
||||
|
||||
NL80211_CMD_SET_WIPHY_NETNS,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* 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
|
||||
* with %NL80211_KEY_* sub-attributes
|
||||
*
|
||||
* @NL80211_ATTR_PID: Process ID of a network namespace.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -701,6 +708,8 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_KEY,
|
||||
NL80211_ATTR_KEYS,
|
||||
|
||||
NL80211_ATTR_PID,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
|
|
@ -542,7 +542,7 @@ struct cfg80211_ssid {
|
|||
* @ie: optional information element(s) to add into Probe Request or %NULL
|
||||
* @ie_len: length of ie in octets
|
||||
* @wiphy: the wiphy this was for
|
||||
* @ifidx: the interface index
|
||||
* @dev: the interface
|
||||
*/
|
||||
struct cfg80211_scan_request {
|
||||
struct cfg80211_ssid *ssids;
|
||||
|
@ -554,7 +554,7 @@ struct cfg80211_scan_request {
|
|||
|
||||
/* internal */
|
||||
struct wiphy *wiphy;
|
||||
int ifidx;
|
||||
struct net_device *dev;
|
||||
bool aborted;
|
||||
};
|
||||
|
||||
|
@ -845,7 +845,8 @@ struct cfg80211_bitrate_mask {
|
|||
* @resume: wiphy device needs to be resumed
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
|
@ -937,7 +938,7 @@ struct cfg80211_ops {
|
|||
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
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,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
|
@ -1088,6 +1089,9 @@ struct cfg80211_ops {
|
|||
* @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
|
||||
* -1 = fragmentation disabled, only odd values >= 256 used
|
||||
* @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 {
|
||||
/* assign these fields before you register the wiphy */
|
||||
|
@ -1101,6 +1105,8 @@ struct wiphy {
|
|||
bool custom_regulatory;
|
||||
bool strict_regulatory;
|
||||
|
||||
bool netnsok;
|
||||
|
||||
enum cfg80211_signal_type signal_type;
|
||||
|
||||
int bss_priv_size;
|
||||
|
@ -1139,9 +1145,35 @@ struct wiphy {
|
|||
/* dir in debugfs: ieee80211/<wiphyname> */
|
||||
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)));
|
||||
};
|
||||
|
||||
#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
|
||||
*
|
||||
|
@ -1563,43 +1595,6 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
|
|||
int cfg80211_wext_giwrange(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
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_param *data, char *extra);
|
||||
|
||||
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
|
||||
struct iw_freq *freq);
|
||||
|
||||
int cfg80211_wext_siwfreq(struct net_device *dev,
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
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_param *wrq, char *extra);
|
||||
|
||||
int cfg80211_wds_wext_siwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *addr, char *extra);
|
||||
int cfg80211_wds_wext_giwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *addr, char *extra);
|
||||
int cfg80211_wext_siwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *ap_addr, char *extra);
|
||||
int cfg80211_wext_giwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *ap_addr, char *extra);
|
||||
|
||||
/*
|
||||
* callbacks for asynchronous cfg80211 methods, notification
|
||||
|
|
|
@ -243,6 +243,9 @@ struct ieee80211_bss_conf {
|
|||
* used to indicate that a frame was already retried due to PS
|
||||
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
|
||||
* 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 {
|
||||
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_RETRIED = BIT(15),
|
||||
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
|
||||
IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17),
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -5344,6 +5344,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
|
|||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_change_net_namespace);
|
||||
|
||||
static int dev_cpu_callback(struct notifier_block *nfb,
|
||||
unsigned long action,
|
||||
|
|
|
@ -6,7 +6,6 @@ config MAC80211
|
|||
select CRYPTO_ARC4
|
||||
select CRYPTO_AES
|
||||
select CRC32
|
||||
select WIRELESS_EXT
|
||||
---help---
|
||||
This option enables the hardware independent IEEE 802.11
|
||||
networking stack.
|
||||
|
|
|
@ -3,7 +3,6 @@ obj-$(CONFIG_MAC80211) += mac80211.o
|
|||
# mac80211 objects
|
||||
mac80211-y := \
|
||||
main.o \
|
||||
wext.o \
|
||||
sta_info.o \
|
||||
wep.o \
|
||||
wpa.o \
|
||||
|
|
|
@ -57,19 +57,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
|||
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;
|
||||
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);
|
||||
ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -742,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
|
|||
if (!netif_running(sdata->dev))
|
||||
return;
|
||||
|
||||
if (local->sw_scanning || local->hw_scanning)
|
||||
if (local->scanning)
|
||||
return;
|
||||
|
||||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "key.h"
|
||||
#include "sta_info.h"
|
||||
|
@ -570,6 +569,43 @@ enum queue_stop_reason {
|
|||
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 {
|
||||
/* embed the driver visible part.
|
||||
* don't cast (use the static inlines below), but we keep
|
||||
|
@ -668,7 +704,7 @@ struct ieee80211_local {
|
|||
|
||||
/* Scanning and BSS list */
|
||||
struct mutex scan_mtx;
|
||||
bool sw_scanning, hw_scanning;
|
||||
unsigned long scanning;
|
||||
struct cfg80211_ssid scan_ssid;
|
||||
struct cfg80211_scan_request int_scan_req;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
|
@ -678,7 +714,7 @@ struct ieee80211_local {
|
|||
int scan_channel_idx;
|
||||
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 ieee80211_sub_if_data *scan_sdata;
|
||||
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);
|
||||
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 */
|
||||
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_init_conf conf;
|
||||
struct sta_info *sta;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb, *tmp;
|
||||
u32 hw_reconf_flags = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
if (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;
|
||||
}
|
||||
|
||||
|
@ -669,7 +684,6 @@ static void ieee80211_if_setup(struct net_device *dev)
|
|||
{
|
||||
ether_setup(dev);
|
||||
dev->netdev_ops = &ieee80211_dataif_ops;
|
||||
dev->wireless_handlers = &ieee80211_iw_handler_def;
|
||||
dev->destructor = free_netdev;
|
||||
}
|
||||
|
||||
|
@ -772,6 +786,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
name, ieee80211_if_setup);
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
|
||||
|
||||
ndev->needed_headroom = local->tx_headroom +
|
||||
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);
|
||||
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 */
|
||||
sdata = netdev_priv(ndev);
|
||||
|
@ -905,7 +919,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
|
||||
if (local->hw_scanning || local->sw_scanning)
|
||||
if (local->scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
|
|
|
@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
/*
|
||||
|
@ -620,6 +620,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
if (!wiphy)
|
||||
return NULL;
|
||||
|
||||
wiphy->netnsok = true;
|
||||
wiphy->privid = mac80211_wiphy_privid;
|
||||
|
||||
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
|
||||
|
|
|
@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
|
|||
if (!netif_running(sdata->dev))
|
||||
return;
|
||||
|
||||
if (local->sw_scanning || local->hw_scanning)
|
||||
if (local->scanning)
|
||||
return;
|
||||
|
||||
while ((skb = skb_dequeue(&ifmsh->skb_queue)))
|
||||
|
|
|
@ -581,7 +581,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
if (!ifmgd->associated)
|
||||
return;
|
||||
|
||||
if (sdata->local->sw_scanning || sdata->local->hw_scanning)
|
||||
if (sdata->local->scanning)
|
||||
return;
|
||||
|
||||
/* 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
|
||||
* take effect when scan finishes.
|
||||
*/
|
||||
if (local->hw_scanning || local->sw_scanning)
|
||||
if (local->scanning)
|
||||
return;
|
||||
|
||||
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))
|
||||
return;
|
||||
|
||||
if (sdata->local->scanning)
|
||||
return;
|
||||
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
|
||||
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:
|
||||
cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
|
||||
break;
|
||||
case RX_MGMT_CFG80211_DEAUTH:
|
||||
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL);
|
||||
break;
|
||||
default:
|
||||
WARN(1, "unexpected: %d", rma);
|
||||
}
|
||||
|
@ -2038,7 +2044,7 @@ static void ieee80211_sta_work(struct work_struct *work)
|
|||
if (!netif_running(sdata->dev))
|
||||
return;
|
||||
|
||||
if (local->sw_scanning || local->hw_scanning)
|
||||
if (local->scanning)
|
||||
return;
|
||||
|
||||
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,
|
||||
u.mgd.monitor_work);
|
||||
|
||||
if (sdata->local->sw_scanning || sdata->local->hw_scanning)
|
||||
return;
|
||||
|
||||
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->auth_alg = auth_alg;
|
||||
wk->timeout = jiffies; /* run right away */
|
||||
|
||||
/*
|
||||
* 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->tries = 0;
|
||||
wk->timeout = jiffies; /* run right away */
|
||||
|
||||
if (req->use_mfp) {
|
||||
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);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
@ -2522,8 +2532,13 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
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);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
|
|
@ -418,10 +418,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
|
|||
struct ieee80211_local *local = rx->local;
|
||||
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);
|
||||
|
||||
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 */
|
||||
if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -782,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
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);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (skb) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr =
|
||||
(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.
|
||||
*/
|
||||
set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
|
||||
info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
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
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
|
||||
dev_queue_xmit(skb);
|
||||
ieee80211_add_pending_skb(rx->local, skb);
|
||||
|
||||
if (no_pending_pkts)
|
||||
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);
|
||||
memset(info, 0, sizeof(*info));
|
||||
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);
|
||||
if (is_multicast_ether_addr(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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ieee80211_parse_qos(&rx);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
|
@ -265,7 +264,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
|
||||
if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) {
|
||||
if (WARN_ON(!local->scanning)) {
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
return;
|
||||
}
|
||||
|
@ -275,16 +274,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
return;
|
||||
}
|
||||
|
||||
if (local->hw_scanning)
|
||||
if (test_bit(SCAN_HW_SCANNING, &local->scanning))
|
||||
ieee80211_restore_scan_ies(local);
|
||||
|
||||
if (local->scan_req != &local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, aborted);
|
||||
local->scan_req = NULL;
|
||||
|
||||
was_hw_scan = local->hw_scanning;
|
||||
local->hw_scanning = false;
|
||||
local->sw_scanning = false;
|
||||
was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
local->scanning = 0;
|
||||
local->scan_channel = NULL;
|
||||
|
||||
/* 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(
|
||||
sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.associated) {
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
ieee80211_scan_ps_enable(sdata);
|
||||
}
|
||||
} else
|
||||
/*
|
||||
* only handle non-STA interfaces here, STA interfaces
|
||||
* are handled in the scan state machine
|
||||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
local->scan_state = SCAN_SET_CHANNEL;
|
||||
local->next_scan_state = SCAN_DECISION;
|
||||
local->scan_channel_idx = 0;
|
||||
|
||||
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)
|
||||
local->hw_scanning = true;
|
||||
__set_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
else
|
||||
local->sw_scanning = true;
|
||||
__set_bit(SCAN_SW_SCANNING, &local->scanning);
|
||||
/*
|
||||
* Kicking off the scan need not be protected,
|
||||
* 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);
|
||||
|
||||
if (rc) {
|
||||
if (local->ops->hw_scan) {
|
||||
local->hw_scanning = false;
|
||||
if (local->ops->hw_scan)
|
||||
ieee80211_restore_scan_ies(local);
|
||||
} else
|
||||
local->sw_scanning = false;
|
||||
local->scanning = 0;
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
|
@ -474,13 +469,195 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
|||
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)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, scan_work.work);
|
||||
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
|
||||
struct ieee80211_channel *chan;
|
||||
int skip, i;
|
||||
unsigned long next_delay = 0;
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
|
@ -489,7 +666,7 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
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;
|
||||
int rc;
|
||||
|
||||
|
@ -513,69 +690,30 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
switch (local->scan_state) {
|
||||
case SCAN_SET_CHANNEL:
|
||||
/* if no more bands/channels left, complete scan */
|
||||
if (local->scan_channel_idx >= local->scan_req->n_channels) {
|
||||
ieee80211_scan_completed(&local->hw, false);
|
||||
return;
|
||||
}
|
||||
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)
|
||||
/*
|
||||
* as long as no delay is required advance immediately
|
||||
* without scheduling a new work
|
||||
*/
|
||||
do {
|
||||
switch (local->next_scan_state) {
|
||||
case SCAN_DECISION:
|
||||
if (ieee80211_scan_state_decision(local, &next_delay))
|
||||
return;
|
||||
break;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
case SCAN_SET_CHANNEL:
|
||||
ieee80211_scan_state_set_channel(local, &next_delay);
|
||||
break;
|
||||
case SCAN_SEND_PROBE:
|
||||
ieee80211_scan_state_send_probe(local, &next_delay);
|
||||
break;
|
||||
case SCAN_LEAVE_OPER_CHANNEL:
|
||||
ieee80211_scan_state_leave_oper_channel(local, &next_delay);
|
||||
break;
|
||||
case SCAN_ENTER_OPER_CHANNEL:
|
||||
ieee80211_scan_state_enter_oper_channel(local, &next_delay);
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} while (next_delay == 0);
|
||||
|
||||
queue_delayed_work(local->hw.workqueue, &local->scan_work,
|
||||
next_delay);
|
||||
|
@ -625,7 +763,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
|
|||
* queued -- mostly at suspend under RTNL.
|
||||
*/
|
||||
mutex_lock(&local->scan_mtx);
|
||||
swscan = local->sw_scanning;
|
||||
swscan = test_bit(SCAN_SW_SCANNING, &local->scanning);
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
if (swscan)
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
* @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
|
||||
* @WLAN_STA_WME: Station is a QoS-STA.
|
||||
* @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
|
||||
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
|
||||
* frame to this station is transmitted.
|
||||
|
@ -47,7 +46,6 @@ enum ieee80211_sta_info_flags {
|
|||
WLAN_STA_ASSOC_AP = 1<<5,
|
||||
WLAN_STA_WME = 1<<6,
|
||||
WLAN_STA_WDS = 1<<7,
|
||||
WLAN_STA_PSPOLL = 1<<8,
|
||||
WLAN_STA_CLEAR_PS_FILT = 1<<9,
|
||||
WLAN_STA_MFP = 1<<10,
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 ret;
|
||||
|
|
|
@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
|||
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
|
||||
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_nullfunc(hdr->frame_control))
|
||||
/*
|
||||
|
@ -373,7 +373,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
staflags = get_sta_flags(sta);
|
||||
|
||||
if (unlikely((staflags & WLAN_STA_PS) &&
|
||||
!(staflags & WLAN_STA_PSPOLL))) {
|
||||
!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
|
||||
"before %d)\n",
|
||||
|
@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
sta_info_set_tim_bit(sta);
|
||||
|
||||
info->control.jiffies = jiffies;
|
||||
info->control.vif = &tx->sdata->vif;
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
|
||||
return TX_QUEUED;
|
||||
|
@ -411,24 +412,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
sta->sta.addr);
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* 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) &&
|
||||
!rate_usable_index_exists(sband, &tx->sta->sta),
|
||||
"%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
|
||||
* 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;
|
||||
|
||||
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) {
|
||||
/* in progress */
|
||||
queued = true;
|
||||
info->control.vif = &sdata->vif;
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
__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 ieee80211_tx_info *info;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
unsigned long flags;
|
||||
int ret, len;
|
||||
bool fragm = false;
|
||||
|
@ -1167,13 +1153,32 @@ static int __ieee80211_tx(struct ieee80211_local *local,
|
|||
|
||||
next = skb->next;
|
||||
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);
|
||||
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
|
||||
dev_kfree_skb(skb);
|
||||
ret = NETDEV_TX_OK;
|
||||
}
|
||||
if (ret != NETDEV_TX_OK)
|
||||
if (ret != NETDEV_TX_OK) {
|
||||
info->control.vif = &sdata->vif;
|
||||
return IEEE80211_TX_AGAIN;
|
||||
}
|
||||
|
||||
*skbp = skb = next;
|
||||
ieee80211_led_tx(local, 1);
|
||||
fragm = true;
|
||||
|
@ -1386,17 +1391,12 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_sub_if_data *tmp_sdata;
|
||||
int headroom;
|
||||
bool may_encrypt;
|
||||
enum {
|
||||
NOT_MONITOR,
|
||||
FOUND_SDATA,
|
||||
UNKNOWN_ADDRESS,
|
||||
} monitor_iface = NOT_MONITOR;
|
||||
|
||||
dev_hold(sdata->dev);
|
||||
|
||||
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
|
||||
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) {
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_PS);
|
||||
|
@ -1424,7 +1424,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
u16 len_rthdr;
|
||||
|
||||
info->flags |= IEEE80211_TX_CTL_INJECTED;
|
||||
monitor_iface = UNKNOWN_ADDRESS;
|
||||
|
||||
len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
||||
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_put(sdata->dev);
|
||||
sdata = tmp_sdata;
|
||||
monitor_iface = FOUND_SDATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1476,13 +1474,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
}
|
||||
|
||||
tmp_sdata = sdata;
|
||||
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;
|
||||
info->control.vif = &sdata->vif;
|
||||
|
||||
ieee80211_select_queue(local, skb);
|
||||
ieee80211_tx(sdata, skb, false);
|
||||
|
@ -1534,9 +1526,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
|||
if (unlikely(skb->len < len_rthdr))
|
||||
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
|
||||
* 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;
|
||||
h_pos += hdrlen;
|
||||
|
||||
skb->iif = dev->ifindex;
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
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 sta_info *sta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct net_device *dev;
|
||||
int ret;
|
||||
bool result = true;
|
||||
|
||||
/* does interface still exist? */
|
||||
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;
|
||||
}
|
||||
sdata = vif_to_sdata(info->control.vif);
|
||||
|
||||
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
|
||||
/* do not use sdata, it may have been changed above */
|
||||
ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
|
||||
ieee80211_tx(sdata, skb, true);
|
||||
} else {
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
|
@ -1891,9 +1859,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
|
|||
result = false;
|
||||
}
|
||||
|
||||
out:
|
||||
dev_put(dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1921,10 +1886,21 @@ void ieee80211_tx_pending(unsigned long data)
|
|||
|
||||
while (!skb_queue_empty(&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,
|
||||
flags);
|
||||
|
||||
txok = ieee80211_tx_pending_skb(local, skb);
|
||||
dev_put(sdata->dev);
|
||||
if (!txok)
|
||||
__skb_queue_head(&local->pending[i], skb);
|
||||
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_transport_header(skb, 0);
|
||||
|
||||
skb->iif = sdata->dev->ifindex;
|
||||
if (!encrypt)
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
|
||||
|
|
|
@ -336,6 +336,12 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
|
|||
struct ieee80211_hw *hw = &local->hw;
|
||||
unsigned long flags;
|
||||
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);
|
||||
__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);
|
||||
|
||||
while ((skb = skb_dequeue(skbs))) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (WARN_ON(!info->control.vif)) {
|
||||
kfree(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret++;
|
||||
queue = skb_get_queue_mapping(skb);
|
||||
__skb_queue_tail(&local->pending[queue], skb);
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -19,6 +19,7 @@
|
|||
#include "core.h"
|
||||
#include "sysfs.h"
|
||||
#include "debugfs.h"
|
||||
#include "wext-compat.h"
|
||||
|
||||
/* name for sysfs, %d is appended */
|
||||
#define PHY_NAME "phy"
|
||||
|
@ -106,7 +107,7 @@ __cfg80211_rdev_from_info(struct genl_info *info)
|
|||
|
||||
if (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->ieee80211_ptr)
|
||||
byifidx =
|
||||
|
@ -151,13 +152,13 @@ cfg80211_get_dev_from_info(struct genl_info *info)
|
|||
}
|
||||
|
||||
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 net_device *dev;
|
||||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
dev = dev_get_by_index(&init_net, ifindex);
|
||||
dev = dev_get_by_index(net, ifindex);
|
||||
if (!dev)
|
||||
goto out;
|
||||
if (dev->ieee80211_ptr) {
|
||||
|
@ -222,6 +223,42 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
|
|||
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)
|
||||
{
|
||||
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.platform_data = rdev;
|
||||
|
||||
wiphy_net_set(&rdev->wiphy, &init_net);
|
||||
|
||||
rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
|
||||
rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
|
||||
&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);
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
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,
|
||||
"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;
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
#ifdef CONFIG_WIRELESS_EXT
|
||||
if (!dev->wireless_handlers)
|
||||
dev->wireless_handlers = &cfg80211_wext_handler;
|
||||
wdev->wext.default_key = -1;
|
||||
wdev->wext.default_mgmt_key = -1;
|
||||
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,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
err = register_pernet_device(&cfg80211_pernet_ops);
|
||||
if (err)
|
||||
goto out_fail_pernet;
|
||||
|
||||
err = wiphy_sysfs_init();
|
||||
if (err)
|
||||
goto out_fail_sysfs;
|
||||
|
@ -736,9 +802,10 @@ out_fail_nl80211:
|
|||
out_fail_notifier:
|
||||
wiphy_sysfs_exit();
|
||||
out_fail_sysfs:
|
||||
unregister_pernet_device(&cfg80211_pernet_ops);
|
||||
out_fail_pernet:
|
||||
return err;
|
||||
}
|
||||
|
||||
subsys_initcall(cfg80211_init);
|
||||
|
||||
static void cfg80211_exit(void)
|
||||
|
@ -748,5 +815,6 @@ static void cfg80211_exit(void)
|
|||
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
|
||||
wiphy_sysfs_exit();
|
||||
regulatory_exit();
|
||||
unregister_pernet_device(&cfg80211_pernet_ops);
|
||||
}
|
||||
module_exit(cfg80211_exit);
|
||||
|
|
|
@ -66,6 +66,9 @@ struct cfg80211_registered_device {
|
|||
struct work_struct conn_work;
|
||||
struct work_struct event_work;
|
||||
|
||||
/* current channel */
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEBUGFS
|
||||
/* Debugfs entries */
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "wext-compat.h"
|
||||
#include "nl80211.h"
|
||||
|
||||
|
||||
|
@ -312,8 +313,6 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
|
|||
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -342,8 +341,6 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
|
|||
/* no channel if not joining */
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -384,8 +381,6 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
|
|||
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -413,8 +408,6 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
|
|||
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -469,8 +462,6 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
|
|||
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -496,6 +487,4 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
/* temporary symbol - mark GPL - in the future the handler won't be */
|
||||
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include "core.h"
|
||||
#include "nl80211.h"
|
||||
|
||||
|
@ -545,6 +547,12 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
|
|||
|
||||
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));
|
||||
req.reason_code = reason;
|
||||
req.ie = ie;
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/sock.h>
|
||||
#include "core.h"
|
||||
#include "nl80211.h"
|
||||
#include "reg.h"
|
||||
|
@ -27,24 +29,26 @@ static struct genl_family nl80211_fam = {
|
|||
.hdrsize = 0, /* no private header */
|
||||
.version = 1, /* no particular meaning now */
|
||||
.maxattr = NL80211_ATTR_MAX,
|
||||
.netnsok = true,
|
||||
};
|
||||
|
||||
/* 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 net_device **dev)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
int ifindex;
|
||||
|
||||
if (!attrs[NL80211_ATTR_IFINDEX])
|
||||
return -EINVAL;
|
||||
|
||||
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)
|
||||
return -ENODEV;
|
||||
|
||||
*rdev = cfg80211_get_dev_from_ifindex(ifindex);
|
||||
*rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex);
|
||||
if (IS_ERR(*rdev)) {
|
||||
dev_put(*dev);
|
||||
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_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_PID] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* 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(disassoc, DISASSOCIATE);
|
||||
CMD(join_ibss, JOIN_IBSS);
|
||||
if (dev->wiphy.netnsok) {
|
||||
i++;
|
||||
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
|
||||
}
|
||||
|
||||
#undef CMD
|
||||
|
||||
|
@ -562,6 +571,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
list_for_each_entry(dev, &cfg80211_rdev_list, list) {
|
||||
if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
|
||||
continue;
|
||||
if (++idx <= start)
|
||||
continue;
|
||||
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);
|
||||
if (result)
|
||||
goto bad_res;
|
||||
|
||||
rdev->channel = chan;
|
||||
}
|
||||
|
||||
changed = 0;
|
||||
|
@ -867,6 +880,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
|
|||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
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) {
|
||||
wp_idx++;
|
||||
continue;
|
||||
|
@ -907,7 +922,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
struct net_device *netdev;
|
||||
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)
|
||||
return err;
|
||||
|
||||
|
@ -975,7 +990,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
int ifindex, err;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
ifindex = dev->ifindex;
|
||||
dev_put(dev);
|
||||
|
||||
if (!rdev->ops->del_virtual_intf) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex);
|
||||
err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
|
||||
|
||||
out:
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
dev_put(dev);
|
||||
unlock_rtnl:
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
|
@ -1195,7 +1209,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -1274,7 +1288,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -1333,7 +1347,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -1380,7 +1394,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -1429,7 +1443,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -1516,7 +1530,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -1726,13 +1740,13 @@ static int nl80211_dump_station(struct sk_buff *skb,
|
|||
|
||||
rtnl_lock();
|
||||
|
||||
netdev = __dev_get_by_index(&init_net, ifidx);
|
||||
netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!netdev) {
|
||||
err = -ENODEV;
|
||||
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)) {
|
||||
err = PTR_ERR(dev);
|
||||
goto out_rtnl;
|
||||
|
@ -1791,7 +1805,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
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.
|
||||
*/
|
||||
static int get_vlan(struct nlattr *vlanattr,
|
||||
static int get_vlan(struct genl_info *info,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device **vlan)
|
||||
{
|
||||
struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
|
||||
*vlan = NULL;
|
||||
|
||||
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)
|
||||
return -ENODEV;
|
||||
if (!(*vlan)->ieee80211_ptr)
|
||||
|
@ -1891,11 +1907,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan);
|
||||
err = get_vlan(info, rdev, ¶ms.vlan);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -2004,11 +2020,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan);
|
||||
err = get_vlan(info, rdev, ¶ms.vlan);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -2079,7 +2095,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2185,13 +2201,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
|
|||
|
||||
rtnl_lock();
|
||||
|
||||
netdev = __dev_get_by_index(&init_net, ifidx);
|
||||
netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!netdev) {
|
||||
err = -ENODEV;
|
||||
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)) {
|
||||
err = PTR_ERR(dev);
|
||||
goto out_rtnl;
|
||||
|
@ -2255,7 +2271,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2314,7 +2330,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2362,7 +2378,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2404,7 +2420,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2455,7 +2471,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2574,7 +2590,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
|
|||
rtnl_lock();
|
||||
|
||||
/* 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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2691,7 +2707,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -2947,7 +2963,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto out_rtnl;
|
||||
|
||||
|
@ -3069,14 +3085,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
|||
request->ie_len);
|
||||
}
|
||||
|
||||
request->ifidx = dev->ifindex;
|
||||
request->dev = dev;
|
||||
request->wiphy = &rdev->wiphy;
|
||||
|
||||
rdev->scan_req = request;
|
||||
err = rdev->ops->scan(&rdev->wiphy, dev, request);
|
||||
|
||||
if (!err)
|
||||
if (!err) {
|
||||
nl80211_send_scan_start(rdev, dev);
|
||||
dev_hold(dev);
|
||||
}
|
||||
|
||||
out_free:
|
||||
if (err) {
|
||||
|
@ -3198,11 +3216,11 @@ static int nl80211_dump_scan(struct sk_buff *skb,
|
|||
cb->args[0] = ifidx;
|
||||
}
|
||||
|
||||
dev = dev_get_by_index(&init_net, ifidx);
|
||||
dev = dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
rdev = cfg80211_get_dev_from_ifindex(ifidx);
|
||||
rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
|
||||
if (IS_ERR(rdev)) {
|
||||
err = PTR_ERR(rdev);
|
||||
goto out_put_netdev;
|
||||
|
@ -3312,7 +3330,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -3369,6 +3387,8 @@ static int nl80211_crypto_settings(struct genl_info *info,
|
|||
struct cfg80211_crypto_settings *settings,
|
||||
int cipher_limit)
|
||||
{
|
||||
memset(settings, 0, sizeof(*settings));
|
||||
|
||||
settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
|
||||
|
||||
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();
|
||||
|
||||
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
|
||||
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
|
||||
if (err)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -3531,7 +3551,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -3593,7 +3613,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -3666,7 +3686,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -3739,7 +3759,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -3924,7 +3944,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
|||
return err;
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -4000,7 +4020,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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)
|
||||
goto unlock_rtnl;
|
||||
|
||||
|
@ -4024,6 +4044,47 @@ unlock_rtnl:
|
|||
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[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
|
@ -4257,6 +4318,12 @@ static struct genl_ops nl80211_ops[] = {
|
|||
.policy = nl80211_policy,
|
||||
.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 = {
|
||||
.name = "mlme",
|
||||
|
@ -4288,7 +4355,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
|
|||
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,
|
||||
|
@ -4365,7 +4433,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
|
|||
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,
|
||||
|
@ -4383,7 +4452,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
|
|||
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,
|
||||
|
@ -4401,7 +4471,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -4486,7 +4560,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4553,7 +4628,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4611,7 +4687,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4651,7 +4728,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4691,7 +4769,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4726,7 +4805,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4766,7 +4846,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
|
|||
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;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -4819,7 +4900,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
|
|||
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;
|
||||
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
#include <net/iw_handler.h>
|
||||
#include "core.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)
|
||||
{
|
||||
|
@ -32,9 +33,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
|
|||
mutex_lock(&rdev->mtx);
|
||||
request = rdev->scan_req;
|
||||
|
||||
dev = dev_get_by_index(&init_net, request->ifidx);
|
||||
if (!dev)
|
||||
goto out;
|
||||
dev = request->dev;
|
||||
|
||||
/*
|
||||
* This must be before sending the other events!
|
||||
|
@ -58,7 +57,6 @@ void __cfg80211_scan_done(struct work_struct *wk)
|
|||
|
||||
dev_put(dev);
|
||||
|
||||
out:
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
wiphy_to_dev(request->wiphy)->scan_req = NULL;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
request->aborted = aborted;
|
||||
schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
|
||||
dev_put(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_scan_done);
|
||||
|
||||
|
@ -592,7 +583,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|||
if (!netif_running(dev))
|
||||
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))
|
||||
return PTR_ERR(rdev);
|
||||
|
@ -617,7 +608,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|||
}
|
||||
|
||||
creq->wiphy = wiphy;
|
||||
creq->ifidx = dev->ifindex;
|
||||
creq->dev = dev;
|
||||
creq->ssids = (void *)(creq + 1);
|
||||
creq->channels = (void *)(creq->ssids + 1);
|
||||
creq->n_channels = n_channels;
|
||||
|
@ -654,8 +645,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|||
if (err) {
|
||||
rdev->scan_req = NULL;
|
||||
kfree(creq);
|
||||
} else
|
||||
} else {
|
||||
nl80211_send_scan_start(rdev, dev);
|
||||
dev_hold(dev);
|
||||
}
|
||||
out:
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
return err;
|
||||
|
@ -948,7 +941,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
|
|||
if (!netif_running(dev))
|
||||
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))
|
||||
return PTR_ERR(rdev);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include "nl80211.h"
|
||||
|
@ -86,7 +88,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
|||
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;
|
||||
|
||||
rdev->scan_req = request;
|
||||
|
@ -95,6 +97,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
|||
if (!err) {
|
||||
wdev->conn->state = CFG80211_CONN_SCANNING;
|
||||
nl80211_send_scan_start(rdev, wdev->netdev);
|
||||
dev_hold(wdev->netdev);
|
||||
} else {
|
||||
rdev->scan_req = NULL;
|
||||
kfree(request);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "wext-compat.h"
|
||||
#include "core.h"
|
||||
|
||||
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 chan;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
|
||||
|
||||
int cfg80211_wext_siwrts(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
|
@ -759,6 +759,58 @@ int cfg80211_wext_giwencode(struct net_device *dev,
|
|||
}
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *data, char *extra)
|
||||
|
@ -1097,9 +1149,9 @@ int cfg80211_wext_giwpower(struct net_device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
|
||||
|
||||
int cfg80211_wds_wext_siwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *addr, char *extra)
|
||||
static int cfg80211_wds_wext_siwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *addr, char *extra)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap);
|
||||
|
||||
int cfg80211_wds_wext_giwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *addr, char *extra)
|
||||
static int cfg80211_wds_wext_giwap(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct sockaddr *addr, char *extra)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
|
||||
|
@ -1141,7 +1192,6 @@ int cfg80211_wds_wext_giwap(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);
|
||||
|
||||
int cfg80211_wext_siwrate(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
|
@ -1275,3 +1325,115 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
|
|||
return &wstats;
|
||||
}
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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 */
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "wext-compat.h"
|
||||
#include "nl80211.h"
|
||||
|
||||
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);
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -138,8 +137,6 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
|
|||
/* no channel if not joining */
|
||||
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,
|
||||
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));
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -221,8 +216,6 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
|
|||
|
||||
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,
|
||||
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));
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
@ -302,8 +293,6 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev,
|
|||
|
||||
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,
|
||||
struct iw_request_info *info,
|
||||
|
|
Loading…
Reference in New Issue