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

This commit is contained in:
David S. Miller 2009-12-04 13:25:15 -08:00
commit 8f56874bd7
88 changed files with 3161 additions and 2262 deletions

View file

@ -2816,6 +2816,15 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git
S: Supported
F: drivers/net/wireless/iwlwifi/
INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi)
M: Samuel Ortiz <samuel.ortiz@intel.com>
M: Zhu Yi <yi.zhu@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
S: Supported
W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi
F: drivers/net/wireless/iwmc3200wifi/
IOC3 ETHERNET DRIVER
M: Ralf Baechle <ralf@linux-mips.org>
L: linux-mips@linux-mips.org

View file

@ -4806,7 +4806,7 @@ static int airo_config_commit(struct net_device *dev,
static inline int sniffing_mode(struct airo_info *ai)
{
return le16_to_cpu(ai->config.rmode & RXMODE_MASK) >=
return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >=
le16_to_cpu(RXMODE_RFMON);
}

View file

@ -23,17 +23,12 @@ config ATH9K
If you choose to build a module, it'll be called ath9k.
if ATH_DEBUG
config ATH9K_DEBUG
config ATH9K_DEBUGFS
bool "Atheros ath9k debugging"
depends on ATH9K
---help---
Say Y, if you need ath9k to display debug messages.
Pass the debug mask as a module parameter:
Say Y, if you need access to ath9k's statistics for
interrupts, rate control, etc.
modprobe ath9k debug=0x00000200
Also required for changing debug message flags at run time.
Look in ath9k/debug.h for possible debug masks
endif # ATH_DEBUG

View file

@ -7,7 +7,7 @@ ath9k-y += beacon.o \
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o

View file

@ -21,7 +21,6 @@
#include <linux/device.h>
#include <linux/leds.h>
#include "rc.h"
#include "debug.h"
#include "common.h"
@ -330,6 +329,7 @@ void ath_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
int ath_beaconq_config(struct ath_softc *sc);
/*******/
/* ANI */
@ -421,8 +421,11 @@ struct ath_led {
#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
#define SC_OP_NULLFUNC_COMPLETED BIT(22)
#define SC_OP_PS_ENABLED BIT(23)
struct ath_wiphy;
struct ath_rate_table;
struct ath_softc {
struct ieee80211_hw *hw;
@ -467,9 +470,8 @@ struct ath_softc {
struct ath_rx rx;
struct ath_tx tx;
struct ath_beacon beacon;
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
const struct ath_rate_table *cur_rate_table;
enum wireless_mode cur_rate_mode;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ath_led radio_led;
@ -484,7 +486,7 @@ struct ath_softc {
int beacon_interval;
#ifdef CONFIG_ATH9K_DEBUG
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath9k_debug debug;
#endif
struct ath_beacon_config cur_beacon_conf;

View file

@ -23,11 +23,12 @@
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
* settings and channel width min/max
*/
static int ath_beaconq_config(struct ath_softc *sc)
int ath_beaconq_config(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
struct ath9k_tx_queue_info qi, qi_be;
int qnum;
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
@ -37,9 +38,12 @@ static int ath_beaconq_config(struct ath_softc *sc)
qi.tqi_cwmax = 0;
} else {
/* Adhoc mode; important thing is to use 2x cwmin. */
qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs;
qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin;
qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax;
qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA,
ATH9K_WME_AC_BE);
ath9k_hw_get_txq_props(ah, qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
}
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
@ -65,9 +69,9 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct ath_common *common = ath9k_hw_common(ah);
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
const struct ath_rate_table *rt;
int flags, antenna, ctsrate = 0, ctsduration = 0;
u8 rate;
struct ieee80211_supported_band *sband;
u8 rate = 0;
ds = bf->bf_desc;
flags = ATH9K_TXDESC_NOACK;
@ -91,10 +95,10 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
ds->ds_data = bf->bf_buf_addr;
rt = sc->cur_rate_table;
rate = rt->info[0].ratecode;
sband = &sc->sbands[common->hw->conf.channel->band];
rate = sband->bitrates[0].hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
rate |= rt->info[0].short_preamble;
rate |= sband->bitrates[0].hw_value_short;
ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
ATH9K_PKT_TYPE_BEACON,

View file

@ -181,8 +181,6 @@ static void ath9k_process_rssi(struct ath_common *common,
ATH_RSSI_EP_MULTIPLIER);
if (rx_stats->rs_rssi < 0)
rx_stats->rs_rssi = 0;
else if (rx_stats->rs_rssi > 127)
rx_stats->rs_rssi = 127;
/* Update Beacon RSSI, this is used by ANI. */
if (ieee80211_is_beacon(fc))
@ -238,16 +236,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
padpos = 24;
fc = hdr->frame_control;
if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
padpos += 6; /* ETH_ALEN */
}
if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
padpos += 2;
}
padpos = ath9k_cmn_padpos(hdr->frame_control);
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
@ -282,6 +272,20 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
}
EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
int ath9k_cmn_padpos(__le16 frame_control)
{
int padpos = 24;
if (ieee80211_has_a4(frame_control)) {
padpos += ETH_ALEN;
}
if (ieee80211_is_data_qos(frame_control)) {
padpos += IEEE80211_QOS_CTL_LEN;
}
return padpos;
}
EXPORT_SYMBOL(ath9k_cmn_padpos);
static int __init ath9k_cmn_init(void)
{
return 0;

View file

@ -78,6 +78,7 @@ struct ath_buf {
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
bool bf_stale;
bool bf_isnullfunc;
u16 bf_flags;
struct ath_buf_state bf_state;
dma_addr_t bf_dmacontext;
@ -122,3 +123,5 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
bool decrypt_error);
int ath9k_cmn_padpos(__le16 frame_control);

View file

@ -31,6 +31,8 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file)
return 0;
}
#ifdef CONFIG_ATH_DEBUG
static ssize_t read_file_debug(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -71,6 +73,8 @@ static const struct file_operations fops_debug = {
.owner = THIS_MODULE
};
#endif
static ssize_t read_file_dma(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -255,21 +259,11 @@ static const struct file_operations fops_interrupt = {
.owner = THIS_MODULE
};
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
void ath_debug_stat_rc(struct ath_softc *sc, int final_rate)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->status.rates;
int final_ts_idx = 0, idx, i;
struct ath_rc_stats *stats;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
if (!rates[i].count)
break;
final_ts_idx = i;
}
idx = rates[final_ts_idx].idx;
stats = &sc->debug.stats.rcstats[idx];
stats = &sc->debug.stats.rcstats[final_rate];
stats->success++;
}
@ -573,10 +567,12 @@ int ath9k_init_debug(struct ath_hw *ah)
if (!sc->debug.debugfs_phy)
goto err;
#ifdef CONFIG_ATH_DEBUG
sc->debug.debugfs_debug = debugfs_create_file("debug",
S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
if (!sc->debug.debugfs_debug)
goto err;
#endif
sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dma);

View file

@ -18,17 +18,18 @@
#define DEBUG_H
#include "hw.h"
#include "rc.h"
struct ath_txq;
struct ath_buf;
#ifdef CONFIG_ATH9K_DEBUG
#ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
#else
#define TX_STAT_INC(q, c) do { } while (0)
#endif
#ifdef CONFIG_ATH9K_DEBUG
#ifdef CONFIG_ATH9K_DEBUGFS
/**
* struct ath_interrupt_stats - Contains statistics about interrupts
@ -138,7 +139,7 @@ void ath9k_exit_debug(struct ath_hw *ah);
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_rc(struct ath_softc *sc, int final_rate);
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,
@ -170,7 +171,7 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
}
static inline void ath_debug_stat_rc(struct ath_softc *sc,
struct sk_buff *skb)
int final_rate)
{
}
@ -185,6 +186,6 @@ static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
{
}
#endif /* CONFIG_ATH9K_DEBUG */
#endif /* CONFIG_ATH9K_DEBUGFS */
#endif /* DEBUG_H */

View file

@ -148,22 +148,19 @@ bool ath9k_get_channel_edges(struct ath_hw *ah,
}
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
const struct ath_rate_table *rates,
u8 phy, int kbps,
u32 frameLen, u16 rateix,
bool shortPreamble)
{
u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
u32 kbps;
kbps = rates->info[rateix].ratekbps;
if (kbps == 0)
return 0;
switch (rates->info[rateix].phy) {
switch (phy) {
case WLAN_RC_PHY_CCK:
phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
if (shortPreamble && rates->info[rateix].short_preamble)
if (shortPreamble)
phyTime >>= 1;
numBits = frameLen << 3;
txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
@ -194,8 +191,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
break;
default:
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
"Unknown phy %u (rate ix %u)\n",
rates->info[rateix].phy, rateix);
"Unknown phy %u (rate ix %u)\n", phy, rateix);
txTime = 0;
break;
}
@ -922,6 +918,11 @@ int ath9k_hw_init(struct ath_hw *ah)
ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
ah->config.serialize_regmode);
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
else
ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
ath_print(common, ATH_DBG_FATAL,
"Mac Chip Rev 0x%02x.%x is not supported by "
@ -975,7 +976,10 @@ int ath9k_hw_init(struct ath_hw *ah)
return r;
ath9k_hw_init_mode_gain_regs(ah);
ath9k_hw_fill_cap_info(ah);
r = ath9k_hw_fill_cap_info(ah);
if (r)
return r;
ath9k_hw_init_11a_eeprom_fix(ah);
r = ath9k_hw_init_macaddr(ah);
@ -3111,7 +3115,7 @@ EXPORT_SYMBOL(ath9k_hw_set_sta_beacon_timers);
/* HW Capabilities */
/*******************/
void ath9k_hw_fill_cap_info(struct ath_hw *ah)
int ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
@ -3142,6 +3146,12 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
ath_print(common, ATH_DBG_FATAL,
"no band has been marked as supported in EEPROM.\n");
return -EINVAL;
}
bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
if (eeval & AR5416_OPFLAGS_11A) {
@ -3228,7 +3238,11 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->keycache_size = AR_KEYTABLE_SIZE;
pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
else
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
if (AR_SREV_9285_10_OR_LATER(ah))
pCap->num_gpio_pins = AR9285_NUM_GPIO;
@ -3301,6 +3315,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
} else {
btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
}
return 0;
}
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,

View file

@ -60,7 +60,7 @@
#define ATH_DEFAULT_NOISE_FLOOR -95
#define ATH9K_RSSI_BAD 0x80
#define ATH9K_RSSI_BAD -128
/* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) \
@ -226,6 +226,7 @@ struct ath9k_ops_config {
#define AR_SPUR_FEEQ_BOUND_HT20 10
int spurmode;
u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
u8 max_txtrig_level;
};
enum ath9k_int {
@ -619,7 +620,7 @@ void ath9k_hw_detach(struct ath_hw *ah);
int ath9k_hw_init(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange);
void ath9k_hw_fill_cap_info(struct ath_hw *ah);
int ath9k_hw_fill_cap_info(struct ath_hw *ah);
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
u32 capability, u32 *result);
bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
@ -647,7 +648,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
u32 ath9k_hw_reverse_bits(u32 val, u32 n);
bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
const struct ath_rate_table *rates,
u8 phy, int kbps,
u32 frameLen, u16 rateix, bool shortPreamble);
void ath9k_hw_get_channel_centers(struct ath_hw *ah,
struct ath9k_channel *chan,

View file

@ -70,12 +70,37 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
}
EXPORT_SYMBOL(ath9k_hw_numtxpending);
/**
* ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
*
* @ah: atheros hardware struct
* @bIncTrigLevel: whether or not the frame trigger level should be updated
*
* The frame trigger level specifies the minimum number of bytes,
* in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
* before the PCU will initiate sending the frame on the air. This can
* mean we initiate transmit before a full frame is on the PCU TX FIFO.
* Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
* first)
*
* Caution must be taken to ensure to set the frame trigger level based
* on the DMA request size. For example if the DMA request size is set to
* 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
* there need to be enough space in the tx FIFO for the requested transfer
* size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
* the threshold to a value beyond 6, then the transmit will hang.
*
* Current dual stream devices have a PCU TX FIFO size of 8 KB.
* Current single stream devices have a PCU TX FIFO size of 4 KB, however,
* there is a hardware issue which forces us to use 2 KB instead so the
* frame trigger level must not exceed 2 KB for these chipsets.
*/
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
{
u32 txcfg, curLevel, newLevel;
enum ath9k_int omask;
if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD)
if (ah->tx_trig_level >= ah->config.max_txtrig_level)
return false;
omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
@ -84,7 +109,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
curLevel = MS(txcfg, AR_FTRIG);
newLevel = curLevel;
if (bIncTrigLevel) {
if (curLevel < MAX_TX_FIFO_THRESHOLD)
if (curLevel < ah->config.max_txtrig_level)
newLevel++;
} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
newLevel--;
@ -231,6 +256,8 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
ds->ds_txstat.ts_status = 0;
ds->ds_txstat.ts_flags = 0;
if (ads->ds_txstatus1 & AR_FrmXmitOK)
ds->ds_txstat.ts_status |= ATH9K_TX_ACKED;
if (ads->ds_txstatus1 & AR_ExcessiveRetries)
ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
if (ads->ds_txstatus1 & AR_Filtered)
@ -926,6 +953,13 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
}
EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
/*
* This can stop or re-enables RX.
*
* If bool is set this will kill any frame which is currently being
* transferred between the MAC and baseband and also prevent any new
* frames from getting started.
*/
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
{
u32 reg;

View file

@ -76,6 +76,7 @@
#define ATH9K_TXERR_FIFO 0x04
#define ATH9K_TXERR_XTXOP 0x08
#define ATH9K_TXERR_TIMER_EXPIRED 0x10
#define ATH9K_TX_ACKED 0x20
#define ATH9K_TX_BA 0x01
#define ATH9K_TX_PWRMGMT 0x02
@ -85,9 +86,15 @@
#define ATH9K_TX_SW_ABORTED 0x40
#define ATH9K_TX_SW_FILTERED 0x80
/* 64 bytes */
#define MIN_TX_FIFO_THRESHOLD 0x1
/*
* Single stream device AR9285 and AR9271 require 2 KB
* to work around a hardware issue, all other devices
* have can use the max 4 KB limit.
*/
#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1)
#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD
struct ath_tx_status {
u32 ts_tstamp;
@ -380,6 +387,11 @@ struct ar5416_desc {
#define AR_TxBaStatus 0x40000000
#define AR_TxStatusRsvd01 0x80000000
/*
* AR_FrmXmitOK - Frame transmission success flag. If set, the frame was
* transmitted successfully. If clear, no ACK or BA was received to indicate
* successful transmission when we were expecting an ACK or BA.
*/
#define AR_FrmXmitOK 0x00000001
#define AR_ExcessiveRetries 0x00000002
#define AR_FIFOUnderrun 0x00000004
@ -616,7 +628,6 @@ enum ath9k_cipher {
struct ath_hw;
struct ath9k_channel;
struct ath_rate_table;
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);

View file

@ -104,37 +104,55 @@ static struct ieee80211_channel ath9k_5ghz_chantable[] = {
CHAN5G(5825, 37), /* Channel 165 */
};
/* Atheros hardware rate code addition for short premble */
#define SHPCHECK(__hw_rate, __flags) \
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
#define RATE(_bitrate, _hw_rate, _flags) { \
.bitrate = (_bitrate), \
.flags = (_flags), \
.hw_value = (_hw_rate), \
.hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
}
static struct ieee80211_rate ath9k_legacy_rates[] = {
RATE(10, 0x1b, 0),
RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
RATE(60, 0x0b, 0),
RATE(90, 0x0f, 0),
RATE(120, 0x0a, 0),
RATE(180, 0x0e, 0),
RATE(240, 0x09, 0),
RATE(360, 0x0d, 0),
RATE(480, 0x08, 0),
RATE(540, 0x0c, 0),
};
static void ath_cache_conf_rate(struct ath_softc *sc,
struct ieee80211_conf *conf)
{
switch (conf->channel->band) {
case IEEE80211_BAND_2GHZ:
if (conf_is_ht20(conf))
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
sc->cur_rate_mode = ATH9K_MODE_11NG_HT20;
else if (conf_is_ht40_minus(conf))
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS];
sc->cur_rate_mode = ATH9K_MODE_11NG_HT40MINUS;
else if (conf_is_ht40_plus(conf))
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS];
sc->cur_rate_mode = ATH9K_MODE_11NG_HT40PLUS;
else
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11G];
sc->cur_rate_mode = ATH9K_MODE_11G;
break;
case IEEE80211_BAND_5GHZ:
if (conf_is_ht20(conf))
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
sc->cur_rate_mode = ATH9K_MODE_11NA_HT20;
else if (conf_is_ht40_minus(conf))
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS];
sc->cur_rate_mode = ATH9K_MODE_11NA_HT40MINUS;
else if (conf_is_ht40_plus(conf))
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS];
sc->cur_rate_mode = ATH9K_MODE_11NA_HT40PLUS;
else
sc->cur_rate_table =
sc->hw_rate_table[ATH9K_MODE_11A];
sc->cur_rate_mode = ATH9K_MODE_11A;
break;
default:
BUG_ON(1);
@ -190,51 +208,6 @@ static u8 parse_mpdudensity(u8 mpdudensity)
}
}
static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
{
const struct ath_rate_table *rate_table = NULL;
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate;
int i, maxrates;
switch (band) {
case IEEE80211_BAND_2GHZ:
rate_table = sc->hw_rate_table[ATH9K_MODE_11G];
break;
case IEEE80211_BAND_5GHZ:
rate_table = sc->hw_rate_table[ATH9K_MODE_11A];
break;
default:
break;
}
if (rate_table == NULL)
return;
sband = &sc->sbands[band];
rate = sc->rates[band];
if (rate_table->rate_cnt > ATH_RATE_MAX)
maxrates = ATH_RATE_MAX;
else
maxrates = rate_table->rate_cnt;
for (i = 0; i < maxrates; i++) {
rate[i].bitrate = rate_table->info[i].ratekbps / 100;
rate[i].hw_value = rate_table->info[i].ratecode;
if (rate_table->info[i].short_preamble) {
rate[i].hw_value_short = rate_table->info[i].ratecode |
rate_table->info[i].short_preamble;
rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE;
}
sband->n_bitrates++;
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
"Rate: %2dMbps, ratecode: %2d\n",
rate[i].bitrate / 10, rate[i].hw_value);
}
}
static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
struct ieee80211_hw *hw)
{
@ -1701,12 +1674,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
/* default to MONITOR mode */
sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
/* Setup rate tables */
ath_rate_attach(sc);
ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
/*
* Allocate hardware transmit queues: one queue for
* beacon frames and one data queue for each QoS
@ -1826,20 +1793,25 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
/* setup channels and rates */
sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
sc->rates[IEEE80211_BAND_2GHZ];
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
ARRAY_SIZE(ath9k_2ghz_chantable);
if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
ARRAY_SIZE(ath9k_2ghz_chantable);
sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
ARRAY_SIZE(ath9k_legacy_rates);
}
if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
sc->rates[IEEE80211_BAND_5GHZ];
sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
ARRAY_SIZE(ath9k_5ghz_chantable);
sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
ath9k_legacy_rates + 4;
sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
ARRAY_SIZE(ath9k_legacy_rates) - 4;
}
switch (ah->btcoex_hw.scheme) {
@ -1906,8 +1878,9 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->rate_control_algorithm = "ath9k_rate_control";
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&sc->sbands[IEEE80211_BAND_2GHZ];
if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&sc->sbands[IEEE80211_BAND_2GHZ];
if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ];
@ -1946,9 +1919,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
reg = &common->regulatory;
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes))
setup_ht_cap(sc,
&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes))
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
setup_ht_cap(sc,
&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
/* initialize tx/rx engine */
@ -2394,7 +2370,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl;
int hdrlen, padsize;
int padpos, padsize;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
ath_print(common, ATH_DBG_XMIT,
@ -2404,7 +2381,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
}
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
* need to update that based on the current PS mode.
@ -2424,7 +2400,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
* power save mode. Need to wake up hardware for the TX to be
* completed and if needed, also for RX of buffered frames.
*/
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
ath9k_ps_wakeup(sc);
ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
@ -2452,7 +2427,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
* BSSes.
*/
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
@ -2460,13 +2434,13 @@ static int ath9k_tx(struct ieee80211_hw *hw,
}
/* Add the padding after the header if this is not already done */
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
if (hdrlen & 3) {
padsize = hdrlen % 4;
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len>padpos) {
if (skb_headroom(skb) < padsize)
return -1;
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, hdrlen);
memmove(skb->data, skb->data + padsize, padpos);
}
/* Check if a tx queue is available */
@ -2731,8 +2705,15 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
}
/*
* We just prepare to enable PS. We have to wait until our AP has
* ACK'd our null data frame to disable RX otherwise we'll ignore
* those ACKs and end up retransmitting the same null data frames.
* IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
*/
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
sc->sc_flags |= SC_OP_PS_ENABLED;
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
@ -2740,11 +2721,20 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
ath9k_hw_set_interrupts(sc->sc_ah,
sc->imask);
}
ath9k_hw_setrxabort(sc->sc_ah, 1);
}
sc->ps_enabled = true;
/*
* At this point we know hardware has received an ACK
* of a previously sent null data frame.
*/
if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) {
sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
sc->ps_enabled = true;
ath9k_hw_setrxabort(sc->sc_ah, 1);
}
} else {
sc->ps_enabled = false;
sc->sc_flags &= ~(SC_OP_PS_ENABLED |
SC_OP_NULLFUNC_COMPLETED);
ath9k_setpower(sc, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
@ -2898,6 +2888,10 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
if (ret)
ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
if ((qnum == sc->tx.hwq_map[ATH9K_WME_AC_BE]) && !ret)
ath_beaconq_config(sc);
mutex_unlock(&sc->mutex);
return ret;

View file

@ -19,133 +19,92 @@
static const struct ath_rate_table ar5416_11na_ratetable = {
42,
8, /* MCS start */
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
0, 0, 0, 0, 0, 0 },
5400, 0, 12, 0, 0, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
0, 1, 1, 1, 1, 0 },
7800, 1, 18, 0, 1, 1, 1, 1 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
2, 2, 2, 2, 2, 0 },
10000, 2, 24, 2, 2, 2, 2, 2 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
2, 3, 3, 3, 3, 0 },
13900, 3, 36, 2, 3, 3, 3, 3 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
4, 4, 4, 4, 4, 0 },
17300, 4, 48, 4, 4, 4, 4, 4 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
4, 5, 5, 5, 5, 0 },
23000, 5, 72, 4, 5, 5, 5, 5 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
4, 6, 6, 6, 6, 0 },
27400, 6, 96, 4, 6, 6, 6, 6 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 7, 7, 7, 7, 0 },
29300, 7, 108, 4, 7, 7, 7, 7 },
{ VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
0, 8, 24, 8, 24, 3216 },
6400, 0, 0, 0, 8, 24, 8, 24 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
2, 9, 25, 9, 25, 6434 },
12700, 1, 1, 2, 9, 25, 9, 25 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
2, 10, 26, 10, 26, 9650 },
18800, 2, 2, 2, 10, 26, 10, 26 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
4, 11, 27, 11, 27, 12868 },
25000, 3, 3, 4, 11, 27, 11, 27 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
4, 12, 28, 12, 28, 19304 },
36700, 4, 4, 4, 12, 28, 12, 28 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
4, 13, 29, 13, 29, 25740 },
48100, 5, 5, 4, 13, 29, 13, 29 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
4, 14, 30, 14, 30, 28956 },
53500, 6, 6, 4, 14, 30, 14, 30 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
4, 15, 31, 15, 32, 32180 },
59000, 7, 7, 4, 15, 31, 15, 32 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
8, 3, 16, 33, 16, 33, 6430 },
12700, 8, 8, 3, 16, 33, 16, 33 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
2, 17, 34, 17, 34, 12860 },
24800, 9, 9, 2, 17, 34, 17, 34 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
2, 18, 35, 18, 35, 19300 },
36600, 10, 10, 2, 18, 35, 18, 35 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
4, 19, 36, 19, 36, 25736 },
48100, 11, 11, 4, 19, 36, 19, 36 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
4, 20, 37, 20, 37, 38600 },
69500, 12, 12, 4, 20, 37, 20, 37 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
4, 21, 38, 21, 38, 51472 },
89500, 13, 13, 4, 21, 38, 21, 38 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
4, 22, 39, 22, 39, 57890 },
98900, 14, 14, 4, 22, 39, 22, 39 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
4, 23, 40, 23, 41, 64320 },
108300, 15, 15, 4, 23, 40, 23, 41 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
0, 8, 24, 24, 24, 6684 },
13200, 0, 0, 0, 8, 24, 24, 24 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
2, 9, 25, 25, 25, 13368 },
25900, 1, 1, 2, 9, 25, 25, 25 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
2, 10, 26, 26, 26, 20052 },
38600, 2, 2, 2, 10, 26, 26, 26 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
4, 11, 27, 27, 27, 26738 },
49800, 3, 3, 4, 11, 27, 27, 27 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
4, 12, 28, 28, 28, 40104 },
72200, 4, 4, 4, 12, 28, 28, 28 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
4, 13, 29, 29, 29, 53476 },
92900, 5, 5, 4, 13, 29, 29, 29 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
4, 14, 30, 30, 30, 60156 },
102700, 6, 6, 4, 14, 30, 30, 30 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
4, 15, 31, 32, 32, 66840 },
112000, 7, 7, 4, 15, 31, 32, 32 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
4, 15, 31, 32, 32, 74200 },
122000, 7, 7, 4, 15, 31, 32, 32 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
0, 16, 33, 33, 33, 13360 },
25800, 8, 8, 0, 16, 33, 33, 33 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
2, 17, 34, 34, 34, 26720 },
49800, 9, 9, 2, 17, 34, 34, 34 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
2, 18, 35, 35, 35, 40080 },
71900, 10, 10, 2, 18, 35, 35, 35 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
4, 19, 36, 36, 36, 53440 },
92500, 11, 11, 4, 19, 36, 36, 36 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
4, 20, 37, 37, 37, 80160 },
130300, 12, 12, 4, 20, 37, 37, 37 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
4, 21, 38, 38, 38, 106880 },
162800, 13, 13, 4, 21, 38, 38, 38 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
4, 22, 39, 39, 39, 120240 },
178200, 14, 14, 4, 22, 39, 39, 39 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
4, 23, 40, 41, 41, 133600 },
192100, 15, 15, 4, 23, 40, 41, 41 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
4, 23, 40, 41, 41, 148400 },
207000, 15, 15, 4, 23, 40, 41, 41 },
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
@ -156,177 +115,125 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
static const struct ath_rate_table ar5416_11ng_ratetable = {
46,
12, /* MCS start */
{
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
0, 0, 0, 0, 0, 0 },
900, 0, 2, 0, 0, 0, 0, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
1, 1, 1, 1, 1, 0 },
1900, 1, 4, 1, 1, 1, 1, 1 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
2, 2, 2, 2, 2, 0 },
4900, 2, 11, 2, 2, 2, 2, 2 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
3, 3, 3, 3, 3, 0 },
8100, 3, 22, 3, 3, 3, 3, 3 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
4, 4, 4, 4, 4, 0 },
5400, 4, 12, 4, 4, 4, 4, 4 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
4, 5, 5, 5, 5, 0 },
7800, 5, 18, 4, 5, 5, 5, 5 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
6, 6, 6, 6, 6, 0 },
10100, 6, 24, 6, 6, 6, 6, 6 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
6, 7, 7, 7, 7, 0 },
14100, 7, 36, 6, 7, 7, 7, 7 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
8, 8, 8, 8, 8, 0 },
17700, 8, 48, 8, 8, 8, 8, 8 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
8, 9, 9, 9, 9, 0 },
23700, 9, 72, 8, 9, 9, 9, 9 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
8, 10, 10, 10, 10, 0 },
27400, 10, 96, 8, 10, 10, 10, 10 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
8, 11, 11, 11, 11, 0 },
30900, 11, 108, 8, 11, 11, 11, 11 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
4, 12, 28, 12, 28, 3216 },
6400, 0, 0, 4, 12, 28, 12, 28 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
6, 13, 29, 13, 29, 6434 },
12700, 1, 1, 6, 13, 29, 13, 29 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
6, 14, 30, 14, 30, 9650 },
18800, 2, 2, 6, 14, 30, 14, 30 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
8, 15, 31, 15, 31, 12868 },
25000, 3, 3, 8, 15, 31, 15, 31 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
8, 16, 32, 16, 32, 19304 },
36700, 4, 4, 8, 16, 32, 16, 32 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
8, 17, 33, 17, 33, 25740 },
48100, 5, 5, 8, 17, 33, 17, 33 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
8, 18, 34, 18, 34, 28956 },
53500, 6, 6, 8, 18, 34, 18, 34 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
8, 19, 35, 19, 36, 32180 },
59000, 7, 7, 8, 19, 35, 19, 36 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
4, 20, 37, 20, 37, 6430 },
12700, 8, 8, 4, 20, 37, 20, 37 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
6, 21, 38, 21, 38, 12860 },
24800, 9, 9, 6, 21, 38, 21, 38 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
6, 22, 39, 22, 39, 19300 },
36600, 10, 10, 6, 22, 39, 22, 39 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
8, 23, 40, 23, 40, 25736 },
48100, 11, 11, 8, 23, 40, 23, 40 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
8, 24, 41, 24, 41, 38600 },
69500, 12, 12, 8, 24, 41, 24, 41 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
8, 25, 42, 25, 42, 51472 },
89500, 13, 13, 8, 25, 42, 25, 42 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
8, 26, 43, 26, 44, 57890 },
98900, 14, 14, 8, 26, 43, 26, 44 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
8, 27, 44, 27, 45, 64320 },
108300, 15, 15, 8, 27, 44, 27, 45 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
8, 12, 28, 28, 28, 6684 },
13200, 0, 0, 8, 12, 28, 28, 28 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
8, 13, 29, 29, 29, 13368 },
25900, 1, 1, 8, 13, 29, 29, 29 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
8, 14, 30, 30, 30, 20052 },
38600, 2, 2, 8, 14, 30, 30, 30 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
8, 15, 31, 31, 31, 26738 },
49800, 3, 3, 8, 15, 31, 31, 31 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
8, 16, 32, 32, 32, 40104 },
72200, 4, 4, 8, 16, 32, 32, 32 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
8, 17, 33, 33, 33, 53476 },
92900, 5, 5, 8, 17, 33, 33, 33 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
8, 18, 34, 34, 34, 60156 },
102700, 6, 6, 8, 18, 34, 34, 34 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
8, 19, 35, 36, 36, 66840 },
112000, 7, 7, 8, 19, 35, 36, 36 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
8, 19, 35, 36, 36, 74200 },
122000, 7, 7, 8, 19, 35, 36, 36 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
8, 20, 37, 37, 37, 13360 },
25800, 8, 8, 8, 20, 37, 37, 37 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
8, 21, 38, 38, 38, 26720 },
49800, 9, 9, 8, 21, 38, 38, 38 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
8, 22, 39, 39, 39, 40080 },
71900, 10, 10, 8, 22, 39, 39, 39 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
8, 23, 40, 40, 40, 53440 },
92500, 11, 11, 8, 23, 40, 40, 40 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
8, 24, 41, 41, 41, 80160 },
130300, 12, 12, 8, 24, 41, 41, 41 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
8, 25, 42, 42, 42, 106880 },
162800, 13, 13, 8, 25, 42, 42, 42 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
8, 26, 43, 43, 43, 120240 },
178200, 14, 14, 8, 26, 43, 43, 43 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
8, 27, 44, 45, 45, 133600 },
192100, 15, 15, 8, 27, 44, 45, 45 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
8, 27, 44, 45, 45, 148400 },
},
207000, 15, 15, 8, 27, 44, 45, 45 },
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
static const struct ath_rate_table ar5416_11a_ratetable = {
8,
0,
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
0, 0, 0 },
5400, 0, 12, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
0, 1, 0 },
7800, 1, 18, 0, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
2, 2, 0 },
10000, 2, 24, 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
2, 3, 0 },
13900, 3, 36, 2, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
4, 4, 0 },
17300, 4, 48, 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
4, 5, 0 },
23000, 5, 72, 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
4, 6, 0 },
27400, 6, 96, 4, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 7, 0 },
29300, 7, 108, 4, 7, 0 },
},
50, /* probe interval */
0, /* Phy rates allowed initially */
@ -334,48 +241,51 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
static const struct ath_rate_table ar5416_11g_ratetable = {
12,
0,
{
{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
0, 0, 0 },
900, 0, 2, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
1, 1, 0 },
1900, 1, 4, 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
2, 2, 0 },
4900, 2, 11, 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
3, 3, 0 },
8100, 3, 22, 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
4, 4, 0 },
5400, 4, 12, 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
4, 5, 0 },
7800, 5, 18, 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
6, 6, 0 },
10000, 6, 24, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
6, 7, 0 },
13900, 7, 36, 6, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
8, 8, 0 },
17300, 8, 48, 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
8, 9, 0 },
23000, 9, 72, 8, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
8, 10, 0 },
27400, 10, 96, 8, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
8, 11, 0 },
29300, 11, 108, 8, 11, 0 },
},
50, /* probe interval */
0, /* Phy rates allowed initially */
};
static const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX] = {
[ATH9K_MODE_11A] = &ar5416_11a_ratetable,
[ATH9K_MODE_11G] = &ar5416_11g_ratetable,
[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable,
[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable,
[ATH9K_MODE_11NA_HT40PLUS] = &ar5416_11na_ratetable,
[ATH9K_MODE_11NA_HT40MINUS] = &ar5416_11na_ratetable,
[ATH9K_MODE_11NG_HT40PLUS] = &ar5416_11ng_ratetable,
[ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable,
};
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
struct ieee80211_tx_rate *rate);
static inline int8_t median(int8_t a, int8_t b, int8_t c)
{
if (a >= b) {
@ -534,7 +444,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
* capflag matches one of the validity
* (VALID/VALID_20/VALID_40) flags */
if (((rate & 0x7F) == (dot11rate & 0x7F)) &&
if ((rate == dot11rate) &&
((valid & WLAN_RC_CAP_MODE(capflag)) ==
WLAN_RC_CAP_MODE(capflag)) &&
!WLAN_RC_PHY_HT(phy)) {
@ -576,8 +486,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
u8 rate = rateset->rs_rates[i];
u8 dot11rate = rate_table->info[j].dot11rate;
if (((rate & 0x7F) != (dot11rate & 0x7F)) ||
!WLAN_RC_PHY_HT(phy) ||
if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) ||
!WLAN_RC_PHY_HT_VALID(valid, capflag))
continue;
@ -696,18 +605,20 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table,
u8 tries, u8 rix, int rtsctsenable)
{
rate->count = tries;
rate->idx = rix;
rate->idx = rate_table->info[rix].ratecode;
if (txrc->short_preamble)
rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
if (txrc->rts || rtsctsenable)
rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
if (WLAN_RC_PHY_HT(rate_table->info[rix].phy))
if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) {
rate->flags |= IEEE80211_TX_RC_MCS;
if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
}
}
static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
@ -720,7 +631,7 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
/* get the cix for the lowest valid rix */
for (i = 3; i >= 0; i--) {
if (rates[i].count && (rates[i].idx >= 0)) {
rix = rates[i].idx;
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
break;
}
}
@ -1080,15 +991,19 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
{
int rix;
if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx;
rix = rate->idx + rate_table->mcs_start;
if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
(rate->flags & IEEE80211_TX_RC_SHORT_GI))
rix = rate_table->info[rate->idx].ht_index;
rix = rate_table->info[rix].ht_index;
else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rix = rate_table->info[rate->idx].sgi_index;
rix = rate_table->info[rix].sgi_index;
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
rix = rate_table->info[rate->idx].cw40index;
rix = rate_table->info[rix].cw40index;
else
rix = rate_table->info[rate->idx].base_index;
rix = rate_table->info[rix].base_index;
return rix;
}
@ -1183,7 +1098,9 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
ath_print(common, ATH_DBG_CONFIG,
"Choosing rate table for mode: %d\n", mode);
return sc->hw_rate_table[mode];
sc->cur_rate_mode = mode;
return hw_rate_table[mode];
}
static void ath_rc_init(struct ath_softc *sc,
@ -1197,12 +1114,6 @@ static void ath_rc_init(struct ath_softc *sc,
u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
u8 i, j, k, hi = 0, hthi = 0;
if (!rate_table) {
ath_print(common, ATH_DBG_FATAL,
"Rate table not initialized\n");
return;
}
/* Initial rate table size. Will change depending
* on the working rate set */
ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
@ -1324,10 +1235,14 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
return;
/*
* If underrun error is seen assume it as an excessive retry only
* if prefetch trigger level have reached the max (0x3f for 5416)
* Adjust the long retry as if the frame was tried hw->max_rate_tries
* times. This affects how ratectrl updates PER for the failed rate.
* If an underrun error is seen assume it as an excessive retry only
* if max frame trigger level has been reached (2 KB for singel stream,
* and 4 KB for dual stream). Adjust the long retry as if the frame was
* tried hw->max_rate_tries times to affect how ratectrl updates PER for
* the failed rate. In case of congestion on the bus penalizing these
* type of underruns should help hardware actually transmit new frames
* successfully by eventually preferring slower rates. This itself
* should also alleviate congestion on the bus.
*/
if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
(sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
@ -1357,7 +1272,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
}
}
ath_debug_stat_rc(sc, skb);
ath_debug_stat_rc(sc, ath_rc_get_rateindex(sc->cur_rate_table,
&tx_info->status.rates[final_ts_idx]));
}
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
@ -1365,7 +1281,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
{
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table = NULL;
const struct ath_rate_table *rate_table;
bool is_cw40, is_sgi40;
int i, j = 0;
@ -1397,11 +1313,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
(sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
rate_table = ath_choose_rate_table(sc, sband->band,
sta->ht_cap.ht_supported,
is_cw40);
} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
/* cur_rate_table would be set on init through config() */
rate_table = sc->cur_rate_table;
sta->ht_cap.ht_supported, is_cw40);
} else {
rate_table = hw_rate_table[sc->cur_rate_mode];
}
ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40);
@ -1445,6 +1359,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
"Operating HT Bandwidth changed to: %d\n",
sc->hw->conf.channel_type);
sc->cur_rate_table = hw_rate_table[sc->cur_rate_mode];
}
}
}
@ -1497,26 +1412,6 @@ static struct rate_control_ops ath_rate_ops = {
.free_sta = ath_rate_free_sta,
};
void ath_rate_attach(struct ath_softc *sc)
{
sc->hw_rate_table[ATH9K_MODE_11A] =
&ar5416_11a_ratetable;
sc->hw_rate_table[ATH9K_MODE_11G] =
&ar5416_11g_ratetable;
sc->hw_rate_table[ATH9K_MODE_11NA_HT20] =
&ar5416_11na_ratetable;
sc->hw_rate_table[ATH9K_MODE_11NG_HT20] =
&ar5416_11ng_ratetable;
sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
&ar5416_11na_ratetable;
sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
&ar5416_11na_ratetable;
sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
&ar5416_11ng_ratetable;
sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
&ar5416_11ng_ratetable;
}
int ath_rate_control_register(void)
{
return ieee80211_rate_control_register(&ath_rate_ops);

View file

@ -104,6 +104,7 @@ enum {
*/
struct ath_rate_table {
int rate_cnt;
int mcs_start;
struct {
int valid;
int valid_single_stream;
@ -111,14 +112,12 @@ struct ath_rate_table {
u32 ratekbps;
u32 user_ratekbps;
u8 ratecode;
u8 short_preamble;
u8 dot11rate;
u8 ctrl_rate;
u8 base_index;
u8 cw40index;
u8 sgi_index;
u8 ht_index;
u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
u8 initial_ratemax;
@ -179,8 +178,6 @@ enum ath9k_internal_frame_type {
ATH9K_INT_UNPAUSE
};
void ath_rate_attach(struct ath_softc *sc);
u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);

View file

@ -1332,13 +1332,22 @@ enum {
#define AR_MCAST_FIL0 0x8040
#define AR_MCAST_FIL1 0x8044
/*
* AR_DIAG_SW - Register which can be used for diagnostics and testing purposes.
*
* The force RX abort (AR_DIAG_RX_ABORT, bit 25) can be used in conjunction with
* RX block (AR_DIAG_RX_DIS, bit 5) to help fast channel change to shut down
* receive. The force RX abort bit will kill any frame which is currently being
* transferred between the MAC and baseband. The RX block bit (AR_DIAG_RX_DIS)
* will prevent any new frames from getting started.
*/
#define AR_DIAG_SW 0x8048
#define AR_DIAG_CACHE_ACK 0x00000001
#define AR_DIAG_ACK_DIS 0x00000002
#define AR_DIAG_CTS_DIS 0x00000004
#define AR_DIAG_ENCRYPT_DIS 0x00000008
#define AR_DIAG_DECRYPT_DIS 0x00000010
#define AR_DIAG_RX_DIS 0x00000020
#define AR_DIAG_RX_DIS 0x00000020 /* RX block */
#define AR_DIAG_LOOP_BACK 0x00000040
#define AR_DIAG_CORR_FCS 0x00000080
#define AR_DIAG_CHAN_INFO 0x00000100
@ -1347,12 +1356,12 @@ enum {
#define AR_DIAG_FRAME_NV0 0x00020000
#define AR_DIAG_OBS_PT_SEL1 0x000C0000
#define AR_DIAG_OBS_PT_SEL1_S 18
#define AR_DIAG_FORCE_RX_CLEAR 0x00100000
#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */
#define AR_DIAG_IGNORE_VIRT_CS 0x00200000
#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000
#define AR_DIAG_EIFS_CTRL_ENA 0x00800000
#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000
#define AR_DIAG_RX_ABORT 0x02000000
#define AR_DIAG_RX_ABORT 0x02000000 /* Force RX abort */
#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000
#define AR_DIAG_OBS_PT_SEL2 0x08000000
#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000

View file

@ -70,6 +70,29 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
int nbad, int txok, bool update_rc);
enum {
MCS_DEFAULT,
MCS_HT40,
MCS_HT40_SGI,
};
static int ath_max_4ms_framelen[3][16] = {
[MCS_DEFAULT] = {
3216, 6434, 9650, 12868, 19304, 25740, 28956, 32180,
6430, 12860, 19300, 25736, 38600, 51472, 57890, 64320,
},
[MCS_HT40] = {
6684, 13368, 20052, 26738, 40104, 53476, 60156, 66840,
13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600,
},
[MCS_HT40_SGI] = {
/* TODO: Only MCS 7 and 15 updated, recalculate the rest */
6684, 13368, 20052, 26738, 40104, 53476, 60156, 74200,
13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400,
}
};
/*********************/
/* Aggregation logic */
/*********************/
@ -459,7 +482,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ath_atx_tid *tid)
{
const struct ath_rate_table *rate_table = sc->cur_rate_table;
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
@ -480,12 +502,20 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
for (i = 0; i < 4; i++) {
if (rates[i].count) {
if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
int modeidx;
if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
legacy = 1;
break;
}
frmlen = rate_table->info[rates[i].idx].max_4ms_framelen;
if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
modeidx = MCS_HT40_SGI;
else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
modeidx = MCS_HT40;
else
modeidx = MCS_DEFAULT;
frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
max_4ms_framelen = min(max_4ms_framelen, frmlen);
}
}
@ -523,12 +553,11 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
struct ath_buf *bf, u16 frmlen)
{
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;
u16 minlen;
u8 rc, flags, rix;
u8 flags, rix;
int width, half_gi, ndelim, mindelim;
/* Select standard number of delimiters based on frame length alone */
@ -558,7 +587,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
rix = tx_info->control.rates[0].idx;
flags = tx_info->control.rates[0].flags;
rc = rt->info[rix].ratecode;
width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
@ -570,7 +598,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
if (nsymbols == 0)
nsymbols = 1;
nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
nsymbits = bits_per_symbol[rix][width];
minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
if (frmlen < minlen) {
@ -1425,22 +1453,14 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
int width, int half_gi, bool shortPreamble)
{
const struct ath_rate_table *rate_table = sc->cur_rate_table;
u32 nbits, nsymbits, duration, nsymbols;
u8 rc;
int streams, pktlen;
pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
rc = rate_table->info[rix].ratecode;
/* for legacy rates, use old function to compute packet duration */
if (!IS_HT_RATE(rc))
return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
rix, shortPreamble);
/* find number of symbols: PLCP + data */
nbits = (pktlen << 3) + OFDM_PLCP_BITS;
nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
nsymbits = bits_per_symbol[rix][width];
nsymbols = (nbits + nsymbits - 1) / nsymbits;
if (!half_gi)
@ -1449,7 +1469,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
duration = SYMBOL_TIME_HALFGI(nsymbols);
/* addup duration for legacy/ht training and signal fields */
streams = HT_RC_2_STREAMS(rc);
streams = HT_RC_2_STREAMS(rix);
duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
return duration;
@ -1458,11 +1478,11 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
const struct ath_rate_table *rt = sc->cur_rate_table;
struct ath9k_11n_rate_series series[4];
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
const struct ieee80211_rate *rate;
struct ieee80211_hdr *hdr;
int i, flags = 0;
u8 rix = 0, ctsrate = 0;
@ -1481,11 +1501,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* checking the BSS's global flag.
* But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
*/
rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
ctsrate = rate->hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode |
rt->info[tx_info->control.rts_cts_rate_idx].short_preamble;
else
ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode;
ctsrate |= rate->hw_value_short;
/*
* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
@ -1508,6 +1527,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
flags &= ~(ATH9K_TXDESC_RTSENA);
for (i = 0; i < 4; i++) {
bool is_40, is_sgi, is_sp;
int phy;
if (!rates[i].count || (rates[i].idx < 0))
continue;
@ -1515,12 +1537,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
series[i].Tries = rates[i].count;
series[i].ChSel = common->tx_chainmask;
if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
series[i].Rate = rt->info[rix].ratecode |
rt->info[rix].short_preamble;
else
series[i].Rate = rt->info[rix].ratecode;
if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
@ -1528,10 +1544,36 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
(rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE));
is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
if (rates[i].flags & IEEE80211_TX_RC_MCS) {
/* MCS rates */
series[i].Rate = rix | 0x80;
series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
is_40, is_sgi, is_sp);
continue;
}
/* legcay rates */
if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
!(rate->flags & IEEE80211_RATE_ERP_G))
phy = WLAN_RC_PHY_CCK;
else
phy = WLAN_RC_PHY_OFDM;
rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
series[i].Rate = rate->hw_value;
if (rate->hw_value_short) {
if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
series[i].Rate |= rate->hw_value_short;
} else {
is_sp = false;
}
series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
}
/* set dur_update_en for l-sig computation except for PS-Poll frames */
@ -1554,6 +1596,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
int hdrlen;
__le16 fc;
int padpos, padsize;
tx_info->pad[0] = 0;
switch (txctl->frame_type) {
@ -1572,7 +1615,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
ATH_TXBUF_RESET(bf);
bf->aphy = aphy;
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
bf->bf_frmlen = skb->len + FCS_LEN;
/* Remove the padding size from bf_frmlen, if any */
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len>padpos+padsize) {
bf->bf_frmlen -= padsize;
}
if (conf_is_ht(&hw->conf) && !is_pae(skb))
bf->bf_state.bf_type |= BUF_HT;
@ -1602,6 +1651,14 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
}
bf->bf_buf_addr = bf->bf_dmacontext;
/* tag if this is a nullfunc frame to enable PS when AP acks it */
if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
bf->bf_isnullfunc = true;
sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
} else
bf->bf_isnullfunc = false;
return 0;
}
@ -1920,8 +1977,10 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
}
}
for (i = tx_rateindex + 1; i < hw->max_rates; i++)
for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
tx_info->status.rates[i].count = 0;
tx_info->status.rates[i].idx = -1;
}
tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
}
@ -1994,6 +2053,19 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
break;
}
/*
* We now know the nullfunc frame has been ACKed so we
* can disable RX.
*/
if (bf->bf_isnullfunc &&
(ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
sc->ps_enabled = true;
ath9k_hw_setrxabort(sc->sc_ah, 1);
} else
sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
}
/*
* Remove ath_buf's of the same transmit unit from txq,
* however leave the last descriptor back as the holding

View file

@ -246,6 +246,7 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev,
*behaviour = B43_LED_OFF;
break;
default:
*behaviour = B43_LED_OFF;
B43_WARN_ON(1);
return;
}

View file

@ -33,8 +33,14 @@ bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
& B43_MMIO_RADIO_HWENABLED_HI_MASK))
return 1;
} else {
if (b43_status(dev) >= B43_STAT_STARTED &&
b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
/* To prevent CPU fault on PPC, do not read a register
* unless the interface is started; however, on resume
* for hibernation, this routine is entered early. When
* that happens, unconditionally return TRUE.
*/
if (b43_status(dev) < B43_STAT_STARTED)
return 1;
if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
& B43_MMIO_RADIO_HWENABLED_LO_MASK)
return 1;
}

View file

@ -34,6 +34,13 @@ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
& B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
return 1;
} else {
/* To prevent CPU fault on PPC, do not read a register
* unless the interface is started; however, on resume
* for hibernation, this routine is entered early. When
* that happens, unconditionally return TRUE.
*/
if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
return 1;
if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
& B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
return 1;

View file

@ -6573,6 +6573,16 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
}
#endif
static void ipw2100_shutdown(struct pci_dev *pci_dev)
{
struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
/* Take down the device; powers it off, etc. */
ipw2100_down(priv);
pci_disable_device(pci_dev);
}
#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
@ -6636,6 +6646,7 @@ static struct pci_driver ipw2100_pci_driver = {
.suspend = ipw2100_suspend,
.resume = ipw2100_resume,
#endif
.shutdown = ipw2100_shutdown,
};
/**

View file

@ -248,17 +248,22 @@ u32 libipw_debug_level = 0;
EXPORT_SYMBOL_GPL(libipw_debug_level);
static struct proc_dir_entry *libipw_proc = NULL;
static int show_debug_level(char *page, char **start, off_t offset,
int count, int *eof, void *data)
static int debug_level_proc_show(struct seq_file *m, void *v)
{
return snprintf(page, count, "0x%08X\n", libipw_debug_level);
seq_printf(m, "0x%08X\n", libipw_debug_level);
return 0;
}
static int store_debug_level(struct file *file, const char __user * buffer,
unsigned long count, void *data)
static int debug_level_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_level_proc_show, NULL);
}
static ssize_t debug_level_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *pos)
{
char buf[] = "0x00000000\n";
unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
size_t len = min(sizeof(buf) - 1, count);
unsigned long val;
if (copy_from_user(buf, buffer, len))
@ -272,6 +277,15 @@ static int store_debug_level(struct file *file, const char __user * buffer,
return strnlen(buf, len);
}
static const struct file_operations debug_level_proc_fops = {
.owner = THIS_MODULE,
.open = debug_level_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = debug_level_proc_write,
};
#endif /* CONFIG_LIBIPW_DEBUG */
static int __init libipw_init(void)
@ -286,16 +300,13 @@ static int __init libipw_init(void)
" proc directory\n");
return -EIO;
}
e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
libipw_proc);
e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
&debug_level_proc_fops);
if (!e) {
remove_proc_entry(DRV_NAME, init_net.proc_net);
libipw_proc = NULL;
return -EIO;
}
e->read_proc = show_debug_level;
e->write_proc = store_debug_level;
e->data = NULL;
#endif /* CONFIG_LIBIPW_DEBUG */
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");

View file

@ -1662,7 +1662,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
IWL_ERR(priv,
"Not valid error log pointer 0x%08X for %s uCode\n",
base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
return;
}
@ -1807,7 +1809,9 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
IWL_ERR(priv,
"Invalid event log pointer 0x%08X for %s uCode\n",
base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
return;
}

View file

@ -63,6 +63,8 @@
#ifndef __iwl_core_h__
#define __iwl_core_h__
#include <linux/utsrelease.h>
/************************
* forward declarations *
************************/
@ -70,7 +72,7 @@ struct iwl_host_cmd;
struct iwl_cmd;
#define IWLWIFI_VERSION "1.3.27k"
#define IWLWIFI_VERSION UTS_RELEASE "-k"
#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"

View file

@ -76,11 +76,9 @@
#define VS
#endif
#define IWL39_VERSION "1.2.26k" VD VS
#define DRV_VERSION IWLWIFI_VERSION VD VS
#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
#define DRV_VERSION IWL39_VERSION
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
@ -1701,15 +1699,6 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n",
size);
/* if uCode has wrapped back to top of log, start at the oldest entry,
* i.e the next one that uCode would fill. */
if (num_wraps)
iwl3945_print_event_log(priv, next_entry,
capacity - next_entry, mode);
/* (then/else) start at top of log */
iwl3945_print_event_log(priv, 0, next_entry, mode);
#ifdef CONFIG_IWLWIFI_DEBUG
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
/* if uCode has wrapped back to top of log,

View file

@ -678,6 +678,9 @@ static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
case TX_POWER_AUTOMATIC:
return 0;
case TX_POWER_FIXED:
if (!test_bit(IWM_STATUS_READY, &iwm->status))
return 0;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_TX_PWR_LIMIT_USR, dbm * 2);
if (ret < 0)
@ -685,6 +688,7 @@ static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
return iwm_tx_power_trigger(iwm);
default:
IWM_ERR(iwm, "Unsupported power type: %d\n", type);
return -EOPNOTSUPP;
}
@ -721,6 +725,33 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
CFG_POWER_INDEX, iwm->conf.power_index);
}
int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
}
int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
}
int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
struct cfg80211_pmksa pmksa;
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH);
}
static struct cfg80211_ops iwm_cfg80211_ops = {
.change_virtual_intf = iwm_cfg80211_change_iface,
.add_key = iwm_cfg80211_add_key,
@ -737,6 +768,9 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
.set_tx_power = iwm_cfg80211_set_txpower,
.get_tx_power = iwm_cfg80211_get_txpower,
.set_power_mgmt = iwm_cfg80211_set_power_mgmt,
.set_pmksa = iwm_cfg80211_set_pmksa,
.del_pmksa = iwm_cfg80211_del_pmksa,
.flush_pmksa = iwm_cfg80211_flush_pmksa,
};
static const u32 cipher_suites[] = {
@ -782,6 +816,7 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
set_wiphy_dev(wdev->wiphy, dev);
wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS;
wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;

View file

@ -99,6 +99,10 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
return ret;
}
static int modparam_wiwi = COEX_MODE_CM;
module_param_named(wiwi, modparam_wiwi, int, 0644);
MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)");
static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
{
{4, 3, 0, COEX_UNASSOC_IDLE_FLAGS},
@ -122,18 +126,18 @@ static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
{
{1, 1, 0, COEX_UNASSOC_IDLE_FLAGS},
{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
{4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
{5, 5, 0, COEX_CALIBRATION_FLAGS},
{6, 6, 0, COEX_CALIBRATION_FLAGS},
{3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
{6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS},
{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
{4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
{4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
{1, 1, 0, COEX_RF_ON_FLAGS},
{1, 1, 0, COEX_RF_OFF_FLAGS},
{6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
{7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
{5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
{1, 1, 0, COEX_RSRVD1_FLAGS},
{1, 1, 0, COEX_RSRVD2_FLAGS}
@ -148,7 +152,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK;
switch (iwm->conf.coexist_mode) {
switch (modparam_wiwi) {
case COEX_MODE_XOR:
case COEX_MODE_CM:
coex_enabled = 1;
@ -173,7 +177,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK |
COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK;
switch (iwm->conf.coexist_mode) {
switch (modparam_wiwi) {
case COEX_MODE_XOR:
memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl,
sizeof(iwm_sta_xor_prio_tbl));
@ -184,7 +188,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
break;
default:
IWM_ERR(iwm, "Invalid coex_mode 0x%x\n",
iwm->conf.coexist_mode);
modparam_wiwi);
break;
}
} else
@ -192,7 +196,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD,
&coex_table_cmd,
sizeof(struct iwm_coex_prio_table_cmd), 1);
sizeof(struct iwm_coex_prio_table_cmd), 0);
}
int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
@ -396,7 +400,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_COEX_MODE, iwm->conf.coexist_mode);
CFG_COEX_MODE, modparam_wiwi);
if (ret < 0)
return ret;
@ -929,3 +933,58 @@ int iwm_target_reset(struct iwm_priv *iwm)
return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
}
int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
struct iwm_umac_notif_stop_resume_tx *ntf)
{
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
struct iwm_umac_cmd umac_cmd;
struct iwm_umac_cmd_stop_resume_tx stp_res_cmd;
struct iwm_sta_info *sta_info;
u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id);
int i;
sta_info = &iwm->sta_table[sta_id];
if (!sta_info->valid) {
IWM_ERR(iwm, "Invalid STA: %d\n", sta_id);
return -EINVAL;
}
umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX;
umac_cmd.resp = 0;
stp_res_cmd.flags = ntf->flags;
stp_res_cmd.sta_id = ntf->sta_id;
stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk;
for (i = 0; i < IWM_UMAC_TID_NR; i++)
stp_res_cmd.last_seq_num[i] =
sta_info->tid_info[i].last_seq_num;
return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd,
sizeof(struct iwm_umac_cmd_stop_resume_tx));
}
int iwm_send_pmkid_update(struct iwm_priv *iwm,
struct cfg80211_pmksa *pmksa, u32 command)
{
struct iwm_umac_pmkid_update update;
int ret;
memset(&update, 0, sizeof(struct iwm_umac_pmkid_update));
update.command = cpu_to_le32(command);
if (pmksa->bssid)
memcpy(&update.bssid, pmksa->bssid, ETH_ALEN);
if (pmksa->pmkid)
memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
ret = iwm_send_wifi_if_cmd(iwm, &update,
sizeof(struct iwm_umac_pmkid_update), 0);
if (ret) {
IWM_ERR(iwm, "PMKID update command failed\n");
return ret;
}
return 0;
}

View file

@ -450,6 +450,25 @@ struct iwm_umac_cmd_stats_req {
__le32 flags;
} __attribute__ ((packed));
struct iwm_umac_cmd_stop_resume_tx {
u8 flags;
u8 sta_id;
__le16 stop_resume_tid_msk;
__le16 last_seq_num[IWM_UMAC_TID_NR];
u16 reserved;
} __attribute__ ((packed));
#define IWM_CMD_PMKID_ADD 1
#define IWM_CMD_PMKID_DEL 2
#define IWM_CMD_PMKID_FLUSH 3
struct iwm_umac_pmkid_update {
__le32 command;
u8 bssid[ETH_ALEN];
__le16 reserved;
u8 pmkid[WLAN_PMKID_LEN];
} __attribute__ ((packed));
/* LMAC commands */
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
int iwm_send_prio_table(struct iwm_priv *iwm);
@ -478,6 +497,10 @@ int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
int ssid_num);
int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
struct iwm_umac_notif_stop_resume_tx *ntf);
int iwm_send_pmkid_update(struct iwm_priv *iwm,
struct cfg80211_pmksa *pmksa, u32 command);
/* UDMA commands */
int iwm_target_reset(struct iwm_priv *iwm);

View file

@ -158,6 +158,29 @@ static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
}
spin_unlock_irqrestore(&txq->queue.lock, flags);
spin_lock_irqsave(&txq->stopped_queue.lock, flags);
len += snprintf(buf + len, buf_len - len,
"\tStopped Queue len: %d\n",
skb_queue_len(&txq->stopped_queue));
for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) {
struct iwm_tx_info *tx_info;
skb = skb->next;
tx_info = skb_to_tx_info(skb);
len += snprintf(buf + len, buf_len - len,
"\tSKB #%d\n", j);
len += snprintf(buf + len, buf_len - len,
"\t\tsta: %d\n", tx_info->sta);
len += snprintf(buf + len, buf_len - len,
"\t\tcolor: %d\n", tx_info->color);
len += snprintf(buf + len, buf_len - len,
"\t\ttid: %d\n", tx_info->tid);
}
spin_unlock_irqrestore(&txq->stopped_queue.lock, flags);
}
ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);

View file

@ -66,6 +66,10 @@ static struct iwm_eeprom_entry eeprom_map[] = {
[IWM_EEPROM_SKU_CAP] =
{"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN},
[IWM_EEPROM_FAT_CHANNELS_CAP] =
{"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF,
IWM_EEPROM_FAT_CHANNELS_CAP_LEN},
[IWM_EEPROM_CALIB_RXIQ_OFFSET] =
{"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN},
@ -146,6 +150,52 @@ u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id)
return iwm->eeprom + eeprom_map[eeprom_id].offset;
}
int iwm_eeprom_fat_channels(struct iwm_priv *iwm)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct ieee80211_supported_band *band;
u16 *channels, i;
channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP);
if (IS_ERR(channels))
return PTR_ERR(channels);
band = wiphy->bands[IEEE80211_BAND_2GHZ];
band->ht_cap.ht_supported = true;
for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++)
if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
band->ht_cap.ht_supported = false;
band = wiphy->bands[IEEE80211_BAND_5GHZ];
band->ht_cap.ht_supported = true;
for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++)
if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
band->ht_cap.ht_supported = false;
return 0;
}
u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm)
{
u16 sku_cap;
u32 wireless_mode = 0;
sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP));
if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ)
wireless_mode |= WIRELESS_MODE_11G;
if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ)
wireless_mode |= WIRELESS_MODE_11A;
if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE)
wireless_mode |= WIRELESS_MODE_11N;
return wireless_mode;
}
int iwm_eeprom_init(struct iwm_priv *iwm)
{
int i, ret = 0;

View file

@ -48,6 +48,7 @@ enum {
IWM_EEPROM_CARD_ID,
IWM_EEPROM_RADIO_CONF,
IWM_EEPROM_SKU_CAP,
IWM_EEPROM_FAT_CHANNELS_CAP,
IWM_EEPROM_INDIRECT_OFFSET,
IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET,
@ -58,14 +59,15 @@ enum {
IWM_EEPROM_LAST,
};
#define IWM_EEPROM_SIG_OFF 0x00
#define IWM_EEPROM_VERSION_OFF (0x54 << 1)
#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1)
#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1)
#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1)
#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1)
#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1)
#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1)
#define IWM_EEPROM_SIG_OFF 0x00
#define IWM_EEPROM_VERSION_OFF (0x54 << 1)
#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1)
#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1)
#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1)
#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1)
#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1)
#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1)
#define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1)
#define IWM_EEPROM_SIG_LEN 4
#define IWM_EEPROM_VERSION_LEN 2
@ -74,6 +76,7 @@ enum {
#define IWM_EEPROM_CARD_ID_LEN 2
#define IWM_EEPROM_RADIO_CONF_LEN 2
#define IWM_EEPROM_SKU_CAP_LEN 2
#define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40
#define IWM_EEPROM_INDIRECT_LEN 2
#define IWM_MAX_EEPROM_DATA_LEN 240
@ -87,6 +90,14 @@ enum {
#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5)
#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
#define IWM_EEPROM_FAT_CHANNELS 20
/* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */
#define IWM_EEPROM_FAT_CHANNELS_24 9
/* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */
#define IWM_EEPROM_FAT_CHANNELS_52 11
#define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0)
enum {
IWM_EEPROM_CALIB_CAL_HDR,
IWM_EEPROM_CALIB_TX_POWER,
@ -110,5 +121,7 @@ struct iwm_eeprom_entry {
int iwm_eeprom_init(struct iwm_priv *iwm);
void iwm_eeprom_exit(struct iwm_priv *iwm);
u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id);
int iwm_eeprom_fat_channels(struct iwm_priv *iwm);
u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm);
#endif

View file

@ -81,7 +81,6 @@ struct iwm_conf {
u32 assoc_timeout;
u32 roam_timeout;
u32 wireless_mode;
u32 coexist_mode;
u8 ibss_band;
u8 ibss_channel;
@ -131,11 +130,18 @@ struct iwm_notif {
unsigned long buf_size;
};
struct iwm_tid_info {
__le16 last_seq_num;
bool stopped;
struct mutex mutex;
};
struct iwm_sta_info {
u8 addr[ETH_ALEN];
bool valid;
bool qos;
u8 color;
struct iwm_tid_info tid_info[IWM_UMAC_TID_NR];
};
struct iwm_tx_info {
@ -185,6 +191,8 @@ struct iwm_key {
struct iwm_tx_queue {
int id;
struct sk_buff_head queue;
struct sk_buff_head stopped_queue;
spinlock_t lock;
struct workqueue_struct *wq;
struct work_struct worker;
u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
@ -341,6 +349,7 @@ int iwm_up(struct iwm_priv *iwm);
int iwm_down(struct iwm_priv *iwm);
/* TX API */
u16 iwm_tid_to_queue(u16 tid);
void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
void iwm_tx_worker(struct work_struct *work);
int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);

View file

@ -68,7 +68,6 @@ static struct iwm_conf def_iwm_conf = {
.ct_kill_exit = 110,
.reset_on_fatal_err = 1,
.auto_connect = 1,
.wimax_not_present = 0,
.enable_qos = 1,
.mode = UMAC_MODE_BSS,
@ -80,8 +79,8 @@ static struct iwm_conf def_iwm_conf = {
.assoc_timeout = 2,
.roam_timeout = 10,
.wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G,
.coexist_mode = COEX_MODE_CM,
.wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G |
WIRELESS_MODE_11N,
/* IBSS */
.ibss_band = UMAC_BAND_2GHZ,
@ -94,6 +93,10 @@ static int modparam_reset;
module_param_named(reset, modparam_reset, bool, 0644);
MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])");
static int modparam_wimax_enable = 1;
module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644);
MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])");
int iwm_mode_to_nl80211_iftype(int mode)
{
switch (mode) {
@ -247,7 +250,7 @@ static void iwm_watchdog(unsigned long data)
int iwm_priv_init(struct iwm_priv *iwm)
{
int i;
int i, j;
char name[32];
iwm->status = 0;
@ -291,6 +294,8 @@ int iwm_priv_init(struct iwm_priv *iwm)
return -EAGAIN;
skb_queue_head_init(&iwm->txq[i].queue);
skb_queue_head_init(&iwm->txq[i].stopped_queue);
spin_lock_init(&iwm->txq[i].lock);
}
for (i = 0; i < IWM_NUM_KEYS; i++)
@ -298,6 +303,12 @@ int iwm_priv_init(struct iwm_priv *iwm)
iwm->default_key = -1;
for (i = 0; i < IWM_STA_TABLE_NUM; i++)
for (j = 0; j < IWM_UMAC_TID_NR; j++) {
mutex_init(&iwm->sta_table[i].tid_info[j].mutex);
iwm->sta_table[i].tid_info[j].stopped = false;
}
init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog;
iwm->watchdog.data = (unsigned long)iwm;
@ -478,7 +489,7 @@ static int iwm_config_boot_params(struct iwm_priv *iwm)
int ret;
/* check Wimax is off and config debug monitor */
if (iwm->conf.wimax_not_present) {
if (!modparam_wimax_enable) {
u32 data1 = 0x1f;
u32 addr1 = 0x606BE258;
@ -571,6 +582,7 @@ void iwm_link_off(struct iwm_priv *iwm)
for (i = 0; i < IWM_TX_QUEUES; i++) {
skb_queue_purge(&iwm->txq[i].queue);
skb_queue_purge(&iwm->txq[i].stopped_queue);
iwm->txq[i].concat_count = 0;
iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
@ -630,6 +642,7 @@ static int __iwm_up(struct iwm_priv *iwm)
int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL;
struct wiphy *wiphy = iwm_to_wiphy(iwm);
u32 wireless_mode;
ret = iwm_bus_enable(iwm);
if (ret) {
@ -691,6 +704,27 @@ static int __iwm_up(struct iwm_priv *iwm)
goto err_disable;
}
ret = iwm_eeprom_fat_channels(iwm);
if (ret) {
IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n");
goto err_fw;
}
/*
* Read our SKU capabilities.
* If it's valid, we AND the configured wireless mode with the
* device EEPROM value as the current profile wireless mode.
*/
wireless_mode = iwm_eeprom_wireless_mode(iwm);
if (wireless_mode) {
iwm->conf.wireless_mode &= wireless_mode;
if (iwm->umac_profile)
iwm->umac_profile->wireless_mode =
iwm->conf.wireless_mode;
} else
IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n",
*((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)));
snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
iwm->lmac_version, iwm->umac_version);

View file

@ -76,6 +76,14 @@ static int iwm_stop(struct net_device *ndev)
*/
static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
u16 iwm_tid_to_queue(u16 tid)
{
if (tid > IWM_UMAC_TID_NR - 2)
return -EINVAL;
return iwm_1d_to_queue[tid];
}
static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
{
skb->priority = cfg80211_classify8021d(skb);

View file

@ -1087,6 +1087,71 @@ static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf,
return 0;
}
static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
struct iwm_umac_notif_stop_resume_tx *stp_res_tx =
(struct iwm_umac_notif_stop_resume_tx *)buf;
struct iwm_sta_info *sta_info;
struct iwm_tid_info *tid_info;
u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id);
u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk);
int bit, ret = 0;
bool stop = false;
IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n"
"\tflags: 0x%x\n"
"\tSTA id: %d\n"
"\tTID bitmask: 0x%x\n",
stp_res_tx->flags, stp_res_tx->sta_id,
stp_res_tx->stop_resume_tid_msk);
if (stp_res_tx->flags & UMAC_STOP_TX_FLAG)
stop = true;
sta_info = &iwm->sta_table[sta_id];
if (!sta_info->valid) {
IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n",
sta_id, stp_res_tx->sta_id);
return -EINVAL;
}
for_each_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) {
tid_info = &sta_info->tid_info[bit];
mutex_lock(&tid_info->mutex);
tid_info->stopped = stop;
mutex_unlock(&tid_info->mutex);
if (!stop) {
struct iwm_tx_queue *txq;
u16 queue = iwm_tid_to_queue(bit);
if (queue < 0)
continue;
txq = &iwm->txq[queue];
/*
* If we resume, we have to move our SKBs
* back to the tx queue and queue some work.
*/
spin_lock_bh(&txq->lock);
skb_queue_splice_init(&txq->queue, &txq->stopped_queue);
spin_unlock_bh(&txq->lock);
queue_work(txq->wq, &txq->worker);
}
}
/* We send an ACK only for the stop case */
if (stop)
ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx);
return ret;
}
static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
@ -1371,6 +1436,7 @@ static const iwm_handler iwm_umac_handlers[] =
[UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics,
[UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy,
[UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list,
[UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx,
[REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet,
[UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper,
};

View file

@ -329,7 +329,7 @@ static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
memcpy(buf + sizeof(*hdr), skb->data, skb->len);
return 0;
return umac_cmd.seq_num;
}
static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
@ -354,16 +354,15 @@ static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
return ret;
}
#define CONFIG_IWM_TX_CONCATENATED 1
void iwm_tx_worker(struct work_struct *work)
{
struct iwm_priv *iwm;
struct iwm_tx_info *tx_info = NULL;
struct sk_buff *skb;
int cmdlen, ret;
struct iwm_tx_queue *txq;
int pool_id;
struct iwm_sta_info *sta_info;
struct iwm_tid_info *tid_info;
int cmdlen, ret, pool_id;
txq = container_of(work, struct iwm_tx_queue, worker);
iwm = container_of(txq, struct iwm_priv, txq[txq->id]);
@ -373,19 +372,46 @@ void iwm_tx_worker(struct work_struct *work)
while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
!skb_queue_empty(&txq->queue)) {
spin_lock_bh(&txq->lock);
skb = skb_dequeue(&txq->queue);
spin_unlock_bh(&txq->lock);
tx_info = skb_to_tx_info(skb);
sta_info = &iwm->sta_table[tx_info->sta];
if (!sta_info->valid) {
IWM_ERR(iwm, "Trying to send a frame to unknown STA\n");
kfree_skb(skb);
continue;
}
tid_info = &sta_info->tid_info[tx_info->tid];
mutex_lock(&tid_info->mutex);
/*
* If the RAxTID is stopped, we queue the skb to the stopped
* queue.
* Whenever we'll get a UMAC notification to resume the tx flow
* for this RAxTID, we'll merge back the stopped queue into the
* regular queue. See iwm_ntf_stop_resume_tx() from rx.c.
*/
if (tid_info->stopped) {
IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n",
tx_info->sta, tx_info->tid);
spin_lock_bh(&txq->lock);
skb_queue_tail(&txq->stopped_queue, skb);
spin_unlock_bh(&txq->lock);
mutex_unlock(&tid_info->mutex);
continue;
}
cmdlen = IWM_UDMA_HDR_LEN + skb->len;
IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: "
"%d, color: %d\n", txq->id, skb, tx_info->sta,
tx_info->color);
#if !CONFIG_IWM_TX_CONCATENATED
/* temporarily keep this to comparing the performance */
ret = iwm_send_packet(iwm, skb, pool_id);
#else
if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE)
iwm_tx_send_concat_packets(iwm, txq);
@ -393,14 +419,21 @@ void iwm_tx_worker(struct work_struct *work)
if (ret) {
IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue "
"%d, Tx worker stopped\n", txq->id);
spin_lock_bh(&txq->lock);
skb_queue_head(&txq->queue, skb);
spin_unlock_bh(&txq->lock);
mutex_unlock(&tid_info->mutex);
break;
}
txq->concat_ptr = txq->concat_buf + txq->concat_count;
iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
tid_info->last_seq_num =
iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
txq->concat_count += ALIGN(cmdlen, 16);
#endif
mutex_unlock(&tid_info->mutex);
kfree_skb(skb);
}
@ -419,14 +452,14 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct iwm_priv *iwm = ndev_to_iwm(netdev);
struct net_device *ndev = iwm_to_ndev(iwm);
struct wireless_dev *wdev = iwm_to_wdev(iwm);
u8 *dst_addr;
struct iwm_tx_info *tx_info;
struct iwm_tx_queue *txq;
struct iwm_sta_info *sta_info;
u8 sta_id;
u8 *dst_addr, sta_id;
u16 queue;
int ret;
if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
"not associated\n");
@ -440,7 +473,8 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
txq = &iwm->txq[queue];
/* No free space for Tx, tx_worker is too slow */
if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) {
if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) ||
(skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) {
IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
netif_stop_subqueue(netdev, queue);
return NETDEV_TX_BUSY;
@ -477,7 +511,9 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
else
tx_info->tid = IWM_UMAC_MGMT_TID;
spin_lock_bh(&iwm->txq[queue].lock);
skb_queue_tail(&iwm->txq[queue].queue, skb);
spin_unlock_bh(&iwm->txq[queue].lock);
queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);

View file

@ -83,6 +83,20 @@ struct iwm_udma_out_wifi_hdr {
((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
(UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
/* STA ID and color */
#define STA_ID_SEED (0x0f)
#define STA_ID_POS (0)
#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS)
#define STA_COLOR_SEED (0x7)
#define STA_COLOR_POS (4)
#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS)
#define STA_ID_N_COLOR_COLOR(id_n_color) \
(((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS)
#define STA_ID_N_COLOR_ID(id_n_color) \
(((id_n_color) & STA_ID_MSK) >> STA_ID_POS)
/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */
#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0
#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF
@ -260,6 +274,9 @@ struct iwm_udma_out_wifi_hdr {
#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16
#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17
#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18
#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19
#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A
#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA
#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB
#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC
@ -281,6 +298,7 @@ struct iwm_udma_out_wifi_hdr {
#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B
#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C
#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E
#define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F
#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20
/* UMAC WiFi interface ports */
@ -691,13 +709,13 @@ struct iwm_umac_notif_rx_ticket {
#define UMAC_PHY_NUM_CHAINS 3
#define IWM_UMAC_MGMT_TID 8
#define IWM_UMAC_TID_NR 8
#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */
struct iwm_umac_notif_stats {
struct iwm_umac_wifi_in_hdr hdr;
__le32 flags;
__le32 timestamp;
__le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */
__le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */
__le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
__le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
__le32 chain_energy[UMAC_PHY_NUM_CHAINS];
@ -742,6 +760,20 @@ struct iwm_umac_notif_stats {
__le32 roam_ap_loadblance;
} __attribute__ ((packed));
#define UMAC_STOP_TX_FLAG 0x1
#define UMAC_RESUME_TX_FLAG 0x2
#define LAST_SEQ_NUM_INVALID 0xFFFF
struct iwm_umac_notif_stop_resume_tx {
struct iwm_umac_wifi_in_hdr hdr;
u8 flags; /* UMAC_*_TX_FLAG_* */
u8 sta_id;
__le16 stop_resume_tid_msk; /* tid bitmask */
} __attribute__ ((packed));
#define UMAC_MAX_NUM_PMKIDS 4
/* WiFi interface wrapper header */
struct iwm_umac_wifi_if {
u8 oid;

View file

@ -5,7 +5,7 @@ libertas-y += cmdresp.o
libertas-y += debugfs.o
libertas-y += ethtool.o
libertas-y += main.o
libertas-y += persistcfg.o
libertas-y += mesh.o
libertas-y += rx.o
libertas-y += scan.o
libertas-y += tx.o

View file

@ -3,7 +3,6 @@
* It prepares command and sends it to firmware when it is ready.
*/
#include <net/lib80211.h>
#include <linux/kfifo.h>
#include <linux/sched.h>
@ -697,173 +696,6 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
return 0;
}
static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_BT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
sizeof(struct cmd_header));
cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action);
switch (cmd_action) {
case CMD_ACT_BT_ACCESS_ADD:
memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
break;
case CMD_ACT_BT_ACCESS_DEL:
memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
break;
case CMD_ACT_BT_ACCESS_LIST:
bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
break;
case CMD_ACT_BT_ACCESS_RESET:
break;
case CMD_ACT_BT_ACCESS_SET_INVERT:
bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
break;
case CMD_ACT_BT_ACCESS_GET_INVERT:
break;
default:
break;
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
sizeof(struct cmd_header));
cmd->result = 0;
if (pdata_buf)
memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
else
memset(fwt_access, 0, sizeof(*fwt_access));
fwt_access->action = cpu_to_le16(cmd_action);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd)
{
int ret;
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
cmd->hdr.result = 0;
cmd->action = cpu_to_le16(cmd_action);
ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
static int __lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type)
{
int ret;
u16 command = CMD_MESH_CONFIG_OLD;
lbs_deb_enter(LBS_DEB_CMD);
/*
* Command id is 0xac for v10 FW along with mesh interface
* id in bits 14-13-12.
*/
if (priv->mesh_fw_ver == MESH_FW_NEW)
command = CMD_MESH_CONFIG |
(MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
cmd->hdr.command = cpu_to_le16(command);
cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
cmd->hdr.result = 0;
cmd->type = cpu_to_le16(type);
cmd->action = cpu_to_le16(action);
ret = lbs_cmd_with_response(priv, command, cmd);
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
int lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type)
{
int ret;
if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
return -EOPNOTSUPP;
ret = __lbs_mesh_config_send(priv, cmd, action, type);
return ret;
}
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
* START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
* are all handled by preparing a struct cmd_ds_mesh_config and passing it to
* lbs_mesh_config_send.
*/
int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_meshie *ie;
DECLARE_SSID_BUF(ssid);
memset(&cmd, 0, sizeof(cmd));
cmd.channel = cpu_to_le16(chan);
ie = (struct mrvl_meshie *)cmd.data;
switch (action) {
case CMD_ACT_MESH_CONFIG_START:
ie->id = WLAN_EID_GENERIC;
ie->val.oui[0] = 0x00;
ie->val.oui[1] = 0x50;
ie->val.oui[2] = 0x43;
ie->val.type = MARVELL_MESH_IE_TYPE;
ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
ie->val.version = MARVELL_MESH_IE_VERSION;
ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
ie->len = sizeof(struct mrvl_meshie_val) -
IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break;
case CMD_ACT_MESH_CONFIG_STOP:
break;
default:
return -1;
}
lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
action, priv->mesh_tlv, chan,
print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
static void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode)
{

View file

@ -27,11 +27,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
/* persistcfg.c */
void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
/* main.c */
struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
void lbs_remove_card(struct lbs_private *priv);
@ -39,6 +34,9 @@ int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_set_mac_address(struct net_device *dev, void *addr);
void lbs_set_multicast_list(struct net_device *dev);
int lbs_suspend(struct lbs_private *priv);
void lbs_resume(struct lbs_private *priv);

View file

@ -6,6 +6,7 @@
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
#include "mesh.h"
#include "scan.h"
#include "assoc.h"
@ -21,17 +22,6 @@ struct sleep_params {
uint16_t sp_reserved;
};
/* Mesh statistics */
struct lbs_mesh_stats {
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
u32 fwd_drop_ttl; /* Fwd: TTL zero */
u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
u32 fwd_drop_noroute; /* Fwd: No route to Destination */
u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
u32 drop_blind; /* Rx: Dropped by blinding table */
u32 tx_failed_cnt; /* Tx: Failed transmissions */
};
/** Private structure for the MV device */
struct lbs_private {

View file

@ -8,17 +8,8 @@
#include "dev.h"
#include "wext.h"
#include "cmd.h"
#include "mesh.h"
static const char * mesh_stat_strings[]= {
"drop_duplicate_bcast",
"drop_ttl_zero",
"drop_no_fwd_route",
"drop_no_buffers",
"fwded_unicast_cnt",
"fwded_bcast_cnt",
"drop_blind_table",
"tx_failed_cnt"
};
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
@ -73,73 +64,6 @@ out:
return ret;
}
static void lbs_ethtool_get_stats(struct net_device *dev,
struct ethtool_stats *stats, uint64_t *data)
{
struct lbs_private *priv = dev->ml_priv;
struct cmd_ds_mesh_access mesh_access;
int ret;
lbs_deb_enter(LBS_DEB_ETHTOOL);
/* Get Mesh Statistics */
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
if (ret) {
memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
return;
}
priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
data[0] = priv->mstats.fwd_drop_rbt;
data[1] = priv->mstats.fwd_drop_ttl;
data[2] = priv->mstats.fwd_drop_noroute;
data[3] = priv->mstats.fwd_drop_nobuf;
data[4] = priv->mstats.fwd_unicast_cnt;
data[5] = priv->mstats.fwd_bcast_cnt;
data[6] = priv->mstats.drop_blind;
data[7] = priv->mstats.tx_failed_cnt;
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
{
struct lbs_private *priv = dev->ml_priv;
if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
return MESH_STATS_NUM;
return -EOPNOTSUPP;
}
static void lbs_ethtool_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *s)
{
int i;
lbs_deb_enter(LBS_DEB_ETHTOOL);
switch (stringset) {
case ETH_SS_STATS:
for (i=0; i < MESH_STATS_NUM; i++) {
memcpy(s + i * ETH_GSTRING_LEN,
mesh_stat_strings[i],
ETH_GSTRING_LEN);
}
break;
}
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
static void lbs_ethtool_get_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
@ -190,9 +114,9 @@ const struct ethtool_ops lbs_ethtool_ops = {
.get_drvinfo = lbs_ethtool_get_drvinfo,
.get_eeprom = lbs_ethtool_get_eeprom,
.get_eeprom_len = lbs_ethtool_get_eeprom_len,
.get_sset_count = lbs_ethtool_get_sset_count,
.get_ethtool_stats = lbs_ethtool_get_stats,
.get_strings = lbs_ethtool_get_strings,
.get_sset_count = lbs_mesh_ethtool_get_sset_count,
.get_ethtool_stats = lbs_mesh_ethtool_get_stats,
.get_strings = lbs_mesh_ethtool_get_strings,
.get_wol = lbs_ethtool_get_wol,
.set_wol = lbs_ethtool_set_wol,
};

View file

@ -94,107 +94,9 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
return 0;
}
/**
* Attributes exported through sysfs
*/
/**
* @brief Get function for sysfs attribute anycast_mask
*/
static ssize_t lbs_anycast_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
int ret;
memset(&mesh_access, 0, sizeof(mesh_access));
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
if (ret)
return ret;
return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
}
/**
* @brief Set function for sysfs attribute anycast_mask
*/
static ssize_t lbs_anycast_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
uint32_t datum;
int ret;
memset(&mesh_access, 0, sizeof(mesh_access));
sscanf(buf, "%x", &datum);
mesh_access.data[0] = cpu_to_le32(datum);
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute prb_rsp_limit
*/
static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
int ret;
u32 retry_limit;
memset(&mesh_access, 0, sizeof(mesh_access));
mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
&mesh_access);
if (ret)
return ret;
retry_limit = le32_to_cpu(mesh_access.data[1]);
return snprintf(buf, 10, "%d\n", retry_limit);
}
/**
* @brief Set function for sysfs attribute prb_rsp_limit
*/
static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
int ret;
unsigned long retry_limit;
memset(&mesh_access, 0, sizeof(mesh_access));
mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
if (!strict_strtoul(buf, 10, &retry_limit))
return -ENOTSUPP;
if (retry_limit > 15)
return -ENOTSUPP;
mesh_access.data[1] = cpu_to_le32(retry_limit);
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
&mesh_access);
if (ret)
return ret;
return strlen(buf);
}
static int lbs_add_rtap(struct lbs_private *priv);
static void lbs_remove_rtap(struct lbs_private *priv);
static int lbs_add_mesh(struct lbs_private *priv);
static void lbs_remove_mesh(struct lbs_private *priv);
/**
@ -260,74 +162,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
/**
* Get function for sysfs attribute mesh
*/
static ssize_t lbs_mesh_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
}
/**
* Set function for sysfs attribute mesh
*/
static ssize_t lbs_mesh_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
int enable;
int ret, action = CMD_ACT_MESH_CONFIG_STOP;
sscanf(buf, "%x", &enable);
enable = !!enable;
if (enable == !!priv->mesh_dev)
return count;
if (enable)
action = CMD_ACT_MESH_CONFIG_START;
ret = lbs_mesh_config(priv, action, priv->channel);
if (ret)
return ret;
if (enable)
lbs_add_mesh(priv);
else
lbs_remove_mesh(priv);
return count;
}
/**
* lbs_mesh attribute to be exported per ethX interface
* through sysfs (/sys/class/net/ethX/lbs_mesh)
*/
static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
/**
* anycast_mask attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/anycast_mask)
*/
static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
/**
* prb_rsp_limit attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/prb_rsp_limit)
*/
static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
lbs_prb_rsp_limit_set);
static struct attribute *lbs_mesh_sysfs_entries[] = {
&dev_attr_anycast_mask.attr,
&dev_attr_prb_rsp_limit.attr,
NULL,
};
static struct attribute_group lbs_mesh_attr_group = {
.attrs = lbs_mesh_sysfs_entries,
};
/**
* @brief This function opens the ethX or mshX interface
* @brief This function opens the ethX interface
*
* @param dev A pointer to net_device structure
* @return 0 or -EBUSY if monitor mode active
@ -346,18 +181,12 @@ static int lbs_dev_open(struct net_device *dev)
goto out;
}
if (dev == priv->mesh_dev) {
priv->mesh_open = 1;
priv->mesh_connect_status = LBS_CONNECTED;
netif_carrier_on(dev);
} else {
priv->infra_open = 1;
priv->infra_open = 1;
if (priv->connect_status == LBS_CONNECTED)
netif_carrier_on(dev);
else
netif_carrier_off(dev);
}
if (priv->connect_status == LBS_CONNECTED)
netif_carrier_on(dev);
else
netif_carrier_off(dev);
if (!priv->tx_pending_len)
netif_wake_queue(dev);
@ -368,33 +197,6 @@ static int lbs_dev_open(struct net_device *dev)
return ret;
}
/**
* @brief This function closes the mshX interface
*
* @param dev A pointer to net_device structure
* @return 0
*/
static int lbs_mesh_stop(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_MESH);
spin_lock_irq(&priv->driver_lock);
priv->mesh_open = 0;
priv->mesh_connect_status = LBS_DISCONNECTED;
netif_stop_queue(dev);
netif_carrier_off(dev);
spin_unlock_irq(&priv->driver_lock);
schedule_work(&priv->mcast_work);
lbs_deb_leave(LBS_DEB_MESH);
return 0;
}
/**
* @brief This function closes the ethX interface
*
@ -466,7 +268,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
}
EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
static int lbs_set_mac_address(struct net_device *dev, void *addr)
int lbs_set_mac_address(struct net_device *dev, void *addr)
{
int ret = 0;
struct lbs_private *priv = dev->ml_priv;
@ -600,7 +402,7 @@ static void lbs_set_mcast_worker(struct work_struct *work)
lbs_deb_leave(LBS_DEB_NET);
}
static void lbs_set_multicast_list(struct net_device *dev)
void lbs_set_multicast_list(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
@ -1177,7 +979,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->card = card;
priv->mesh_open = 0;
priv->infra_open = 0;
@ -1198,6 +999,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
priv->mesh_open = 0;
sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4;
@ -1292,50 +1094,12 @@ int lbs_start_card(struct lbs_private *priv)
lbs_update_channel(priv);
/* Check mesh FW version and appropriately send the mesh start
* command
/*
* While rtap isn't related to mesh, only mesh-enabled
* firmware implements the rtap functionality via
* CMD_802_11_MONITOR_MODE.
*/
if (priv->mesh_fw_ver == MESH_FW_OLD) {
/* Enable mesh, if supported, and work out which TLV it uses.
0x100 + 291 is an unofficial value used in 5.110.20.pXX
0x100 + 37 is the official value used in 5.110.21.pXX
but we check them in that order because 20.pXX doesn't
give an error -- it just silently fails. */
/* 5.110.20.pXX firmware will fail the command if the channel
doesn't match the existing channel. But only if the TLV
is correct. If the channel is wrong, _BOTH_ versions will
give an error to 0x100+291, and allow 0x100+37 to succeed.
It's just that 5.110.20.pXX will not have done anything
useful */
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->channel)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->channel))
priv->mesh_tlv = 0;
}
} else if (priv->mesh_fw_ver == MESH_FW_NEW) {
/* 10.0.0.pXX new firmwares should succeed with TLV
* 0x100+37; Do not invoke command with old TLV.
*/
priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
lbs_add_mesh(priv);
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
lbs_pr_err("cannot register lbs_mesh attribute\n");
/* While rtap isn't related to mesh, only mesh-enabled
* firmware implements the rtap functionality via
* CMD_802_11_MONITOR_MODE.
*/
if (lbs_init_mesh(priv)) {
if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
lbs_pr_err("cannot register lbs_rtap attribute\n");
}
@ -1369,10 +1133,8 @@ void lbs_stop_card(struct lbs_private *priv)
netif_carrier_off(dev);
lbs_debugfs_remove_one(priv);
if (priv->mesh_tlv) {
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
if (lbs_deinit_mesh(priv))
device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
}
/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
@ -1405,95 +1167,6 @@ out:
EXPORT_SYMBOL_GPL(lbs_stop_card);
static const struct net_device_ops mesh_netdev_ops = {
.ndo_open = lbs_dev_open,
.ndo_stop = lbs_mesh_stop,
.ndo_start_xmit = lbs_hard_start_xmit,
.ndo_set_mac_address = lbs_set_mac_address,
.ndo_set_multicast_list = lbs_set_multicast_list,
};
/**
* @brief This function adds mshX interface
*
* @param priv A pointer to the struct lbs_private structure
* @return 0 if successful, -X otherwise
*/
static int lbs_add_mesh(struct lbs_private *priv)
{
struct net_device *mesh_dev = NULL;
int ret = 0;
lbs_deb_enter(LBS_DEB_MESH);
/* Allocate a virtual mesh device */
if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
lbs_deb_mesh("init mshX device failed\n");
ret = -ENOMEM;
goto done;
}
mesh_dev->ml_priv = priv;
priv->mesh_dev = mesh_dev;
mesh_dev->netdev_ops = &mesh_netdev_ops;
mesh_dev->ethtool_ops = &lbs_ethtool_ops;
memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
sizeof(priv->dev->dev_addr));
SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
#ifdef WIRELESS_EXT
mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
#endif
mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
/* Register virtual mesh interface */
ret = register_netdev(mesh_dev);
if (ret) {
lbs_pr_err("cannot register mshX virtual interface\n");
goto err_free;
}
ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
if (ret)
goto err_unregister;
lbs_persist_config_init(mesh_dev);
/* Everything successful */
ret = 0;
goto done;
err_unregister:
unregister_netdev(mesh_dev);
err_free:
free_netdev(mesh_dev);
done:
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret;
}
static void lbs_remove_mesh(struct lbs_private *priv)
{
struct net_device *mesh_dev;
mesh_dev = priv->mesh_dev;
if (!mesh_dev)
return;
lbs_deb_enter(LBS_DEB_MESH);
netif_stop_queue(mesh_dev);
netif_carrier_off(mesh_dev);
sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
lbs_persist_config_remove(mesh_dev);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL;
free_netdev(mesh_dev);
lbs_deb_leave(LBS_DEB_MESH);
}
void lbs_queue_event(struct lbs_private *priv, u32 event)
{
unsigned long flags;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
/**
* Contains all definitions needed for the Libertas' MESH implementation.
*/
#ifndef _LBS_MESH_H_
#define _LBS_MESH_H_
#include <net/iw_handler.h>
#include <net/lib80211.h>
/* Mesh statistics */
struct lbs_mesh_stats {
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
u32 fwd_drop_ttl; /* Fwd: TTL zero */
u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
u32 fwd_drop_noroute; /* Fwd: No route to Destination */
u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
u32 drop_blind; /* Rx: Dropped by blinding table */
u32 tx_failed_cnt; /* Tx: Failed transmissions */
};
struct net_device;
struct lbs_private;
int lbs_init_mesh(struct lbs_private *priv);
int lbs_deinit_mesh(struct lbs_private *priv);
int lbs_add_mesh(struct lbs_private *priv);
void lbs_remove_mesh(struct lbs_private *priv);
/* Sending / Receiving */
struct rxpd;
struct txpd;
struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
struct net_device *dev, struct rxpd *rxpd);
void lbs_mesh_set_txpd(struct lbs_private *priv,
struct net_device *dev, struct txpd *txpd);
/* Command handling */
struct cmd_ds_command;
int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf);
int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf);
/* Persistent configuration */
void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
/* WEXT handler */
extern struct iw_handler_def mesh_handler_def;
/* Ethtool statistics */
struct ethtool_stats;
void lbs_mesh_ethtool_get_stats(struct net_device *dev,
struct ethtool_stats *stats, uint64_t *data);
int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset);
void lbs_mesh_ethtool_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *s);
#endif

View file

@ -1,453 +0,0 @@
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
#include "cmd.h"
static int mesh_get_default_parameters(struct device *dev,
struct mrvl_mesh_defaults *defs)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
int ret;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
CMD_TYPE_MESH_GET_DEFAULTS);
if (ret)
return -EOPNOTSUPP;
memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
return 0;
}
/**
* @brief Get function for sysfs attribute bootflag
*/
static ssize_t bootflag_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
}
/**
* @brief Set function for sysfs attribute bootflag
*/
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%d", &datum);
if ((ret != 1) || (datum > 1))
return -EINVAL;
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
cmd.length = cpu_to_le16(sizeof(uint32_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_BOOTFLAG);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute boottime
*/
static ssize_t boottime_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "%d\n", defs.boottime);
}
/**
* @brief Set function for sysfs attribute boottime
*/
static ssize_t boottime_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%d", &datum);
if ((ret != 1) || (datum > 255))
return -EINVAL;
/* A too small boot time will result in the device booting into
* standalone (no-host) mode before the host can take control of it,
* so the change will be hard to revert. This may be a desired
* feature (e.g to configure a very fast boot time for devices that
* will not be attached to a host), but dangerous. So I'm enforcing a
* lower limit of 20 seconds: remove and recompile the driver if this
* does not work for you.
*/
datum = (datum < 20) ? 20 : datum;
cmd.data[0] = datum;
cmd.length = cpu_to_le16(sizeof(uint8_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_BOOTTIME);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute channel
*/
static ssize_t channel_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
}
/**
* @brief Set function for sysfs attribute channel
*/
static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%d", &datum);
if (ret != 1 || datum < 1 || datum > 11)
return -EINVAL;
*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
cmd.length = cpu_to_le16(sizeof(uint16_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_DEF_CHANNEL);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute mesh_id
*/
static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mrvl_mesh_defaults defs;
int maxlen;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
lbs_pr_err("inconsistent mesh ID length");
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
/* SSID not null terminated: reserve room for \0 + \n */
maxlen = defs.meshie.val.mesh_id_len + 2;
maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
}
/**
* @brief Set function for sysfs attribute mesh_id
*/
static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
int len;
int ret;
if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
return -EINVAL;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
ie = (struct mrvl_meshie *) &cmd.data[0];
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
len = count - 1;
memcpy(ie->val.mesh_id, buf, len);
/* SSID len */
ie->val.mesh_id_len = len;
/* IE len */
ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute protocol_id
*/
static ssize_t protocol_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
}
/**
* @brief Set function for sysfs attribute protocol_id
*/
static ssize_t protocol_id_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%d", &datum);
if ((ret != 1) || (datum > 255))
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update protocol id */
ie->val.active_protocol_id = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute metric_id
*/
static ssize_t metric_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
}
/**
* @brief Set function for sysfs attribute metric_id
*/
static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%d", &datum);
if ((ret != 1) || (datum > 255))
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update metric id */
ie->val.active_metric_id = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute capability
*/
static ssize_t capability_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
}
/**
* @brief Set function for sysfs attribute capability
*/
static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%d", &datum);
if ((ret != 1) || (datum > 255))
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update value */
ie->val.mesh_capability = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
static struct attribute *boot_opts_attrs[] = {
&dev_attr_bootflag.attr,
&dev_attr_boottime.attr,
&dev_attr_channel.attr,
NULL
};
static struct attribute_group boot_opts_group = {
.name = "boot_options",
.attrs = boot_opts_attrs,
};
static struct attribute *mesh_ie_attrs[] = {
&dev_attr_mesh_id.attr,
&dev_attr_protocol_id.attr,
&dev_attr_metric_id.attr,
&dev_attr_capability.attr,
NULL
};
static struct attribute_group mesh_ie_group = {
.name = "mesh_ie",
.attrs = mesh_ie_attrs,
};
void lbs_persist_config_init(struct net_device *dev)
{
int ret;
ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
}
void lbs_persist_config_remove(struct net_device *dev)
{
sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
}

View file

@ -160,15 +160,8 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
p_rx_pd = (struct rxpd *) skb->data;
p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
le32_to_cpu(p_rx_pd->pkt_ptr));
if (priv->mesh_dev) {
if (priv->mesh_fw_ver == MESH_FW_OLD) {
if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
dev = priv->mesh_dev;
} else if (priv->mesh_fw_ver == MESH_FW_NEW) {
if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID)
dev = priv->mesh_dev;
}
}
dev = lbs_mesh_set_dev(priv, dev, p_rx_pd);
lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
min_t(unsigned int, skb->len, 100));

View file

@ -131,12 +131,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
txpd->tx_packet_length = cpu_to_le16(pkt_len);
txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
if (dev == priv->mesh_dev) {
if (priv->mesh_fw_ver == MESH_FW_OLD)
txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
else if (priv->mesh_fw_ver == MESH_FW_NEW)
txpd->u.bss.bss_num = MESH_IFACE_ID;
}
lbs_mesh_set_txpd(priv, dev, txpd);
lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));

View file

@ -7,12 +7,11 @@
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
extern struct iw_handler_def lbs_handler_def;
extern struct iw_handler_def mesh_handler_def;
struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
struct lbs_private *priv,
u8 band,
u16 channel);
extern struct iw_handler_def lbs_handler_def;
#endif

View file

@ -2865,18 +2865,8 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
/*===========================================================================*/
#ifdef CONFIG_PROC_FS
static void raycs_write(const char *name, write_proc_t *w, void *data)
{
struct proc_dir_entry *entry =
create_proc_entry(name, S_IFREG | S_IWUSR, NULL);
if (entry) {
entry->write_proc = w;
entry->data = data;
}
}
static int write_essid(struct file *file, const char __user *buffer,
unsigned long count, void *data)
static ssize_t ray_cs_essid_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *pos)
{
static char proc_essid[33];
unsigned int len = count;
@ -2890,8 +2880,13 @@ static int write_essid(struct file *file, const char __user *buffer,
return count;
}
static int write_int(struct file *file, const char __user *buffer,
unsigned long count, void *data)
static const struct file_operations ray_cs_essid_proc_fops = {
.owner = THIS_MODULE,
.write = ray_cs_essid_proc_write,
};
static ssize_t int_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
static char proc_number[10];
char *p;
@ -2914,9 +2909,14 @@ static int write_int(struct file *file, const char __user *buffer,
nr = nr * 10 + c;
p++;
} while (--len);
*(int *)data = nr;
*(int *)PDE(file->f_path.dentry->d_inode)->data = nr;
return count;
}
static const struct file_operations int_proc_fops = {
.owner = THIS_MODULE,
.write = int_proc_write,
};
#endif
static struct pcmcia_device_id ray_ids[] = {
@ -2951,9 +2951,9 @@ static int __init init_ray_cs(void)
proc_mkdir("driver/ray_cs", NULL);
proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops);
raycs_write("driver/ray_cs/essid", write_essid, NULL);
raycs_write("driver/ray_cs/net_type", write_int, &net_type);
raycs_write("driver/ray_cs/translate", write_int, &translate);
proc_create("driver/ray_cs/essid", S_IWUSR, NULL, &ray_cs_essid_proc_fops);
proc_create_data("driver/ray_cs/net_type", S_IWUSR, NULL, &int_proc_fops, &net_type);
proc_create_data("driver/ray_cs/translate", S_IWUSR, NULL, &int_proc_fops, &translate);
#endif
if (translate != 0)
translate = 1;

View file

@ -1432,7 +1432,6 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -1623,20 +1622,21 @@ static const struct data_queue_desc rt2400pci_queue_atim = {
};
static const struct rt2x00_ops rt2400pci_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2400pci_queue_rx,
.tx = &rt2400pci_queue_tx,
.bcn = &rt2400pci_queue_bcn,
.atim = &rt2400pci_queue_atim,
.lib = &rt2400pci_rt2x00_ops,
.hw = &rt2400pci_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = 0,
.rx = &rt2400pci_queue_rx,
.tx = &rt2400pci_queue_tx,
.bcn = &rt2400pci_queue_bcn,
.atim = &rt2400pci_queue_atim,
.lib = &rt2400pci_rt2x00_ops,
.hw = &rt2400pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2400pci_rt2x00debug,
.debugfs = &rt2400pci_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -1733,8 +1733,6 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
@ -1922,20 +1920,21 @@ static const struct data_queue_desc rt2500pci_queue_atim = {
};
static const struct rt2x00_ops rt2500pci_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2500pci_queue_rx,
.tx = &rt2500pci_queue_tx,
.bcn = &rt2500pci_queue_bcn,
.atim = &rt2500pci_queue_atim,
.lib = &rt2500pci_rt2x00_ops,
.hw = &rt2500pci_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = 0,
.rx = &rt2500pci_queue_rx,
.tx = &rt2500pci_queue_tx,
.bcn = &rt2500pci_queue_bcn,
.atim = &rt2500pci_queue_atim,
.lib = &rt2500pci_rt2x00_ops,
.hw = &rt2500pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2500pci_rt2x00debug,
.debugfs = &rt2500pci_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -1656,8 +1656,6 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
@ -1823,20 +1821,21 @@ static const struct data_queue_desc rt2500usb_queue_atim = {
};
static const struct rt2x00_ops rt2500usb_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2500usb_queue_rx,
.tx = &rt2500usb_queue_tx,
.bcn = &rt2500usb_queue_bcn,
.atim = &rt2500usb_queue_atim,
.lib = &rt2500usb_rt2x00_ops,
.hw = &rt2500usb_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = TXD_DESC_SIZE,
.rx = &rt2500usb_queue_rx,
.tx = &rt2500usb_queue_tx,
.bcn = &rt2500usb_queue_bcn,
.atim = &rt2500usb_queue_atim,
.lib = &rt2500usb_rt2x00_ops,
.hw = &rt2500usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2500usb_rt2x00debug,
.debugfs = &rt2500usb_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -217,14 +217,12 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
if (rt2x00_intf_is_pci(rt2x00dev)) {
/*
* RT2880 and RT3052 don't support MCU requests.
*/
if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
rt2x00_rt(&rt2x00dev->chip, RT3052))
return;
}
/*
* RT2880 and RT3052 don't support MCU requests.
*/
if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
rt2x00_rt(&rt2x00dev->chip, RT3052))
return;
mutex_lock(&rt2x00dev->csr_mutex);
@ -1482,8 +1480,7 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 105, 0x05);
}
if (rt2x00_intf_is_pci(rt2x00dev) &&
rt2x00_rt(&rt2x00dev->chip, RT3052)) {
if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
rt2800_bbp_write(rt2x00dev, 31, 0x08);
rt2800_bbp_write(rt2x00dev, 78, 0x0e);
rt2800_bbp_write(rt2x00dev, 80, 0x08);
@ -2033,12 +2030,6 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
if (rt2x00_intf_is_usb(rt2x00dev))
rt2x00dev->hw->extra_tx_headroom =
TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
else if (rt2x00_intf_is_pci(rt2x00dev))
rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
@ -2072,7 +2063,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize HT information.
*/
spec->ht.ht_supported = true;
if (!rt2x00_rf(chip, RF2020))
spec->ht.ht_supported = true;
else
spec->ht.ht_supported = false;
spec->ht.cap =
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |

View file

@ -652,7 +652,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
__le32 *txwi = (__le32 *)(skb->data - rt2x00dev->hw->extra_tx_headroom);
__le32 *txwi = (__le32 *)(skb->data - rt2x00dev->ops->extra_tx_headroom);
u32 word;
/*
@ -725,14 +725,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_BURST,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
rt2x00dev->hw->extra_tx_headroom);
rt2x00dev->ops->extra_tx_headroom);
rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
skbdesc->skb_dma + rt2x00dev->hw->extra_tx_headroom);
skbdesc->skb_dma + rt2x00dev->ops->extra_tx_headroom);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 3, &word);
@ -1201,19 +1201,20 @@ static const struct data_queue_desc rt2800pci_queue_bcn = {
};
static const struct rt2x00_ops rt2800pci_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2800pci_queue_rx,
.tx = &rt2800pci_queue_tx,
.bcn = &rt2800pci_queue_bcn,
.lib = &rt2800pci_rt2x00_ops,
.hw = &rt2800_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = TXWI_DESC_SIZE,
.rx = &rt2800pci_queue_rx,
.tx = &rt2800pci_queue_tx,
.bcn = &rt2800pci_queue_bcn,
.lib = &rt2800pci_rt2x00_ops,
.hw = &rt2800_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -790,19 +790,20 @@ static const struct data_queue_desc rt2800usb_queue_bcn = {
};
static const struct rt2x00_ops rt2800usb_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2800usb_queue_rx,
.tx = &rt2800usb_queue_tx,
.bcn = &rt2800usb_queue_bcn,
.lib = &rt2800usb_rt2x00_ops,
.hw = &rt2800_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE,
.rx = &rt2800usb_queue_rx,
.tx = &rt2800usb_queue_tx,
.bcn = &rt2800usb_queue_bcn,
.lib = &rt2800usb_rt2x00_ops,
.hw = &rt2800_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -588,6 +588,7 @@ struct rt2x00_ops {
const unsigned int eeprom_size;
const unsigned int rf_size;
const unsigned int tx_queues;
const unsigned int extra_tx_headroom;
const struct data_queue_desc *rx;
const struct data_queue_desc *tx;
const struct data_queue_desc *bcn;

View file

@ -683,6 +683,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues;
/*
* Initialize extra TX headroom required.
*/
rt2x00dev->hw->extra_tx_headroom = rt2x00dev->ops->extra_tx_headroom;
/*
* Register HW.
*/

View file

@ -103,10 +103,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
enum data_queue_qid qid = skb_get_queue_mapping(skb);
struct data_queue *queue;
u16 frame_control;
/*
* Mac80211 might be calling this function while we are trying
@ -141,7 +139,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* either RTS or CTS-to-self frame and handles everything
* inside the hardware.
*/
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
!rt2x00dev->ops->hw->set_rts_threshold) {

View file

@ -162,10 +162,10 @@ void rt2x00queue_align_frame(struct sk_buff *skb)
skb_trim(skb, frame_length);
}
void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt)
void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
{
unsigned int frame_length = skb->len;
unsigned int align = ALIGN_SIZE(skb, header_lengt);
unsigned int align = ALIGN_SIZE(skb, header_length);
if (!align)
return;
@ -214,7 +214,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
skb_push(skb, header_align);
memmove(skb->data, skb->data + header_align, header_length);
memmove(skb->data + header_length + l2pad,
skb->data + header_length + l2pad + header_align,
skb->data + header_length + l2pad + payload_align,
frame_length - header_length);
skbdesc->flags |= SKBDESC_L2_PADDED;
}

View file

@ -2546,7 +2546,6 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -2788,19 +2787,20 @@ static const struct data_queue_desc rt61pci_queue_bcn = {
};
static const struct rt2x00_ops rt61pci_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt61pci_queue_rx,
.tx = &rt61pci_queue_tx,
.bcn = &rt61pci_queue_bcn,
.lib = &rt61pci_rt2x00_ops,
.hw = &rt61pci_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = 0,
.rx = &rt61pci_queue_rx,
.tx = &rt61pci_queue_tx,
.bcn = &rt61pci_queue_bcn,
.lib = &rt61pci_rt2x00_ops,
.hw = &rt61pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt61pci_rt2x00debug,
.debugfs = &rt61pci_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -2069,7 +2069,6 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -2306,19 +2305,20 @@ static const struct data_queue_desc rt73usb_queue_bcn = {
};
static const struct rt2x00_ops rt73usb_ops = {
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt73usb_queue_rx,
.tx = &rt73usb_queue_tx,
.bcn = &rt73usb_queue_bcn,
.lib = &rt73usb_rt2x00_ops,
.hw = &rt73usb_mac80211_ops,
.name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.extra_tx_headroom = TXD_DESC_SIZE,
.rx = &rt73usb_queue_rx,
.tx = &rt73usb_queue_tx,
.bcn = &rt73usb_queue_bcn,
.lib = &rt73usb_rt2x00_ops,
.hw = &rt73usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt73usb_rt2x00debug,
.debugfs = &rt73usb_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};

View file

@ -188,6 +188,113 @@ static int wl1271_cmd_cal(struct wl1271 *wl)
return ret;
}
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
struct conf_general_parms *g = &wl->conf.init.genparam;
int ret;
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
gen_parms->ref_clk = g->ref_clk;
gen_parms->settling_time = g->settling_time;
gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup;
gen_parms->dc2dcmode = g->dc2dcmode;
gen_parms->single_dual_band = g->single_dual_band;
gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect;
gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
gen_parms->settings = g->settings;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
kfree(gen_parms);
return ret;
}
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_radio_parms_cmd *radio_parms;
struct conf_radio_parms *r = &wl->conf.init.radioparam;
int i, ret;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
return -ENOMEM;
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* Static radio parameters */
radio_parms->rx_trace_loss = r->rx_trace_loss;
radio_parms->tx_trace_loss = r->tx_trace_loss;
memcpy(radio_parms->rx_rssi_and_proc_compens,
r->rx_rssi_and_proc_compens,
CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->rx_rssi_and_proc_compens_5,
r->rx_rssi_and_proc_compens_5,
CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
/* Dynamic radio parameters */
radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage);
radio_parms->tx_ref_power = r->tx_ref_power;
radio_parms->tx_offset_db = r->tx_offset_db;
memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
CONF_NUMBER_OF_CHANNELS_2_4);
memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm,
CONF_NUMBER_OF_CHANNELS_2_4);
memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
radio_parms->tx_ref_pd_voltage_5[i] =
cpu_to_le16(r->tx_ref_pd_voltage_5[i]);
memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_rate_limits_normal_5,
r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded_5,
r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_ofdm_5,
r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->rx_fem_insertion_loss_5,
r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
kfree(radio_parms);
return ret;
}
int wl1271_cmd_join(struct wl1271 *wl)
{
static bool do_cal = true;

View file

@ -31,6 +31,8 @@ struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_join(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
@ -418,6 +420,76 @@ enum wl1271_channel_tune_bands {
#define TEST_CMD_P2G_CAL 0x02
#define TEST_CMD_CHANNEL_TUNE 0x0d
#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
struct wl1271_general_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
u8 ref_clk;
u8 settling_time;
u8 clk_valid_on_wakeup;
u8 dc2dcmode;
u8 single_dual_band;
u8 tx_bip_fem_autodetect;
u8 tx_bip_fem_manufacturer;
u8 settings;
} __attribute__ ((packed));
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
/* Static radio parameters */
/* 2.4GHz */
u8 rx_trace_loss;
u8 tx_trace_loss;
s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* 5GHz */
u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* Dynamic radio parameters */
/* 2.4GHz */
__le16 tx_ref_pd_voltage;
s8 tx_ref_power;
s8 tx_offset_db;
s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 padding2;
/* 5GHz */
__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
/* FIXME: this is inconsistent with the types for 2.4GHz */
s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 padding3[2];
} __attribute__ ((packed));
struct wl1271_cmd_cal_channel_tune {
struct wl1271_cmd_header header;

View file

@ -78,12 +78,16 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
switch (mbox->ps_status) {
case EVENT_ENTER_POWER_SAVE_FAIL:
if (!wl->psm) {
wl->psm_entry_retry = 0;
break;
}
if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
wl->psm_entry_retry++;
wl1271_error("PSM entry failed, retrying %d\n",
wl->psm_entry_retry);
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
} else {
wl1271_error("PSM entry failed, giving up.\n");
wl->psm_entry_retry = 0;
*beacon_loss = true;
}

View file

@ -193,125 +193,16 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
return 0;
}
static int wl1271_init_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms *gen_parms;
struct conf_general_parms *g = &wl->conf.init.genparam;
int ret;
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM;
gen_parms->ref_clk = g->ref_clk;
gen_parms->settling_time = g->settling_time;
gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup;
gen_parms->dc2dcmode = g->dc2dcmode;
gen_parms->single_dual_band = g->single_dual_band;
gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect;
gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
gen_parms->settings = g->settings;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
return ret;
}
kfree(gen_parms);
return 0;
}
static int wl1271_init_radio_parms(struct wl1271 *wl)
{
struct wl1271_radio_parms *radio_parms;
struct conf_radio_parms *r = &wl->conf.init.radioparam;
int i, ret;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
return -ENOMEM;
radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* Static radio parameters */
radio_parms->rx_trace_loss = r->rx_trace_loss;
radio_parms->tx_trace_loss = r->tx_trace_loss;
memcpy(radio_parms->rx_rssi_and_proc_compens,
r->rx_rssi_and_proc_compens,
CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->rx_rssi_and_proc_compens_5,
r->rx_rssi_and_proc_compens_5,
CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
/* Dynamic radio parameters */
radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage);
radio_parms->tx_ref_power = r->tx_ref_power;
radio_parms->tx_offset_db = r->tx_offset_db;
memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
CONF_NUMBER_OF_CHANNELS_2_4);
memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm,
CONF_NUMBER_OF_CHANNELS_2_4);
memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
radio_parms->tx_ref_pd_voltage_5[i] =
cpu_to_le16(r->tx_ref_pd_voltage_5[i]);
memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_rate_limits_normal_5,
r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded_5,
r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_ofdm_5,
r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->rx_fem_insertion_loss_5,
r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
kfree(radio_parms);
return ret;
}
int wl1271_hw_init(struct wl1271 *wl)
{
int ret;
/* FIXME: the following parameter setting functions return error
* codes - the reason is so far unknown. The -EIO is therefore
* ignored for the time being. */
ret = wl1271_init_general_parms(wl);
if (ret < 0 && ret != -EIO)
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
return ret;
ret = wl1271_init_radio_parms(wl);
if (ret < 0 && ret != -EIO)
ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
return ret;
/* Template settings */

View file

@ -29,74 +29,4 @@
int wl1271_hw_init_power_auth(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
/* These are not really a TEST_CMD, but the ref driver uses them as such */
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
struct wl1271_general_parms {
u8 id;
u8 padding[3];
u8 ref_clk;
u8 settling_time;
u8 clk_valid_on_wakeup;
u8 dc2dcmode;
u8 single_dual_band;
u8 tx_bip_fem_autodetect;
u8 tx_bip_fem_manufacturer;
u8 settings;
} __attribute__ ((packed));
struct wl1271_radio_parms {
u8 id;
u8 padding[3];
/* Static radio parameters */
/* 2.4GHz */
u8 rx_trace_loss;
u8 tx_trace_loss;
s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* 5GHz */
u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* Dynamic radio parameters */
/* 2.4GHz */
__le16 tx_ref_pd_voltage;
s8 tx_ref_power;
s8 tx_offset_db;
s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 padding2;
/* 5GHz */
__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
/* FIXME: this is inconsistent with the types for 2.4GHz */
s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 padding3[2];
} __attribute__ ((packed));
#endif

View file

@ -222,7 +222,7 @@ static struct conf_drv_settings default_conf = {
.snr_pkt_avg_weight = 10
},
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 100,
.bet_max_consecutive = 10,
.psm_entry_retries = 3
},
.init = {
@ -251,14 +251,7 @@ static struct conf_drv_settings default_conf = {
},
.sr_enable = 1,
.genparam = {
/*
* FIXME: The correct value CONF_REF_CLK_38_4_E
* causes the firmware to crash on boot.
* The value 5 apparently is an
* unnoficial XTAL configuration of the
* same frequency, which appears to work.
*/
.ref_clk = 5,
.ref_clk = CONF_REF_CLK_38_4_E,
.settling_time = 5,
.clk_valid_on_wakeup = 0,
.dc2dcmode = 0,
@ -354,6 +347,14 @@ static int wl1271_plt_init(struct wl1271 *wl)
{
int ret;
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
return ret;
ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
return ret;
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
return ret;
@ -815,15 +816,15 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
wdev = dev->ieee80211_ptr;
if (wdev == NULL)
return -ENODEV;
return NOTIFY_DONE;
wiphy = wdev->wiphy;
if (wiphy == NULL)
return -ENODEV;
return NOTIFY_DONE;
hw = wiphy_priv(wiphy);
if (hw == NULL)
return -ENODEV;
return NOTIFY_DONE;
/* Check that the interface is one supported by this driver. */
wl_temp = hw->priv;
@ -832,7 +833,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
break;
}
if (wl == NULL)
return -ENODEV;
return NOTIFY_DONE;
/* Get the interface IP address for the device. "ifa" will become
NULL if:
@ -868,7 +869,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
out:
mutex_unlock(&wl->mutex);
return ret;
return NOTIFY_OK;
}
static struct notifier_block wl1271_dev_notifier = {
@ -1753,7 +1754,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_BEACON_FILTER;
IEEE80211_HW_BEACON_FILTER |
IEEE80211_HW_SUPPORTS_PS;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;

View file

@ -1266,6 +1266,8 @@ enum ieee80211_sa_query_action {
#define WLAN_MAX_KEY_LEN 32
#define WLAN_PMKID_LEN 16
/**
* ieee80211_get_qos_ctl - get pointer to qos control bytes
* @hdr: the frame

View file

@ -349,6 +349,10 @@ enum nl80211_commands {
NL80211_CMD_GET_SURVEY,
NL80211_CMD_NEW_SURVEY_RESULTS,
NL80211_CMD_SET_PMKSA,
NL80211_CMD_DEL_PMKSA,
NL80211_CMD_FLUSH_PMKSA,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -598,6 +602,10 @@ enum nl80211_commands {
* the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
* containing info as possible, see &enum survey_info.
*
* @NL80211_ATTR_PMKID: PMK material for PMKSA caching.
* @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
* cache, a wiphy attribute.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -732,6 +740,9 @@ enum nl80211_attrs {
NL80211_ATTR_SURVEY_INFO,
NL80211_ATTR_PMKID,
NL80211_ATTR_MAX_NUM_PMKIDS,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,

View file

@ -871,6 +871,19 @@ struct cfg80211_bitrate_mask {
u32 fixed; /* fixed bitrate, 0 == not fixed */
u32 maxrate; /* in kbps, 0 == no limit */
};
/**
* struct cfg80211_pmksa - PMK Security Association
*
* This structure is passed to the set/del_pmksa() method for PMKSA
* caching.
*
* @bssid: The AP's BSSID.
* @pmkid: The PMK material itself.
*/
struct cfg80211_pmksa {
u8 *bssid;
u8 *pmkid;
};
/**
* struct cfg80211_ops - backend description for wireless configuration
@ -976,6 +989,13 @@ struct cfg80211_bitrate_mask {
* @dump_survey: get site survey information.
*
* @testmode_cmd: run a test mode command
*
* @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
* devices running firmwares capable of generating the (re) association
* RSN IE. It allows for faster roaming between WPA2 BSSIDs.
* @del_pmksa: Delete a cached PMKID.
* @flush_pmksa: Flush all cached PMKIDs.
*
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
@ -1097,6 +1117,12 @@ struct cfg80211_ops {
int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev,
int idx, struct survey_info *info);
int (*set_pmksa)(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa);
int (*del_pmksa)(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa);
int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);
/* some temporary stuff to finish wext */
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout);
@ -1195,6 +1221,8 @@ struct wiphy {
char fw_version[ETHTOOL_BUSINFO_LEN];
u32 hw_version;
u8 max_num_pmkids;
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered

View file

@ -513,6 +513,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
* @RX_FLAG_40MHZ: HT40 (40 MHz) was used
* @RX_FLAG_SHORT_GI: Short guard interval was used
* @RX_FLAG_INTERNAL_CMTR: set internally after frame was reported
* on cooked monitor to avoid double-reporting it for multiple
* virtual interfaces
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
@ -526,6 +529,7 @@ enum mac80211_rx_flags {
RX_FLAG_HT = 1<<9,
RX_FLAG_40MHZ = 1<<10,
RX_FLAG_SHORT_GI = 1<<11,
RX_FLAG_INTERNAL_CMTR = 1<<12,
};
/**

View file

@ -131,17 +131,35 @@ TRACE_EVENT(drv_config,
LOCAL_ENTRY
__field(u32, changed)
__field(int, ret)
__field(u32, flags)
__field(int, power_level)
__field(int, dynamic_ps_timeout)
__field(int, max_sleep_period)
__field(u16, listen_interval)
__field(u8, long_frame_max_tx_count)
__field(u8, short_frame_max_tx_count)
__field(int, center_freq)
__field(int, channel_type)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->changed = changed;
__entry->ret = ret;
__entry->flags = local->hw.conf.flags;
__entry->power_level = local->hw.conf.power_level;
__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
__entry->max_sleep_period = local->hw.conf.max_sleep_period;
__entry->listen_interval = local->hw.conf.listen_interval;
__entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
__entry->center_freq = local->hw.conf.channel->center_freq;
__entry->channel_type = local->hw.conf.channel_type;
),
TP_printk(
LOCAL_PR_FMT " ch:%#x ret:%d",
LOCAL_PR_ARG, __entry->changed, __entry->ret
LOCAL_PR_FMT " ch:%#x freq:%d ret:%d",
LOCAL_PR_ARG, __entry->changed, __entry->center_freq, __entry->ret
)
);
@ -167,6 +185,8 @@ TRACE_EVENT(drv_bss_info_changed,
__field(u64, timestamp)
__field(u32, basic_rates)
__field(u32, changed)
__field(bool, enable_beacon)
__field(u16, ht_operation_mode)
),
TP_fast_assign(
@ -183,6 +203,8 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->assoc_cap = info->assoc_capability;
__entry->timestamp = info->timestamp;
__entry->basic_rates = info->basic_rates;
__entry->enable_beacon = info->enable_beacon;
__entry->ht_operation_mode = info->ht_operation_mode;
),
TP_printk(

View file

@ -163,8 +163,8 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
/* frame is destined to interface currently processed (incl. multicast frames) */
#define IEEE80211_RX_RA_MATCH BIT(1)
#define IEEE80211_RX_AMSDU BIT(2)
#define IEEE80211_RX_CMNTR_REPORTED BIT(3)
#define IEEE80211_RX_FRAGMENTED BIT(4)
#define IEEE80211_RX_FRAGMENTED BIT(3)
/* only add flags here that do not change with subframes of an aMPDU */
struct ieee80211_rx_data {
struct sk_buff *skb;

View file

@ -860,22 +860,18 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
void ieee80211_remove_interfaces(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata, *tmp;
LIST_HEAD(unreg_list);
ASSERT_RTNL();
mutex_lock(&local->iflist_mtx);
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
/*
* we cannot hold the iflist_mtx across unregister_netdevice,
* but we only need to hold it for list modifications to lock
* out readers since we're under the RTNL here as all other
* writers.
*/
mutex_lock(&local->iflist_mtx);
list_del(&sdata->list);
mutex_unlock(&local->iflist_mtx);
unregister_netdevice(sdata->dev);
unregister_netdevice_queue(sdata->dev, &unreg_list);
}
mutex_unlock(&local->iflist_mtx);
unregister_netdevice_many(&unreg_list);
}
static u32 ieee80211_idle_off(struct ieee80211_local *local,

View file

@ -27,10 +27,6 @@
#include "tkip.h"
#include "wme.h"
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
u16 head_seq_num);
/*
* monitor mode reception
*
@ -534,6 +530,242 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}
#define SEQ_MODULO 0x1000
#define SEQ_MASK 0xfff
static inline int seq_less(u16 sq1, u16 sq2)
{
return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
}
static inline u16 seq_inc(u16 sq)
{
return (sq + 1) & SEQ_MASK;
}
static inline u16 seq_sub(u16 sq1, u16 sq2)
{
return (sq1 - sq2) & SEQ_MASK;
}
static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
int index,
struct sk_buff_head *frames)
{
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate = NULL;
struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
struct ieee80211_rx_status *status;
if (!skb)
goto no_frame;
status = IEEE80211_SKB_RXCB(skb);
/* release the reordered frames to stack */
sband = hw->wiphy->bands[status->band];
if (!(status->flag & RX_FLAG_HT))
rate = &sband->bitrates[status->rate_idx];
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
skb_queue_tail(frames, skb);
no_frame:
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
}
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
u16 head_seq_num,
struct sk_buff_head *frames)
{
int index;
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
}
}
/*
* Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
* the skb was added to the buffer longer than this time ago, the earlier
* frames that have not yet been received are assumed to be lost and the skb
* can be released for processing. This may also release other skb's from the
* reorder buffer if there are no additional gaps between the frames.
*/
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
/*
* As this function belongs to the RX path it must be under
* rcu_read_lock protection. It returns false if the frame
* can be processed immediately, true if it was consumed.
*/
static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb,
struct sk_buff_head *frames)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 sc = le16_to_cpu(hdr->seq_ctrl);
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
u16 head_seq_num, buf_size;
int index;
buf_size = tid_agg_rx->buf_size;
head_seq_num = tid_agg_rx->head_seq_num;
/* frame with out of date sequence number */
if (seq_less(mpdu_seq_num, head_seq_num)) {
dev_kfree_skb(skb);
return true;
}
/*
* If frame the sequence number exceeds our buffering window
* size release some previous frames to make room for this one.
*/
if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
/* release stored frames up to new head to stack */
ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num,
frames);
}
/* Now the new frame is always in the range of the reordering buffer */
index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
/* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) {
dev_kfree_skb(skb);
return true;
}
/*
* If the current MPDU is in the right order and nothing else
* is stored we can process it directly, no need to buffer it.
*/
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) {
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
return false;
}
/* put the frame in the reordering buffer */
tid_agg_rx->reorder_buf[index] = skb;
tid_agg_rx->reorder_time[index] = jiffies;
tid_agg_rx->stored_mpdu_num++;
/* release the buffer until next missing frame */
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
if (!tid_agg_rx->reorder_buf[index] &&
tid_agg_rx->stored_mpdu_num > 1) {
/*
* No buffers ready to be released, but check whether any
* frames in the reorder buffer have timed out.
*/
int j;
int skipped = 1;
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
j = (j + 1) % tid_agg_rx->buf_size) {
if (!tid_agg_rx->reorder_buf[j]) {
skipped++;
continue;
}
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
HT_RX_REORDER_BUF_TIMEOUT))
break;
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: release an RX reorder "
"frame due to timeout on earlier "
"frames\n",
wiphy_name(hw->wiphy));
#endif
ieee80211_release_reorder_frame(hw, tid_agg_rx,
j, frames);
/*
* Increment the head seq# also for the skipped slots.
*/
tid_agg_rx->head_seq_num =
(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
skipped = 0;
}
} else while (tid_agg_rx->reorder_buf[index]) {
ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
}
return true;
}
/*
* Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
* true if the MPDU was buffered, false if it should be processed.
*/
static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
struct sk_buff_head *frames)
{
struct sk_buff *skb = rx->skb;
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct sta_info *sta = rx->sta;
struct tid_ampdu_rx *tid_agg_rx;
u16 sc;
int tid;
if (!ieee80211_is_data_qos(hdr->frame_control))
goto dont_reorder;
/*
* filter the QoS data rx stream according to
* STA/TID and check if this STA/TID is on aggregation
*/
if (!sta)
goto dont_reorder;
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
goto dont_reorder;
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
/* qos null data frames are excluded */
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
goto dont_reorder;
/* new, potentially un-ordered, ampdu frame - process it */
/* reset session timer */
if (tid_agg_rx->timeout)
mod_timer(&tid_agg_rx->session_timer,
TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
dev_kfree_skb(skb);
return;
}
if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
return;
dont_reorder:
__skb_queue_tail(frames, skb);
}
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
@ -637,6 +869,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
/* start without a key */
rx->key = NULL;
if (rx->sta)
stakey = rcu_dereference(rx->sta->key);
@ -1589,7 +1824,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
}
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
@ -1619,7 +1854,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* release stored frames up to start of BAR */
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
frames);
kfree_skb(skb);
return RX_QUEUED;
}
@ -1868,7 +2104,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
if (status->flag & RX_FLAG_INTERNAL_CMTR)
goto out_free_skb;
if (skb_headroom(skb) < sizeof(*rthdr) &&
@ -1929,7 +2165,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
} else
goto out_free_skb;
rx->flags |= IEEE80211_RX_CMNTR_REPORTED;
status->flag |= RX_FLAG_INTERNAL_CMTR;
return;
out_free_skb:
@ -1942,8 +2178,11 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_rate *rate)
{
struct sk_buff_head reorder_release;
ieee80211_rx_result res = RX_DROP_MONITOR;
__skb_queue_head_init(&reorder_release);
rx->skb = skb;
rx->sdata = sdata;
@ -1951,50 +2190,72 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
do { \
res = rxh(rx); \
if (res != RX_CONTINUE) \
goto rxh_done; \
goto rxh_next; \
} while (0);
/*
* NB: the rxh_next label works even if we jump
* to it from here because then the list will
* be empty, which is a trivial check
*/
CALL_RXH(ieee80211_rx_h_passive_scan)
CALL_RXH(ieee80211_rx_h_check)
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)
ieee80211_rx_reorder_ampdu(rx, &reorder_release);
while ((skb = __skb_dequeue(&reorder_release))) {
/*
* all the other fields are valid across frames
* that belong to an aMPDU since they are on the
* same TID from the same station
*/
rx->skb = skb;
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
if (ieee80211_vif_is_mesh(&sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl)
CALL_RXH(ieee80211_rx_h_action)
CALL_RXH(ieee80211_rx_h_mgmt)
CALL_RXH(ieee80211_rx_h_data)
/* special treatment -- needs the queue */
res = ieee80211_rx_h_ctrl(rx, &reorder_release);
if (res != RX_CONTINUE)
goto rxh_next;
CALL_RXH(ieee80211_rx_h_action)
CALL_RXH(ieee80211_rx_h_mgmt)
#undef CALL_RXH
rxh_done:
switch (res) {
case RX_DROP_MONITOR:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
/* fall through */
case RX_CONTINUE:
ieee80211_rx_cooked_monitor(rx, rate);
break;
case RX_DROP_UNUSABLE:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
dev_kfree_skb(rx->skb);
break;
case RX_QUEUED:
I802_DEBUG_INC(sdata->local->rx_handlers_queued);
break;
rxh_next:
switch (res) {
case RX_DROP_MONITOR:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
/* fall through */
case RX_CONTINUE:
ieee80211_rx_cooked_monitor(rx, rate);
break;
case RX_DROP_UNUSABLE:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
dev_kfree_skb(rx->skb);
break;
case RX_QUEUED:
I802_DEBUG_INC(sdata->local->rx_handlers_queued);
break;
}
}
}
@ -2187,233 +2448,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
dev_kfree_skb(skb);
}
#define SEQ_MODULO 0x1000
#define SEQ_MASK 0xfff
static inline int seq_less(u16 sq1, u16 sq2)
{
return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
}
static inline u16 seq_inc(u16 sq)
{
return (sq + 1) & SEQ_MASK;
}
static inline u16 seq_sub(u16 sq1, u16 sq2)
{
return (sq1 - sq2) & SEQ_MASK;
}
static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
int index)
{
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate = NULL;
struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
struct ieee80211_rx_status *status;
if (!skb)
goto no_frame;
status = IEEE80211_SKB_RXCB(skb);
/* release the reordered frames to stack */
sband = hw->wiphy->bands[status->band];
if (!(status->flag & RX_FLAG_HT))
rate = &sband->bitrates[status->rate_idx];
__ieee80211_rx_handle_packet(hw, skb, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
no_frame:
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
}
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
u16 head_seq_num)
{
int index;
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
}
}
/*
* Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
* the skb was added to the buffer longer than this time ago, the earlier
* frames that have not yet been received are assumed to be lost and the skb
* can be released for processing. This may also release other skb's from the
* reorder buffer if there are no additional gaps between the frames.
*/
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
/*
* As this function belongs to the RX path it must be under
* rcu_read_lock protection. It returns false if the frame
* can be processed immediately, true if it was consumed.
*/
static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 sc = le16_to_cpu(hdr->seq_ctrl);
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
u16 head_seq_num, buf_size;
int index;
buf_size = tid_agg_rx->buf_size;
head_seq_num = tid_agg_rx->head_seq_num;
/* frame with out of date sequence number */
if (seq_less(mpdu_seq_num, head_seq_num)) {
dev_kfree_skb(skb);
return true;
}
/*
* If frame the sequence number exceeds our buffering window
* size release some previous frames to make room for this one.
*/
if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
/* release stored frames up to new head to stack */
ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
}
/* Now the new frame is always in the range of the reordering buffer */
index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
/* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) {
dev_kfree_skb(skb);
return true;
}
/*
* If the current MPDU is in the right order and nothing else
* is stored we can process it directly, no need to buffer it.
*/
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) {
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
return false;
}
/* put the frame in the reordering buffer */
tid_agg_rx->reorder_buf[index] = skb;
tid_agg_rx->reorder_time[index] = jiffies;
tid_agg_rx->stored_mpdu_num++;
/* release the buffer until next missing frame */
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
if (!tid_agg_rx->reorder_buf[index] &&
tid_agg_rx->stored_mpdu_num > 1) {
/*
* No buffers ready to be released, but check whether any
* frames in the reorder buffer have timed out.
*/
int j;
int skipped = 1;
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
j = (j + 1) % tid_agg_rx->buf_size) {
if (!tid_agg_rx->reorder_buf[j]) {
skipped++;
continue;
}
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
HT_RX_REORDER_BUF_TIMEOUT))
break;
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: release an RX reorder "
"frame due to timeout on earlier "
"frames\n",
wiphy_name(hw->wiphy));
#endif
ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
/*
* Increment the head seq# also for the skipped slots.
*/
tid_agg_rx->head_seq_num =
(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
skipped = 0;
}
} else while (tid_agg_rx->reorder_buf[index]) {
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
}
return true;
}
/*
* Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
* true if the MPDU was buffered, false if it should be processed.
*/
static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
struct sk_buff *skb)
{
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct sta_info *sta;
struct tid_ampdu_rx *tid_agg_rx;
u16 sc;
int tid;
if (!ieee80211_is_data_qos(hdr->frame_control))
return false;
/*
* filter the QoS data rx stream according to
* STA/TID and check if this STA/TID is on aggregation
*/
sta = sta_info_get(local, hdr->addr2);
if (!sta)
return false;
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
return false;
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
/* qos null data frames are excluded */
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
return false;
/* new, potentially un-ordered, ampdu frame - process it */
/* reset session timer */
if (tid_agg_rx->timeout)
mod_timer(&tid_agg_rx->session_timer,
TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
dev_kfree_skb(skb);
return true;
}
return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb);
}
/*
* This is the receive path handler. It is called by a low level driver when an
* 802.11 MPDU is received from the hardware.
@ -2495,20 +2529,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
return;
}
/*
* In theory, the block ack reordering should happen after duplicate
* removal (ieee80211_rx_h_check(), which is an RX handler). As such,
* the call to ieee80211_rx_reorder_ampdu() should really be moved to
* happen as a new RX handler between ieee80211_rx_h_check and
* ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for
* the time being, the call can be here since RX reorder buf processing
* will implicitly skip duplicates. We could, in theory at least,
* process frames that ieee80211_rx_h_passive_scan would drop (e.g.,
* frames from other than operational channel), but that should not
* happen in normal networks.
*/
if (!ieee80211_rx_reorder_ampdu(local, skb))
__ieee80211_rx_handle_packet(hw, skb, rate);
__ieee80211_rx_handle_packet(hw, skb, rate);
rcu_read_unlock();

View file

@ -148,6 +148,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
struct net_device *prev_dev = NULL;
struct sta_info *sta;
int retry_count = -1, i;
bool injected;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
/* the HW cannot have attempted that rate */
@ -297,6 +298,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
/* for now report the total retry_count */
rthdr->data_retries = retry_count;
/* Need to make a copy before skb->cb gets cleared */
injected = !!(info->flags & IEEE80211_TX_CTL_INJECTED);
/* XXX: is this sufficient for BPF? */
skb_set_mac_header(skb, 0);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@ -311,7 +315,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
continue;
if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
!injected &&
(type == IEEE80211_FTYPE_DATA))
continue;

View file

@ -45,6 +45,9 @@ DEFINE_MUTEX(cfg80211_mutex);
/* for debugfs */
static struct dentry *ieee80211_debugfs_dir;
/* for the cleanup, scan and event works */
struct workqueue_struct *cfg80211_wq;
/* requires cfg80211_mutex to be held! */
struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
{
@ -727,7 +730,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
break;
case NETDEV_DOWN:
dev_hold(dev);
schedule_work(&wdev->cleanup_work);
queue_work(cfg80211_wq, &wdev->cleanup_work);
break;
case NETDEV_UP:
/*
@ -845,8 +848,14 @@ static int __init cfg80211_init(void)
if (err)
goto out_fail_reg;
cfg80211_wq = create_singlethread_workqueue("cfg80211");
if (!cfg80211_wq)
goto out_fail_wq;
return 0;
out_fail_wq:
regulatory_exit();
out_fail_reg:
debugfs_remove(ieee80211_debugfs_dir);
out_fail_nl80211:
@ -868,5 +877,6 @@ static void cfg80211_exit(void)
wiphy_sysfs_exit();
regulatory_exit();
unregister_pernet_device(&cfg80211_pernet_ops);
destroy_workqueue(cfg80211_wq);
}
module_exit(cfg80211_exit);

View file

@ -91,6 +91,8 @@ bool wiphy_idx_valid(int wiphy_idx)
return (wiphy_idx >= 0);
}
extern struct workqueue_struct *cfg80211_wq;
extern struct mutex cfg80211_mutex;
extern struct list_head cfg80211_rdev_list;
extern int cfg80211_rdev_list_generation;

View file

@ -70,7 +70,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
schedule_work(&rdev->event_work);
queue_work(cfg80211_wq, &rdev->event_work);
}
EXPORT_SYMBOL(cfg80211_ibss_joined);

View file

@ -139,6 +139,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
[NL80211_ATTR_PID] = { .type = NLA_U32 },
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
[NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
.len = WLAN_PMKID_LEN },
};
/* policy for the attributes */
@ -450,6 +452,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
sizeof(u32) * dev->wiphy.n_cipher_suites,
dev->wiphy.cipher_suites);
NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
dev->wiphy.max_num_pmkids);
nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
if (!nl_modes)
goto nla_put_failure;
@ -561,6 +566,9 @@ 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);
CMD(set_pmksa, SET_PMKSA);
CMD(del_pmksa, DEL_PMKSA);
CMD(flush_pmksa, FLUSH_PMKSA);
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@ -4221,6 +4229,99 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
return err;
}
static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa) = NULL;
int err;
struct net_device *dev;
struct cfg80211_pmksa pmksa;
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
if (!info->attrs[NL80211_ATTR_PMKID])
return -EINVAL;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
err = -EOPNOTSUPP;
goto out;
}
switch (info->genlhdr->cmd) {
case NL80211_CMD_SET_PMKSA:
rdev_ops = rdev->ops->set_pmksa;
break;
case NL80211_CMD_DEL_PMKSA:
rdev_ops = rdev->ops->del_pmksa;
break;
default:
WARN_ON(1);
break;
}
if (!rdev_ops) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev_ops(&rdev->wiphy, dev, &pmksa);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err;
}
static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
err = -EOPNOTSUPP;
goto out;
}
if (!rdev->ops->flush_pmksa) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev->ops->flush_pmksa(&rdev->wiphy, dev);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err;
}
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@ -4465,6 +4566,25 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.dumpit = nl80211_dump_survey,
},
{
.cmd = NL80211_CMD_SET_PMKSA,
.doit = nl80211_setdel_pmksa,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_DEL_PMKSA,
.doit = nl80211_setdel_pmksa,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_FLUSH_PMKSA,
.doit = nl80211_flush_pmksa,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme",

View file

@ -1931,7 +1931,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
const struct ieee80211_freq_range *freq_range = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
printk(KERN_INFO " (start_freq - end_freq @ bandwidth), "
"(max_antenna_gain, max_eirp)\n");
for (i = 0; i < rd->n_reg_rules; i++) {
@ -1944,7 +1944,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
* in certain regions
*/
if (power_rule->max_antenna_gain)
printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), "
"(%d mBi, %d mBm)\n",
freq_range->start_freq_khz,
freq_range->end_freq_khz,
@ -1952,7 +1952,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
power_rule->max_antenna_gain,
power_rule->max_eirp);
else
printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), "
"(N/A, %d mBm)\n",
freq_range->start_freq_khz,
freq_range->end_freq_khz,

View file

@ -88,7 +88,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
request->aborted = aborted;
schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
}
EXPORT_SYMBOL(cfg80211_scan_done);

View file

@ -488,7 +488,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
schedule_work(&rdev->event_work);
queue_work(cfg80211_wq, &rdev->event_work);
}
EXPORT_SYMBOL(cfg80211_connect_result);
@ -583,7 +583,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
schedule_work(&rdev->event_work);
queue_work(cfg80211_wq, &rdev->event_work);
}
EXPORT_SYMBOL(cfg80211_roamed);
@ -681,7 +681,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
schedule_work(&rdev->event_work);
queue_work(cfg80211_wq, &rdev->event_work);
}
EXPORT_SYMBOL(cfg80211_disconnected);

View file

@ -1401,6 +1401,47 @@ int cfg80211_wext_giwessid(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid);
int cfg80211_wext_siwpmksa(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_pmksa cfg_pmksa;
struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa));
if (wdev->iftype != NL80211_IFTYPE_STATION)
return -EINVAL;
cfg_pmksa.bssid = pmksa->bssid.sa_data;
cfg_pmksa.pmkid = pmksa->pmkid;
switch (pmksa->cmd) {
case IW_PMKSA_ADD:
if (!rdev->ops->set_pmksa)
return -EOPNOTSUPP;
return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
case IW_PMKSA_REMOVE:
if (!rdev->ops->del_pmksa)
return -EOPNOTSUPP;
return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
case IW_PMKSA_FLUSH:
if (!rdev->ops->flush_pmksa)
return -EOPNOTSUPP;
return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
default:
return -EOPNOTSUPP;
}
}
static const iw_handler cfg80211_handlers[] = {
[IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
[IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,
@ -1433,6 +1474,7 @@ static const iw_handler cfg80211_handlers[] = {
[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,
[IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa,
};
const struct iw_handler_def cfg80211_wext_handler = {

View file

@ -802,7 +802,8 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
}
/* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) {
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
((err == 0) || (err == -EIWCOMMIT))) {
union iwreq_data *data = (union iwreq_data *) iwp;
if (descr->flags & IW_DESCR_FLAG_RESTRICT)