mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
8f56874bd7
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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>"
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
1141
drivers/net/wireless/libertas/mesh.c
Normal file
1141
drivers/net/wireless/libertas/mesh.c
Normal file
File diff suppressed because it is too large
Load Diff
78
drivers/net/wireless/libertas/mesh.h
Normal file
78
drivers/net/wireless/libertas/mesh.h
Normal 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
|
@ -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);
|
||||
}
|
@ -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));
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 |
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user