Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: drivers/net/wireless/iwlwifi/iwl-core.h
This commit is contained in:
commit
6373464288
92 changed files with 7263 additions and 2760 deletions
|
@ -144,7 +144,7 @@ usage should require reading the full document.
|
|||
this though and the recommendation to allow only a single
|
||||
interface in STA mode at first!
|
||||
</para>
|
||||
!Finclude/net/mac80211.h ieee80211_if_init_conf
|
||||
!Finclude/net/mac80211.h ieee80211_vif
|
||||
</chapter>
|
||||
|
||||
<chapter id="rx-tx">
|
||||
|
|
|
@ -1063,6 +1063,7 @@ struct ath5k_hw {
|
|||
u32 ah_cw_min;
|
||||
u32 ah_cw_max;
|
||||
u32 ah_limit_tx_retries;
|
||||
u8 ah_coverage_class;
|
||||
|
||||
/* Antenna Control */
|
||||
u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
|
||||
|
@ -1200,6 +1201,7 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
|
|||
|
||||
/* Protocol Control Unit Functions */
|
||||
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
|
||||
/* BSSID Functions */
|
||||
extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
|
||||
extern void ath5k_hw_set_associd(struct ath5k_hw *ah);
|
||||
|
@ -1231,6 +1233,10 @@ extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
|
|||
extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
|
||||
extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
|
||||
/* Clock rate related functions */
|
||||
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
|
||||
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
|
||||
unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah);
|
||||
/* Key table (WEP) functions */
|
||||
extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
|
||||
extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
|
||||
|
@ -1310,24 +1316,6 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
|
|||
* Functions used internaly
|
||||
*/
|
||||
|
||||
/*
|
||||
* Translate usec to hw clock units
|
||||
* TODO: Half/quarter rate
|
||||
*/
|
||||
static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
|
||||
{
|
||||
return turbo ? (usec * 80) : (usec * 40);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate hw clock units to usec
|
||||
* TODO: Half/quarter rate
|
||||
*/
|
||||
static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
|
||||
{
|
||||
return turbo ? (clock / 80) : (clock / 40);
|
||||
}
|
||||
|
||||
static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
|
||||
{
|
||||
return &ah->common;
|
||||
|
|
|
@ -254,6 +254,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
u32 changes);
|
||||
static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
|
||||
static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
|
||||
static void ath5k_set_coverage_class(struct ieee80211_hw *hw,
|
||||
u8 coverage_class);
|
||||
|
||||
static const struct ieee80211_ops ath5k_hw_ops = {
|
||||
.tx = ath5k_tx,
|
||||
|
@ -274,6 +276,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
|
|||
.bss_info_changed = ath5k_bss_info_changed,
|
||||
.sw_scan_start = ath5k_sw_scan_start,
|
||||
.sw_scan_complete = ath5k_sw_scan_complete,
|
||||
.set_coverage_class = ath5k_set_coverage_class,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -3262,3 +3265,22 @@ static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
|
|||
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
|
||||
AR5K_LED_ASSOC : AR5K_LED_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_set_coverage_class - Set IEEE 802.11 coverage class
|
||||
*
|
||||
* @hw: struct ieee80211_hw pointer
|
||||
* @coverage_class: IEEE 802.11 coverage class number
|
||||
*
|
||||
* Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
|
||||
* coverage class. The values are persistent, they are restored after device
|
||||
* reset.
|
||||
*/
|
||||
static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
|
||||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
|
||||
mutex_lock(&sc->lock);
|
||||
ath5k_hw_set_coverage_class(sc->ah, coverage_class);
|
||||
mutex_unlock(&sc->lock);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
|
|||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
int ret;
|
||||
u16 val;
|
||||
u32 cksum, offset;
|
||||
u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX;
|
||||
|
||||
/*
|
||||
* Read values from EEPROM and store them in the capability structure
|
||||
|
@ -116,12 +116,38 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
|
|||
* Validate the checksum of the EEPROM date. There are some
|
||||
* devices with invalid EEPROMs.
|
||||
*/
|
||||
for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val);
|
||||
if (val) {
|
||||
eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
|
||||
AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val);
|
||||
eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE;
|
||||
|
||||
/*
|
||||
* Fail safe check to prevent stupid loops due
|
||||
* to busted EEPROMs. XXX: This value is likely too
|
||||
* big still, waiting on a better value.
|
||||
*/
|
||||
if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) {
|
||||
ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: "
|
||||
"%d (0x%04x) max expected: %d (0x%04x)\n",
|
||||
eep_max, eep_max,
|
||||
3 * AR5K_EEPROM_INFO_MAX,
|
||||
3 * AR5K_EEPROM_INFO_MAX);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
for (cksum = 0, offset = 0; offset < eep_max; offset++) {
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
|
||||
cksum ^= val;
|
||||
}
|
||||
if (cksum != AR5K_EEPROM_INFO_CKSUM) {
|
||||
ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
|
||||
ATH5K_ERR(ah->ah_sc, "Invalid EEPROM "
|
||||
"checksum: 0x%04x eep_max: 0x%04x (%s)\n",
|
||||
cksum, eep_max,
|
||||
eep_max == AR5K_EEPROM_INFO_MAX ?
|
||||
"default size" : "custom size");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,14 @@
|
|||
#define AR5K_EEPROM_RFKILL_POLARITY_S 1
|
||||
|
||||
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
|
||||
|
||||
/* FLASH(EEPROM) Defines for AR531X chips */
|
||||
#define AR5K_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */
|
||||
#define AR5K_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */
|
||||
#define AR5K_EEPROM_SIZE_UPPER_MASK 0xfff0
|
||||
#define AR5K_EEPROM_SIZE_UPPER_SHIFT 4
|
||||
#define AR5K_EEPROM_SIZE_ENDLOC_SHIFT 12
|
||||
|
||||
#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */
|
||||
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
|
||||
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
|
||||
|
|
|
@ -187,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
|
|||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
|
||||
AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
|
||||
return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
|
||||
AR5K_TIME_OUT), AR5K_TIME_OUT_ACK));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
|
|||
int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
|
||||
ah->ah_turbo) <= timeout)
|
||||
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
|
||||
<= timeout)
|
||||
return -EINVAL;
|
||||
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
|
||||
ath5k_hw_htoclock(timeout, ah->ah_turbo));
|
||||
ath5k_hw_htoclock(ah, timeout));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -218,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
|
|||
unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
|
||||
AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
|
||||
return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
|
||||
AR5K_TIME_OUT), AR5K_TIME_OUT_CTS));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,16 +231,96 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
|
|||
int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
|
||||
ah->ah_turbo) <= timeout)
|
||||
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
|
||||
<= timeout)
|
||||
return -EINVAL;
|
||||
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
|
||||
ath5k_hw_htoclock(timeout, ah->ah_turbo));
|
||||
ath5k_hw_htoclock(ah, timeout));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_htoclock - Translate usec to hw clock units
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @usec: value in microseconds
|
||||
*/
|
||||
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
|
||||
{
|
||||
return usec * ath5k_hw_get_clockrate(ah);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_clocktoh - Translate hw clock units to usec
|
||||
* @clock: value in hw clock units
|
||||
*/
|
||||
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
|
||||
{
|
||||
return clock / ath5k_hw_get_clockrate(ah);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_get_clockrate - Get the clock rate for current mode
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ieee80211_channel *channel = ah->ah_current_channel;
|
||||
int clock;
|
||||
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
clock = 40; /* 802.11a */
|
||||
else if (channel->hw_value & CHANNEL_CCK)
|
||||
clock = 22; /* 802.11b */
|
||||
else
|
||||
clock = 44; /* 802.11g */
|
||||
|
||||
/* Clock rate in turbo modes is twice the normal rate */
|
||||
if (channel->hw_value & CHANNEL_TURBO)
|
||||
clock *= 2;
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_get_default_slottime - Get the default slot time for current mode
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ieee80211_channel *channel = ah->ah_current_channel;
|
||||
|
||||
if (channel->hw_value & CHANNEL_TURBO)
|
||||
return 6; /* both turbo modes */
|
||||
|
||||
if (channel->hw_value & CHANNEL_CCK)
|
||||
return 20; /* 802.11b */
|
||||
|
||||
return 9; /* 802.11 a/g */
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_get_default_sifs - Get the default SIFS for current mode
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ieee80211_channel *channel = ah->ah_current_channel;
|
||||
|
||||
if (channel->hw_value & CHANNEL_TURBO)
|
||||
return 8; /* both turbo modes */
|
||||
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
return 16; /* 802.11a */
|
||||
|
||||
return 10; /* 802.11 b/g */
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_lladdr - Set station id
|
||||
*
|
||||
|
@ -1050,3 +1130,24 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @coverage_class: IEEE 802.11 coverage class number
|
||||
*
|
||||
* Sets slot time, ACK timeout and CTS timeout for given coverage class.
|
||||
*/
|
||||
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
|
||||
{
|
||||
/* As defined by IEEE 802.11-2007 17.3.8.6 */
|
||||
int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
|
||||
int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
|
||||
int cts_timeout = ack_timeout;
|
||||
|
||||
ath5k_hw_set_slot_time(ah, slot_time);
|
||||
ath5k_hw_set_ack_timeout(ah, ack_timeout);
|
||||
ath5k_hw_set_cts_timeout(ah, cts_timeout);
|
||||
|
||||
ah->ah_coverage_class = coverage_class;
|
||||
}
|
||||
|
|
|
@ -520,12 +520,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
*/
|
||||
unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
|
||||
{
|
||||
unsigned int slot_time_clock;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
|
||||
AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
|
||||
slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME);
|
||||
else
|
||||
return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
|
||||
slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT);
|
||||
|
||||
return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -533,15 +537,17 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
|
|||
*/
|
||||
int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
|
||||
{
|
||||
u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
|
||||
|
||||
if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
|
||||
ah->ah_turbo), AR5K_SLOT_TIME);
|
||||
ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
|
||||
else
|
||||
ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
|
||||
ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -60,12 +60,11 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
|
|||
!(channel->hw_value & CHANNEL_OFDM));
|
||||
|
||||
/* Get coefficient
|
||||
* ALGO: coef = (5 * clock * carrier_freq) / 2)
|
||||
* ALGO: coef = (5 * clock / carrier_freq) / 2
|
||||
* we scale coef by shifting clock value by 24 for
|
||||
* better precision since we use integers */
|
||||
/* TODO: Half/quarter rate */
|
||||
clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
|
||||
|
||||
clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40;
|
||||
coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
|
||||
|
||||
/* Get exponent
|
||||
|
@ -1317,6 +1316,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
|||
/* Restore antenna mode */
|
||||
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
|
||||
|
||||
/* Restore slot time and ACK timeouts */
|
||||
if (ah->ah_coverage_class > 0)
|
||||
ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
|
||||
|
||||
/*
|
||||
* Configure QCUs/DCUs
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,7 @@ config ATH9K
|
|||
|
||||
config ATH9K_DEBUGFS
|
||||
bool "Atheros ath9k debugging"
|
||||
depends on ATH9K
|
||||
depends on ATH9K && DEBUG_FS
|
||||
---help---
|
||||
Say Y, if you need access to ath9k's statistics for
|
||||
interrupts, rate control, etc.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
ath9k-y += beacon.o \
|
||||
gpio.o \
|
||||
init.o \
|
||||
main.o \
|
||||
recv.o \
|
||||
xmit.o \
|
||||
|
|
|
@ -121,16 +121,19 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
|||
sc->mem = mem;
|
||||
sc->irq = irq;
|
||||
|
||||
ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize device\n");
|
||||
goto err_free_hw;
|
||||
}
|
||||
/* Will be cleared in ath9k_start() */
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
|
||||
ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request_irq failed\n");
|
||||
goto err_detach;
|
||||
goto err_free_hw;
|
||||
}
|
||||
|
||||
ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize device\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
ah = sc->sc_ah;
|
||||
|
@ -143,8 +146,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_detach:
|
||||
ath_detach(sc);
|
||||
err_irq:
|
||||
free_irq(irq, sc);
|
||||
err_free_hw:
|
||||
ieee80211_free_hw(hw);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
@ -161,8 +164,12 @@ static int ath_ahb_remove(struct platform_device *pdev)
|
|||
if (hw) {
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
ath_cleanup(sc);
|
||||
ath9k_deinit_device(sc);
|
||||
free_irq(sc->irq, sc);
|
||||
ieee80211_free_hw(sc->hw);
|
||||
ath_bus_cleanup(common);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ struct ath_node;
|
|||
|
||||
/* Macro to expand scalars to 64-bit objects */
|
||||
|
||||
#define ito64(x) (sizeof(x) == 8) ? \
|
||||
#define ito64(x) (sizeof(x) == 1) ? \
|
||||
(((unsigned long long int)(x)) & (0xff)) : \
|
||||
(sizeof(x) == 16) ? \
|
||||
(sizeof(x) == 2) ? \
|
||||
(((unsigned long long int)(x)) & 0xffff) : \
|
||||
((sizeof(x) == 32) ? \
|
||||
((sizeof(x) == 4) ? \
|
||||
(((unsigned long long int)(x)) & 0xffffffff) : \
|
||||
(unsigned long long int)(x))
|
||||
|
||||
|
@ -341,6 +341,12 @@ int ath_beaconq_config(struct ath_softc *sc);
|
|||
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
|
||||
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
|
||||
|
||||
void ath_ani_calibrate(unsigned long data);
|
||||
|
||||
/**********/
|
||||
/* BTCOEX */
|
||||
/**********/
|
||||
|
||||
/* Defines the BT AR_BT_COEX_WGHT used */
|
||||
enum ath_stomp_type {
|
||||
ATH_BTCOEX_NO_STOMP,
|
||||
|
@ -361,6 +367,10 @@ struct ath_btcoex {
|
|||
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
|
||||
};
|
||||
|
||||
int ath_init_btcoex_timer(struct ath_softc *sc);
|
||||
void ath9k_btcoex_timer_resume(struct ath_softc *sc);
|
||||
void ath9k_btcoex_timer_pause(struct ath_softc *sc);
|
||||
|
||||
/********************/
|
||||
/* LED Control */
|
||||
/********************/
|
||||
|
@ -385,6 +395,9 @@ struct ath_led {
|
|||
bool registered;
|
||||
};
|
||||
|
||||
void ath_init_leds(struct ath_softc *sc);
|
||||
void ath_deinit_leds(struct ath_softc *sc);
|
||||
|
||||
/********************/
|
||||
/* Main driver core */
|
||||
/********************/
|
||||
|
@ -403,26 +416,28 @@ struct ath_led {
|
|||
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
||||
#define ATH_RATE_DUMMY_MARKER 0
|
||||
|
||||
#define SC_OP_INVALID BIT(0)
|
||||
#define SC_OP_BEACONS BIT(1)
|
||||
#define SC_OP_RXAGGR BIT(2)
|
||||
#define SC_OP_TXAGGR BIT(3)
|
||||
#define SC_OP_FULL_RESET BIT(4)
|
||||
#define SC_OP_PREAMBLE_SHORT BIT(5)
|
||||
#define SC_OP_PROTECT_ENABLE BIT(6)
|
||||
#define SC_OP_RXFLUSH BIT(7)
|
||||
#define SC_OP_LED_ASSOCIATED BIT(8)
|
||||
#define SC_OP_WAIT_FOR_BEACON BIT(12)
|
||||
#define SC_OP_LED_ON BIT(13)
|
||||
#define SC_OP_SCANNING BIT(14)
|
||||
#define SC_OP_TSF_RESET BIT(15)
|
||||
#define SC_OP_WAIT_FOR_CAB BIT(16)
|
||||
#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
|
||||
#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)
|
||||
#define SC_OP_INVALID BIT(0)
|
||||
#define SC_OP_BEACONS BIT(1)
|
||||
#define SC_OP_RXAGGR BIT(2)
|
||||
#define SC_OP_TXAGGR BIT(3)
|
||||
#define SC_OP_FULL_RESET BIT(4)
|
||||
#define SC_OP_PREAMBLE_SHORT BIT(5)
|
||||
#define SC_OP_PROTECT_ENABLE BIT(6)
|
||||
#define SC_OP_RXFLUSH BIT(7)
|
||||
#define SC_OP_LED_ASSOCIATED BIT(8)
|
||||
#define SC_OP_LED_ON BIT(9)
|
||||
#define SC_OP_SCANNING BIT(10)
|
||||
#define SC_OP_TSF_RESET BIT(11)
|
||||
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
|
||||
|
||||
/* Powersave flags */
|
||||
#define PS_WAIT_FOR_BEACON BIT(0)
|
||||
#define PS_WAIT_FOR_CAB BIT(1)
|
||||
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
|
||||
#define PS_WAIT_FOR_TX_ACK BIT(3)
|
||||
#define PS_BEACON_SYNC BIT(4)
|
||||
#define PS_NULLFUNC_COMPLETED BIT(5)
|
||||
#define PS_ENABLED BIT(6)
|
||||
|
||||
struct ath_wiphy;
|
||||
struct ath_rate_table;
|
||||
|
@ -458,6 +473,7 @@ struct ath_softc {
|
|||
|
||||
u32 intrstatus;
|
||||
u32 sc_flags; /* SC_OP_* */
|
||||
u16 ps_flags; /* PS_* */
|
||||
u16 curtxpow;
|
||||
u8 nbcnvifs;
|
||||
u16 nvifs;
|
||||
|
@ -508,6 +524,7 @@ struct ath_wiphy {
|
|||
int chan_is_ht;
|
||||
};
|
||||
|
||||
void ath9k_tasklet(unsigned long data);
|
||||
int ath_reset(struct ath_softc *sc, bool retry_tx);
|
||||
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
|
||||
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
|
||||
|
@ -524,15 +541,15 @@ static inline void ath_bus_cleanup(struct ath_common *common)
|
|||
}
|
||||
|
||||
extern struct ieee80211_ops ath9k_ops;
|
||||
extern int modparam_nohwcrypt;
|
||||
|
||||
irqreturn_t ath_isr(int irq, void *dev);
|
||||
void ath_cleanup(struct ath_softc *sc);
|
||||
int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
const struct ath_bus_ops *bus_ops);
|
||||
void ath_detach(struct ath_softc *sc);
|
||||
void ath9k_deinit_device(struct ath_softc *sc);
|
||||
const char *ath_mac_bb_name(u32 mac_bb_version);
|
||||
const char *ath_rf_name(u16 rf_version);
|
||||
void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
struct ath9k_channel *ichan);
|
||||
void ath_update_chainmask(struct ath_softc *sc, int is_ht);
|
||||
|
@ -541,6 +558,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
|
||||
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
int ath_pci_init(void);
|
||||
|
@ -582,4 +600,8 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
|
|||
void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
|
||||
|
||||
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
|
||||
|
||||
void ath_start_rfkill_poll(struct ath_softc *sc);
|
||||
extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
|
||||
|
||||
#endif /* ATH9K_H */
|
||||
|
|
|
@ -480,7 +480,8 @@ void ath_beacon_tasklet(unsigned long data)
|
|||
sc->beacon.updateslot = COMMIT; /* commit next beacon */
|
||||
sc->beacon.slotupdate = slot;
|
||||
} else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
|
||||
ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
|
||||
ah->slottime = sc->beacon.slottime;
|
||||
ath9k_hw_init_global_settings(ah);
|
||||
sc->beacon.updateslot = OK;
|
||||
}
|
||||
if (bfaddr != 0) {
|
||||
|
|
|
@ -580,6 +580,116 @@ static const struct file_operations fops_xmit = {
|
|||
.owner = THIS_MODULE
|
||||
};
|
||||
|
||||
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
#define PHY_ERR(s, p) \
|
||||
len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
|
||||
sc->debug.stats.rxstats.phy_err_stats[p]);
|
||||
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 1152;
|
||||
ssize_t retval = 0;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "CRC ERR",
|
||||
sc->debug.stats.rxstats.crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "DECRYPT CRC ERR",
|
||||
sc->debug.stats.rxstats.decrypt_crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "PHY ERR",
|
||||
sc->debug.stats.rxstats.phy_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "MIC ERR",
|
||||
sc->debug.stats.rxstats.mic_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "PRE-DELIM CRC ERR",
|
||||
sc->debug.stats.rxstats.pre_delim_crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "POST-DELIM CRC ERR",
|
||||
sc->debug.stats.rxstats.post_delim_crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%18s : %10u\n", "DECRYPT BUSY ERR",
|
||||
sc->debug.stats.rxstats.decrypt_busy_err);
|
||||
|
||||
PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
|
||||
PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
|
||||
PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
|
||||
PHY_ERR("RATE", ATH9K_PHYERR_RATE);
|
||||
PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
|
||||
PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
|
||||
PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
|
||||
PHY_ERR("TOR", ATH9K_PHYERR_TOR);
|
||||
PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
|
||||
PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
|
||||
PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
|
||||
PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
|
||||
PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
|
||||
PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
|
||||
PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
|
||||
PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
|
||||
PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
|
||||
PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
|
||||
PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
|
||||
PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
|
||||
PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
|
||||
PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
|
||||
PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
|
||||
PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
|
||||
PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
|
||||
PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
|
||||
#undef PHY_ERR
|
||||
}
|
||||
|
||||
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf)
|
||||
{
|
||||
#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
|
||||
#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
|
||||
|
||||
struct ath_desc *ds = bf->bf_desc;
|
||||
u32 phyerr;
|
||||
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
|
||||
RX_STAT_INC(crc_err);
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT)
|
||||
RX_STAT_INC(decrypt_crc_err);
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC)
|
||||
RX_STAT_INC(mic_err);
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE)
|
||||
RX_STAT_INC(pre_delim_crc_err);
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST)
|
||||
RX_STAT_INC(post_delim_crc_err);
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY)
|
||||
RX_STAT_INC(decrypt_busy_err);
|
||||
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
|
||||
RX_STAT_INC(phy_err);
|
||||
phyerr = ds->ds_rxstat.rs_phyerr & 0x24;
|
||||
RX_PHY_ERR_INC(phyerr);
|
||||
}
|
||||
|
||||
#undef RX_STAT_INC
|
||||
#undef RX_PHY_ERR_INC
|
||||
}
|
||||
|
||||
static const struct file_operations fops_recv = {
|
||||
.read = read_file_recv,
|
||||
.open = ath9k_debugfs_open,
|
||||
.owner = THIS_MODULE
|
||||
};
|
||||
|
||||
int ath9k_init_debug(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
@ -632,6 +742,13 @@ int ath9k_init_debug(struct ath_hw *ah)
|
|||
if (!sc->debug.debugfs_xmit)
|
||||
goto err;
|
||||
|
||||
sc->debug.debugfs_recv = debugfs_create_file("recv",
|
||||
S_IRUSR,
|
||||
sc->debug.debugfs_phy,
|
||||
sc, &fops_recv);
|
||||
if (!sc->debug.debugfs_recv)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
ath9k_exit_debug(ah);
|
||||
|
@ -643,6 +760,7 @@ void ath9k_exit_debug(struct ath_hw *ah)
|
|||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
|
||||
debugfs_remove(sc->debug.debugfs_recv);
|
||||
debugfs_remove(sc->debug.debugfs_xmit);
|
||||
debugfs_remove(sc->debug.debugfs_wiphy);
|
||||
debugfs_remove(sc->debug.debugfs_rcstat);
|
||||
|
|
|
@ -116,10 +116,35 @@ struct ath_tx_stats {
|
|||
u32 delim_underrun;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ath_rx_stats - RX Statistics
|
||||
* @crc_err: No. of frames with incorrect CRC value
|
||||
* @decrypt_crc_err: No. of frames whose CRC check failed after
|
||||
decryption process completed
|
||||
* @phy_err: No. of frames whose reception failed because the PHY
|
||||
encountered an error
|
||||
* @mic_err: No. of frames with incorrect TKIP MIC verification failure
|
||||
* @pre_delim_crc_err: Pre-Frame delimiter CRC error detections
|
||||
* @post_delim_crc_err: Post-Frame delimiter CRC error detections
|
||||
* @decrypt_busy_err: Decryption interruptions counter
|
||||
* @phy_err_stats: Individual PHY error statistics
|
||||
*/
|
||||
struct ath_rx_stats {
|
||||
u32 crc_err;
|
||||
u32 decrypt_crc_err;
|
||||
u32 phy_err;
|
||||
u32 mic_err;
|
||||
u32 pre_delim_crc_err;
|
||||
u32 post_delim_crc_err;
|
||||
u32 decrypt_busy_err;
|
||||
u32 phy_err_stats[ATH9K_PHYERR_MAX];
|
||||
};
|
||||
|
||||
struct ath_stats {
|
||||
struct ath_interrupt_stats istats;
|
||||
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
|
||||
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
|
||||
struct ath_rx_stats rxstats;
|
||||
};
|
||||
|
||||
struct ath9k_debug {
|
||||
|
@ -130,6 +155,7 @@ struct ath9k_debug {
|
|||
struct dentry *debugfs_rcstat;
|
||||
struct dentry *debugfs_wiphy;
|
||||
struct dentry *debugfs_xmit;
|
||||
struct dentry *debugfs_recv;
|
||||
struct ath_stats stats;
|
||||
};
|
||||
|
||||
|
@ -142,6 +168,7 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
|
|||
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_rx(struct ath_softc *sc, struct ath_buf *bf);
|
||||
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
||||
int xretries, int retries, u8 per);
|
||||
|
||||
|
@ -181,6 +208,11 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc,
|
|||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_rx(struct ath_softc *sc,
|
||||
struct ath_buf *bf)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
||||
int xretries, int retries, u8 per)
|
||||
{
|
||||
|
|
428
drivers/net/wireless/ath/ath9k/gpio.c
Normal file
428
drivers/net/wireless/ath/ath9k/gpio.c
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2009 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
/********************************/
|
||||
/* LED functions */
|
||||
/********************************/
|
||||
|
||||
static void ath_led_blink_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
ath_led_blink_work.work);
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
|
||||
return;
|
||||
|
||||
if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
|
||||
(sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
|
||||
else
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
(sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw,
|
||||
&sc->ath_led_blink_work,
|
||||
(sc->sc_flags & SC_OP_LED_ON) ?
|
||||
msecs_to_jiffies(sc->led_off_duration) :
|
||||
msecs_to_jiffies(sc->led_on_duration));
|
||||
|
||||
sc->led_on_duration = sc->led_on_cnt ?
|
||||
max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
|
||||
ATH_LED_ON_DURATION_IDLE;
|
||||
sc->led_off_duration = sc->led_off_cnt ?
|
||||
max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
|
||||
ATH_LED_OFF_DURATION_IDLE;
|
||||
sc->led_on_cnt = sc->led_off_cnt = 0;
|
||||
if (sc->sc_flags & SC_OP_LED_ON)
|
||||
sc->sc_flags &= ~SC_OP_LED_ON;
|
||||
else
|
||||
sc->sc_flags |= SC_OP_LED_ON;
|
||||
}
|
||||
|
||||
static void ath_led_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
|
||||
struct ath_softc *sc = led->sc;
|
||||
|
||||
switch (brightness) {
|
||||
case LED_OFF:
|
||||
if (led->led_type == ATH_LED_ASSOC ||
|
||||
led->led_type == ATH_LED_RADIO) {
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
(led->led_type == ATH_LED_RADIO));
|
||||
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
|
||||
if (led->led_type == ATH_LED_RADIO)
|
||||
sc->sc_flags &= ~SC_OP_LED_ON;
|
||||
} else {
|
||||
sc->led_off_cnt++;
|
||||
}
|
||||
break;
|
||||
case LED_FULL:
|
||||
if (led->led_type == ATH_LED_ASSOC) {
|
||||
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
|
||||
ieee80211_queue_delayed_work(sc->hw,
|
||||
&sc->ath_led_blink_work, 0);
|
||||
} else if (led->led_type == ATH_LED_RADIO) {
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
|
||||
sc->sc_flags |= SC_OP_LED_ON;
|
||||
} else {
|
||||
sc->led_on_cnt++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
|
||||
char *trigger)
|
||||
{
|
||||
int ret;
|
||||
|
||||
led->sc = sc;
|
||||
led->led_cdev.name = led->name;
|
||||
led->led_cdev.default_trigger = trigger;
|
||||
led->led_cdev.brightness_set = ath_led_brightness;
|
||||
|
||||
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
|
||||
if (ret)
|
||||
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
|
||||
"Failed to register led:%s", led->name);
|
||||
else
|
||||
led->registered = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath_unregister_led(struct ath_led *led)
|
||||
{
|
||||
if (led->registered) {
|
||||
led_classdev_unregister(&led->led_cdev);
|
||||
led->registered = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ath_deinit_leds(struct ath_softc *sc)
|
||||
{
|
||||
ath_unregister_led(&sc->assoc_led);
|
||||
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
|
||||
ath_unregister_led(&sc->tx_led);
|
||||
ath_unregister_led(&sc->rx_led);
|
||||
ath_unregister_led(&sc->radio_led);
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
}
|
||||
|
||||
void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
char *trigger;
|
||||
int ret;
|
||||
|
||||
if (AR_SREV_9287(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9287;
|
||||
else
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
|
||||
|
||||
/* Configure gpio 1 for output */
|
||||
ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
|
||||
INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
|
||||
|
||||
trigger = ieee80211_get_radio_led_name(sc->hw);
|
||||
snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
|
||||
"ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->radio_led, trigger);
|
||||
sc->radio_led.led_type = ATH_LED_RADIO;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
trigger = ieee80211_get_assoc_led_name(sc->hw);
|
||||
snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
|
||||
"ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->assoc_led, trigger);
|
||||
sc->assoc_led.led_type = ATH_LED_ASSOC;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
trigger = ieee80211_get_tx_led_name(sc->hw);
|
||||
snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
|
||||
"ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->tx_led, trigger);
|
||||
sc->tx_led.led_type = ATH_LED_TX;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
trigger = ieee80211_get_rx_led_name(sc->hw);
|
||||
snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
|
||||
"ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->rx_led, trigger);
|
||||
sc->rx_led.led_type = ATH_LED_RX;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
cancel_delayed_work_sync(&sc->ath_led_blink_work);
|
||||
ath_deinit_leds(sc);
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/* Rfkill */
|
||||
/*******************/
|
||||
|
||||
static bool ath_is_rfkill_set(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
|
||||
ah->rfkill_polarity;
|
||||
}
|
||||
|
||||
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
bool blocked = !!ath_is_rfkill_set(sc);
|
||||
|
||||
wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
|
||||
}
|
||||
|
||||
void ath_start_rfkill_poll(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
wiphy_rfkill_start_polling(sc->hw->wiphy);
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* BTCOEX */
|
||||
/******************/
|
||||
|
||||
/*
|
||||
* Detects if there is any priority bt traffic
|
||||
*/
|
||||
static void ath_detect_bt_priority(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
|
||||
btcoex->bt_priority_cnt++;
|
||||
|
||||
if (time_after(jiffies, btcoex->bt_priority_time +
|
||||
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
|
||||
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
|
||||
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
|
||||
"BT priority traffic detected");
|
||||
sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
|
||||
} else {
|
||||
sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
|
||||
}
|
||||
|
||||
btcoex->bt_priority_cnt = 0;
|
||||
btcoex->bt_priority_time = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures appropriate weight based on stomp type.
|
||||
*/
|
||||
static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
|
||||
enum ath_stomp_type stomp_type)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
switch (stomp_type) {
|
||||
case ATH_BTCOEX_STOMP_ALL:
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_ALL_WLAN_WGHT);
|
||||
break;
|
||||
case ATH_BTCOEX_STOMP_LOW:
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_LOW_WLAN_WGHT);
|
||||
break;
|
||||
case ATH_BTCOEX_STOMP_NONE:
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_NONE_WLAN_WGHT);
|
||||
break;
|
||||
default:
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
||||
"Invalid Stomptype\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ath9k_hw_btcoex_enable(ah);
|
||||
}
|
||||
|
||||
static void ath9k_gen_timer_start(struct ath_hw *ah,
|
||||
struct ath_gen_timer *timer,
|
||||
u32 timer_next,
|
||||
u32 timer_period)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
|
||||
ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
|
||||
|
||||
if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
sc->imask |= ATH9K_INT_GENTIMER;
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
|
||||
|
||||
ath9k_hw_gen_timer_stop(ah, timer);
|
||||
|
||||
/* if no timer is enabled, turn off interrupt mask */
|
||||
if (timer_table->timer_mask.val == 0) {
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
sc->imask &= ~ATH9K_INT_GENTIMER;
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the master bt coex timer which runs for every
|
||||
* 45ms, bt traffic will be given priority during 55% of this
|
||||
* period while wlan gets remaining 45%
|
||||
*/
|
||||
static void ath_btcoex_period_timer(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *) data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
|
||||
ath_detect_bt_priority(sc);
|
||||
|
||||
spin_lock_bh(&btcoex->btcoex_lock);
|
||||
|
||||
ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
|
||||
|
||||
spin_unlock_bh(&btcoex->btcoex_lock);
|
||||
|
||||
if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
|
||||
if (btcoex->hw_timer_enabled)
|
||||
ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
|
||||
|
||||
ath9k_gen_timer_start(ah,
|
||||
btcoex->no_stomp_timer,
|
||||
(ath9k_hw_gettsf32(ah) +
|
||||
btcoex->btcoex_no_stomp),
|
||||
btcoex->btcoex_no_stomp * 10);
|
||||
btcoex->hw_timer_enabled = true;
|
||||
}
|
||||
|
||||
mod_timer(&btcoex->period_timer, jiffies +
|
||||
msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic tsf based hw timer which configures weight
|
||||
* registers to time slice between wlan and bt traffic
|
||||
*/
|
||||
static void ath_btcoex_no_stomp_timer(void *arg)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)arg;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
||||
"no stomp timer running \n");
|
||||
|
||||
spin_lock_bh(&btcoex->btcoex_lock);
|
||||
|
||||
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
|
||||
ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
|
||||
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
|
||||
ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
|
||||
|
||||
spin_unlock_bh(&btcoex->btcoex_lock);
|
||||
}
|
||||
|
||||
int ath_init_btcoex_timer(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
|
||||
btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
|
||||
btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
|
||||
btcoex->btcoex_period / 100;
|
||||
|
||||
setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
|
||||
(unsigned long) sc);
|
||||
|
||||
spin_lock_init(&btcoex->btcoex_lock);
|
||||
|
||||
btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
|
||||
ath_btcoex_no_stomp_timer,
|
||||
ath_btcoex_no_stomp_timer,
|
||||
(void *) sc, AR_FIRST_NDP_TIMER);
|
||||
|
||||
if (!btcoex->no_stomp_timer)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (Re)start btcoex timers
|
||||
*/
|
||||
void ath9k_btcoex_timer_resume(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
||||
"Starting btcoex timers");
|
||||
|
||||
/* make sure duty cycle timer is also stopped when resuming */
|
||||
if (btcoex->hw_timer_enabled)
|
||||
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
|
||||
|
||||
btcoex->bt_priority_cnt = 0;
|
||||
btcoex->bt_priority_time = jiffies;
|
||||
sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
|
||||
|
||||
mod_timer(&btcoex->period_timer, jiffies);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pause btcoex timer and bt duty cycle timer
|
||||
*/
|
||||
void ath9k_btcoex_timer_pause(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
del_timer_sync(&btcoex->period_timer);
|
||||
|
||||
if (btcoex->hw_timer_enabled)
|
||||
ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
|
||||
|
||||
btcoex->hw_timer_enabled = false;
|
||||
}
|
|
@ -52,28 +52,6 @@ module_exit(ath9k_exit);
|
|||
/* Helper Functions */
|
||||
/********************/
|
||||
|
||||
static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
||||
|
||||
if (!ah->curchan) /* should really check for CCK instead */
|
||||
return clks / ATH9K_CLOCK_RATE_CCK;
|
||||
if (conf->channel->band == IEEE80211_BAND_2GHZ)
|
||||
return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM;
|
||||
|
||||
return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM;
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
||||
|
||||
if (conf_is_ht40(conf))
|
||||
return ath9k_hw_mac_usec(ah, clks) / 2;
|
||||
else
|
||||
return ath9k_hw_mac_usec(ah, clks);
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
||||
|
@ -413,8 +391,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
|||
ah->beacon_interval = 100;
|
||||
ah->enable_32kHz_clock = DONT_USE_32KHZ;
|
||||
ah->slottime = (u32) -1;
|
||||
ah->acktimeout = (u32) -1;
|
||||
ah->ctstimeout = (u32) -1;
|
||||
ah->globaltxtimeout = (u32) -1;
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
}
|
||||
|
@ -1180,34 +1156,25 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
|
|||
}
|
||||
}
|
||||
|
||||
static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
|
||||
static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
|
||||
{
|
||||
if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
|
||||
"bad ack timeout %u\n", us);
|
||||
ah->acktimeout = (u32) -1;
|
||||
return false;
|
||||
} else {
|
||||
REG_RMW_FIELD(ah, AR_TIME_OUT,
|
||||
AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
|
||||
ah->acktimeout = us;
|
||||
return true;
|
||||
}
|
||||
u32 val = ath9k_hw_mac_to_clks(ah, us);
|
||||
val = min(val, (u32) 0xFFFF);
|
||||
REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
|
||||
}
|
||||
|
||||
static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
|
||||
static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
|
||||
{
|
||||
if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
|
||||
"bad cts timeout %u\n", us);
|
||||
ah->ctstimeout = (u32) -1;
|
||||
return false;
|
||||
} else {
|
||||
REG_RMW_FIELD(ah, AR_TIME_OUT,
|
||||
AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
|
||||
ah->ctstimeout = us;
|
||||
return true;
|
||||
}
|
||||
u32 val = ath9k_hw_mac_to_clks(ah, us);
|
||||
val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
|
||||
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
|
||||
}
|
||||
|
||||
static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
|
||||
{
|
||||
u32 val = ath9k_hw_mac_to_clks(ah, us);
|
||||
val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
|
||||
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val);
|
||||
}
|
||||
|
||||
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
|
||||
|
@ -1224,25 +1191,37 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
|
|||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_init_user_settings(struct ath_hw *ah)
|
||||
void ath9k_hw_init_global_settings(struct ath_hw *ah)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
||||
int acktimeout;
|
||||
int slottime;
|
||||
int sifstime;
|
||||
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
|
||||
ah->misc_mode);
|
||||
|
||||
if (ah->misc_mode != 0)
|
||||
REG_WRITE(ah, AR_PCU_MISC,
|
||||
REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
|
||||
if (ah->slottime != (u32) -1)
|
||||
ath9k_hw_setslottime(ah, ah->slottime);
|
||||
if (ah->acktimeout != (u32) -1)
|
||||
ath9k_hw_set_ack_timeout(ah, ah->acktimeout);
|
||||
if (ah->ctstimeout != (u32) -1)
|
||||
ath9k_hw_set_cts_timeout(ah, ah->ctstimeout);
|
||||
|
||||
if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
|
||||
sifstime = 16;
|
||||
else
|
||||
sifstime = 10;
|
||||
|
||||
/* As defined by IEEE 802.11-2007 17.3.8.6 */
|
||||
slottime = ah->slottime + 3 * ah->coverage_class;
|
||||
acktimeout = slottime + sifstime;
|
||||
ath9k_hw_setslottime(ah, slottime);
|
||||
ath9k_hw_set_ack_timeout(ah, acktimeout);
|
||||
ath9k_hw_set_cts_timeout(ah, acktimeout);
|
||||
if (ah->globaltxtimeout != (u32) -1)
|
||||
ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_init_global_settings);
|
||||
|
||||
void ath9k_hw_detach(struct ath_hw *ah)
|
||||
void ath9k_hw_deinit(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
|
@ -1260,7 +1239,7 @@ void ath9k_hw_detach(struct ath_hw *ah)
|
|||
kfree(ah);
|
||||
ah = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_detach);
|
||||
EXPORT_SYMBOL(ath9k_hw_deinit);
|
||||
|
||||
/*******/
|
||||
/* INI */
|
||||
|
@ -2061,7 +2040,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
ath9k_enable_rfkill(ah);
|
||||
|
||||
ath9k_hw_init_user_settings(ah);
|
||||
ath9k_hw_init_global_settings(ah);
|
||||
|
||||
if (AR_SREV_9287_12_OR_LATER(ah)) {
|
||||
REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
|
||||
|
@ -3658,21 +3637,6 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
|
|||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_extend_tsf);
|
||||
|
||||
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
|
||||
{
|
||||
if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
|
||||
"bad slot time %u\n", us);
|
||||
ah->slottime = (u32) -1;
|
||||
return false;
|
||||
} else {
|
||||
REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
|
||||
ah->slottime = us;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_setslottime);
|
||||
|
||||
void ath9k_hw_set11nmac2040(struct ath_hw *ah)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
||||
|
|
|
@ -551,10 +551,9 @@ struct ath_hw {
|
|||
u32 *bank6Temp;
|
||||
|
||||
int16_t txpower_indexoffset;
|
||||
int coverage_class;
|
||||
u32 beacon_interval;
|
||||
u32 slottime;
|
||||
u32 acktimeout;
|
||||
u32 ctstimeout;
|
||||
u32 globaltxtimeout;
|
||||
|
||||
/* ANI */
|
||||
|
@ -616,7 +615,7 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
|
|||
|
||||
/* Initialization, Detach, Reset */
|
||||
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
|
||||
void ath9k_hw_detach(struct ath_hw *ah);
|
||||
void ath9k_hw_deinit(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);
|
||||
|
@ -668,7 +667,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
|
|||
void ath9k_hw_reset_tsf(struct ath_hw *ah);
|
||||
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
|
||||
u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
|
||||
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
|
||||
void ath9k_hw_init_global_settings(struct ath_hw *ah);
|
||||
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
|
||||
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
|
||||
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
|
||||
|
|
861
drivers/net/wireless/ath/ath9k/init.c
Normal file
861
drivers/net/wireless/ath/ath9k/init.c
Normal file
|
@ -0,0 +1,861 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2009 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
static char *dev_info = "ath9k";
|
||||
|
||||
MODULE_AUTHOR("Atheros Communications");
|
||||
MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
|
||||
MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
|
||||
module_param_named(debug, ath9k_debug, uint, 0);
|
||||
MODULE_PARM_DESC(debug, "Debugging mask");
|
||||
|
||||
int modparam_nohwcrypt;
|
||||
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
|
||||
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
|
||||
|
||||
/* We use the hw_value as an index into our private channel structure */
|
||||
|
||||
#define CHAN2G(_freq, _idx) { \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
#define CHAN5G(_freq, _idx) { \
|
||||
.band = IEEE80211_BAND_5GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
/* Some 2 GHz radios are actually tunable on 2312-2732
|
||||
* on 5 MHz steps, we support the channels which we know
|
||||
* we have calibration data for all cards though to make
|
||||
* this static */
|
||||
static struct ieee80211_channel ath9k_2ghz_chantable[] = {
|
||||
CHAN2G(2412, 0), /* Channel 1 */
|
||||
CHAN2G(2417, 1), /* Channel 2 */
|
||||
CHAN2G(2422, 2), /* Channel 3 */
|
||||
CHAN2G(2427, 3), /* Channel 4 */
|
||||
CHAN2G(2432, 4), /* Channel 5 */
|
||||
CHAN2G(2437, 5), /* Channel 6 */
|
||||
CHAN2G(2442, 6), /* Channel 7 */
|
||||
CHAN2G(2447, 7), /* Channel 8 */
|
||||
CHAN2G(2452, 8), /* Channel 9 */
|
||||
CHAN2G(2457, 9), /* Channel 10 */
|
||||
CHAN2G(2462, 10), /* Channel 11 */
|
||||
CHAN2G(2467, 11), /* Channel 12 */
|
||||
CHAN2G(2472, 12), /* Channel 13 */
|
||||
CHAN2G(2484, 13), /* Channel 14 */
|
||||
};
|
||||
|
||||
/* Some 5 GHz radios are actually tunable on XXXX-YYYY
|
||||
* on 5 MHz steps, we support the channels which we know
|
||||
* we have calibration data for all cards though to make
|
||||
* this static */
|
||||
static struct ieee80211_channel ath9k_5ghz_chantable[] = {
|
||||
/* _We_ call this UNII 1 */
|
||||
CHAN5G(5180, 14), /* Channel 36 */
|
||||
CHAN5G(5200, 15), /* Channel 40 */
|
||||
CHAN5G(5220, 16), /* Channel 44 */
|
||||
CHAN5G(5240, 17), /* Channel 48 */
|
||||
/* _We_ call this UNII 2 */
|
||||
CHAN5G(5260, 18), /* Channel 52 */
|
||||
CHAN5G(5280, 19), /* Channel 56 */
|
||||
CHAN5G(5300, 20), /* Channel 60 */
|
||||
CHAN5G(5320, 21), /* Channel 64 */
|
||||
/* _We_ call this "Middle band" */
|
||||
CHAN5G(5500, 22), /* Channel 100 */
|
||||
CHAN5G(5520, 23), /* Channel 104 */
|
||||
CHAN5G(5540, 24), /* Channel 108 */
|
||||
CHAN5G(5560, 25), /* Channel 112 */
|
||||
CHAN5G(5580, 26), /* Channel 116 */
|
||||
CHAN5G(5600, 27), /* Channel 120 */
|
||||
CHAN5G(5620, 28), /* Channel 124 */
|
||||
CHAN5G(5640, 29), /* Channel 128 */
|
||||
CHAN5G(5660, 30), /* Channel 132 */
|
||||
CHAN5G(5680, 31), /* Channel 136 */
|
||||
CHAN5G(5700, 32), /* Channel 140 */
|
||||
/* _We_ call this UNII 3 */
|
||||
CHAN5G(5745, 33), /* Channel 149 */
|
||||
CHAN5G(5765, 34), /* Channel 153 */
|
||||
CHAN5G(5785, 35), /* Channel 157 */
|
||||
CHAN5G(5805, 36), /* Channel 161 */
|
||||
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 ath9k_deinit_softc(struct ath_softc *sc);
|
||||
|
||||
/*
|
||||
* Read and write, they both share the same lock. We do this to serialize
|
||||
* reads and writes on Atheros 802.11n PCI devices only. This is required
|
||||
* as the FIFO on these devices can only accept sanely 2 requests.
|
||||
*/
|
||||
|
||||
static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
|
||||
{
|
||||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
|
||||
if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&sc->sc_serial_rw, flags);
|
||||
iowrite32(val, sc->mem + reg_offset);
|
||||
spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
|
||||
} else
|
||||
iowrite32(val, sc->mem + reg_offset);
|
||||
}
|
||||
|
||||
static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
|
||||
{
|
||||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
u32 val;
|
||||
|
||||
if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&sc->sc_serial_rw, flags);
|
||||
val = ioread32(sc->mem + reg_offset);
|
||||
spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
|
||||
} else
|
||||
val = ioread32(sc->mem + reg_offset);
|
||||
return val;
|
||||
}
|
||||
|
||||
static const struct ath_ops ath9k_common_ops = {
|
||||
.read = ath9k_ioread32,
|
||||
.write = ath9k_iowrite32,
|
||||
};
|
||||
|
||||
/**************************/
|
||||
/* Initialization */
|
||||
/**************************/
|
||||
|
||||
static void setup_ht_cap(struct ath_softc *sc,
|
||||
struct ieee80211_sta_ht_cap *ht_info)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
u8 tx_streams, rx_streams;
|
||||
|
||||
ht_info->ht_supported = true;
|
||||
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_SM_PS |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40;
|
||||
|
||||
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
|
||||
|
||||
/* set up supported mcs set */
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
|
||||
1 : 2;
|
||||
rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
|
||||
1 : 2;
|
||||
|
||||
if (tx_streams != rx_streams) {
|
||||
ath_print(common, ATH_DBG_CONFIG,
|
||||
"TX streams %d, RX streams: %d\n",
|
||||
tx_streams, rx_streams);
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
|
||||
ht_info->mcs.tx_params |= ((tx_streams - 1) <<
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
|
||||
}
|
||||
|
||||
ht_info->mcs.rx_mask[0] = 0xff;
|
||||
if (rx_streams >= 2)
|
||||
ht_info->mcs.rx_mask[1] = 0xff;
|
||||
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
|
||||
}
|
||||
|
||||
static int ath9k_reg_notifier(struct wiphy *wiphy,
|
||||
struct regulatory_request *request)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
|
||||
|
||||
return ath_reg_notifier_apply(wiphy, request, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will allocate both the DMA descriptor structure, and the
|
||||
* buffers it contains. These are used to contain the descriptors used
|
||||
* by the system.
|
||||
*/
|
||||
int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
||||
struct list_head *head, const char *name,
|
||||
int nbuf, int ndesc)
|
||||
{
|
||||
#define DS2PHYS(_dd, _ds) \
|
||||
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
|
||||
#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
|
||||
#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_desc *ds;
|
||||
struct ath_buf *bf;
|
||||
int i, bsize, error;
|
||||
|
||||
ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
|
||||
name, nbuf, ndesc);
|
||||
|
||||
INIT_LIST_HEAD(head);
|
||||
/* ath_desc must be a multiple of DWORDs */
|
||||
if ((sizeof(struct ath_desc) % 4) != 0) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"ath_desc not DWORD aligned\n");
|
||||
BUG_ON((sizeof(struct ath_desc) % 4) != 0);
|
||||
error = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
|
||||
|
||||
/*
|
||||
* Need additional DMA memory because we can't use
|
||||
* descriptors that cross the 4K page boundary. Assume
|
||||
* one skipped descriptor per 4K page.
|
||||
*/
|
||||
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
|
||||
u32 ndesc_skipped =
|
||||
ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
|
||||
u32 dma_len;
|
||||
|
||||
while (ndesc_skipped) {
|
||||
dma_len = ndesc_skipped * sizeof(struct ath_desc);
|
||||
dd->dd_desc_len += dma_len;
|
||||
|
||||
ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
|
||||
};
|
||||
}
|
||||
|
||||
/* allocate descriptors */
|
||||
dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
|
||||
&dd->dd_desc_paddr, GFP_KERNEL);
|
||||
if (dd->dd_desc == NULL) {
|
||||
error = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
ds = dd->dd_desc;
|
||||
ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
|
||||
name, ds, (u32) dd->dd_desc_len,
|
||||
ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
|
||||
|
||||
/* allocate buffers */
|
||||
bsize = sizeof(struct ath_buf) * nbuf;
|
||||
bf = kzalloc(bsize, GFP_KERNEL);
|
||||
if (bf == NULL) {
|
||||
error = -ENOMEM;
|
||||
goto fail2;
|
||||
}
|
||||
dd->dd_bufptr = bf;
|
||||
|
||||
for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
|
||||
bf->bf_desc = ds;
|
||||
bf->bf_daddr = DS2PHYS(dd, ds);
|
||||
|
||||
if (!(sc->sc_ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_4KB_SPLITTRANS)) {
|
||||
/*
|
||||
* Skip descriptor addresses which can cause 4KB
|
||||
* boundary crossing (addr + length) with a 32 dword
|
||||
* descriptor fetch.
|
||||
*/
|
||||
while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
|
||||
BUG_ON((caddr_t) bf->bf_desc >=
|
||||
((caddr_t) dd->dd_desc +
|
||||
dd->dd_desc_len));
|
||||
|
||||
ds += ndesc;
|
||||
bf->bf_desc = ds;
|
||||
bf->bf_daddr = DS2PHYS(dd, ds);
|
||||
}
|
||||
}
|
||||
list_add_tail(&bf->list, head);
|
||||
}
|
||||
return 0;
|
||||
fail2:
|
||||
dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
|
||||
dd->dd_desc_paddr);
|
||||
fail:
|
||||
memset(dd, 0, sizeof(*dd));
|
||||
return error;
|
||||
#undef ATH_DESC_4KB_BOUND_CHECK
|
||||
#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
|
||||
#undef DS2PHYS
|
||||
}
|
||||
|
||||
static void ath9k_init_crypto(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int i = 0;
|
||||
|
||||
/* Get the hardware key cache size. */
|
||||
common->keymax = sc->sc_ah->caps.keycache_size;
|
||||
if (common->keymax > ATH_KEYMAX) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"Warning, using only %u entries in %u key cache\n",
|
||||
ATH_KEYMAX, common->keymax);
|
||||
common->keymax = ATH_KEYMAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the key cache since some parts do not
|
||||
* reset the contents on initial power up.
|
||||
*/
|
||||
for (i = 0; i < common->keymax; i++)
|
||||
ath9k_hw_keyreset(sc->sc_ah, (u16) i);
|
||||
|
||||
if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
|
||||
ATH9K_CIPHER_TKIP, NULL)) {
|
||||
/*
|
||||
* Whether we should enable h/w TKIP MIC.
|
||||
* XXX: if we don't support WME TKIP MIC, then we wouldn't
|
||||
* report WMM capable, so it's always safe to turn on
|
||||
* TKIP MIC in this case.
|
||||
*/
|
||||
ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the separate key cache entries
|
||||
* are required to handle both tx+rx MIC keys.
|
||||
* With split mic keys the number of stations is limited
|
||||
* to 27 otherwise 59.
|
||||
*/
|
||||
if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
|
||||
ATH9K_CIPHER_TKIP, NULL)
|
||||
&& ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
|
||||
ATH9K_CIPHER_MIC, NULL)
|
||||
&& ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT,
|
||||
0, NULL))
|
||||
common->splitmic = 1;
|
||||
|
||||
/* turn on mcast key search if possible */
|
||||
if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
|
||||
(void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH,
|
||||
1, 1, NULL);
|
||||
|
||||
}
|
||||
|
||||
static int ath9k_init_btcoex(struct ath_softc *sc)
|
||||
{
|
||||
int r, qnum;
|
||||
|
||||
switch (sc->sc_ah->btcoex_hw.scheme) {
|
||||
case ATH_BTCOEX_CFG_NONE:
|
||||
break;
|
||||
case ATH_BTCOEX_CFG_2WIRE:
|
||||
ath9k_hw_btcoex_init_2wire(sc->sc_ah);
|
||||
break;
|
||||
case ATH_BTCOEX_CFG_3WIRE:
|
||||
ath9k_hw_btcoex_init_3wire(sc->sc_ah);
|
||||
r = ath_init_btcoex_timer(sc);
|
||||
if (r)
|
||||
return -1;
|
||||
qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
|
||||
ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum);
|
||||
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath9k_init_queues(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
|
||||
sc->tx.hwq_map[i] = -1;
|
||||
|
||||
sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
|
||||
if (sc->beacon.beaconq == -1) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to setup a beacon xmit queue\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
|
||||
if (sc->beacon.cabq == NULL) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to setup CAB xmit queue\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
|
||||
ath_cabq_update(sc);
|
||||
|
||||
if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to setup xmit queue for BK traffic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to setup xmit queue for BE traffic\n");
|
||||
goto err;
|
||||
}
|
||||
if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to setup xmit queue for VI traffic\n");
|
||||
goto err;
|
||||
}
|
||||
if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to setup xmit queue for VO traffic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
|
||||
if (ATH_TXQ_SETUP(sc, i))
|
||||
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void ath9k_init_channels_rates(struct ath_softc *sc)
|
||||
{
|
||||
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].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;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_init_misc(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int i = 0;
|
||||
|
||||
common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
|
||||
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
|
||||
|
||||
sc->config.txpowlimit = ATH_TXPOWER_MAX;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
|
||||
sc->sc_flags |= SC_OP_TXAGGR;
|
||||
sc->sc_flags |= SC_OP_RXAGGR;
|
||||
}
|
||||
|
||||
common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
|
||||
common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
|
||||
|
||||
ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
|
||||
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
|
||||
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
|
||||
sc->beacon.bslot[i] = NULL;
|
||||
sc->beacon.bslot_aphy[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ath_hw *ah = NULL;
|
||||
struct ath_common *common;
|
||||
int ret = 0, i;
|
||||
int csz = 0;
|
||||
|
||||
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
|
||||
if (!ah)
|
||||
return -ENOMEM;
|
||||
|
||||
ah->hw_version.devid = devid;
|
||||
ah->hw_version.subsysid = subsysid;
|
||||
sc->sc_ah = ah;
|
||||
|
||||
common = ath9k_hw_common(ah);
|
||||
common->ops = &ath9k_common_ops;
|
||||
common->bus_ops = bus_ops;
|
||||
common->ah = ah;
|
||||
common->hw = sc->hw;
|
||||
common->priv = sc;
|
||||
common->debug_mask = ath9k_debug;
|
||||
|
||||
spin_lock_init(&sc->wiphy_lock);
|
||||
spin_lock_init(&sc->sc_resetlock);
|
||||
spin_lock_init(&sc->sc_serial_rw);
|
||||
spin_lock_init(&sc->sc_pm_lock);
|
||||
mutex_init(&sc->mutex);
|
||||
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
|
||||
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
|
||||
(unsigned long)sc);
|
||||
|
||||
/*
|
||||
* Cache line size is used to size and align various
|
||||
* structures used to communicate with the hardware.
|
||||
*/
|
||||
ath_read_cachesize(common, &csz);
|
||||
common->cachelsz = csz << 2; /* convert to bytes */
|
||||
|
||||
ret = ath9k_hw_init(ah);
|
||||
if (ret) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to initialize hardware; "
|
||||
"initialization status: %d\n", ret);
|
||||
goto err_hw;
|
||||
}
|
||||
|
||||
ret = ath9k_init_debug(ah);
|
||||
if (ret) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to create debugfs files\n");
|
||||
goto err_debug;
|
||||
}
|
||||
|
||||
ret = ath9k_init_queues(sc);
|
||||
if (ret)
|
||||
goto err_queues;
|
||||
|
||||
ret = ath9k_init_btcoex(sc);
|
||||
if (ret)
|
||||
goto err_btcoex;
|
||||
|
||||
ath9k_init_crypto(sc);
|
||||
ath9k_init_channels_rates(sc);
|
||||
ath9k_init_misc(sc);
|
||||
|
||||
return 0;
|
||||
|
||||
err_btcoex:
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
|
||||
if (ATH_TXQ_SETUP(sc, i))
|
||||
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
|
||||
err_queues:
|
||||
ath9k_exit_debug(ah);
|
||||
err_debug:
|
||||
ath9k_hw_deinit(ah);
|
||||
err_hw:
|
||||
tasklet_kill(&sc->intr_tq);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
|
||||
kfree(ah);
|
||||
sc->sc_ah = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
|
||||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_AMPDU_AGGREGATION |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_PS_NULLFUNC_STACK |
|
||||
IEEE80211_HW_SPECTRUM_MGMT;
|
||||
|
||||
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
|
||||
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
hw->channel_change_time = 5000;
|
||||
hw->max_listen_interval = 10;
|
||||
/* Hardware supports 10 but we use 4 */
|
||||
hw->max_rate_tries = 4;
|
||||
hw->sta_data_size = sizeof(struct ath_node);
|
||||
hw->vif_data_size = sizeof(struct ath_vif);
|
||||
|
||||
hw->rate_control_algorithm = "ath9k_rate_control";
|
||||
|
||||
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];
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
|
||||
if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
|
||||
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
|
||||
if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
|
||||
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
||||
}
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||
}
|
||||
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath_common *common;
|
||||
struct ath_hw *ah;
|
||||
int error = 0;
|
||||
struct ath_regulatory *reg;
|
||||
|
||||
/* Bring up device */
|
||||
error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
|
||||
if (error != 0)
|
||||
goto error_init;
|
||||
|
||||
ah = sc->sc_ah;
|
||||
common = ath9k_hw_common(ah);
|
||||
ath9k_set_hw_capab(sc, hw);
|
||||
|
||||
/* Initialize regulatory */
|
||||
error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
|
||||
ath9k_reg_notifier);
|
||||
if (error)
|
||||
goto error_regd;
|
||||
|
||||
reg = &common->regulatory;
|
||||
|
||||
/* Setup TX DMA */
|
||||
error = ath_tx_init(sc, ATH_TXBUF);
|
||||
if (error != 0)
|
||||
goto error_tx;
|
||||
|
||||
/* Setup RX DMA */
|
||||
error = ath_rx_init(sc, ATH_RXBUF);
|
||||
if (error != 0)
|
||||
goto error_rx;
|
||||
|
||||
/* Register with mac80211 */
|
||||
error = ieee80211_register_hw(hw);
|
||||
if (error)
|
||||
goto error_register;
|
||||
|
||||
/* Handle world regulatory */
|
||||
if (!ath_is_world_regd(reg)) {
|
||||
error = regulatory_hint(hw->wiphy, reg->alpha2);
|
||||
if (error)
|
||||
goto error_world;
|
||||
}
|
||||
|
||||
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
|
||||
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
|
||||
sc->wiphy_scheduler_int = msecs_to_jiffies(500);
|
||||
|
||||
ath_init_leds(sc);
|
||||
ath_start_rfkill_poll(sc);
|
||||
|
||||
return 0;
|
||||
|
||||
error_world:
|
||||
ieee80211_unregister_hw(hw);
|
||||
error_register:
|
||||
ath_rx_cleanup(sc);
|
||||
error_rx:
|
||||
ath_tx_cleanup(sc);
|
||||
error_tx:
|
||||
/* Nothing */
|
||||
error_regd:
|
||||
ath9k_deinit_softc(sc);
|
||||
error_init:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
/* De-Initialization */
|
||||
/*****************************/
|
||||
|
||||
static void ath9k_deinit_softc(struct ath_softc *sc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if ((sc->btcoex.no_stomp_timer) &&
|
||||
sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
|
||||
ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
|
||||
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
|
||||
if (ATH_TXQ_SETUP(sc, i))
|
||||
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
|
||||
|
||||
ath9k_exit_debug(sc->sc_ah);
|
||||
ath9k_hw_deinit(sc->sc_ah);
|
||||
|
||||
tasklet_kill(&sc->intr_tq);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
}
|
||||
|
||||
void ath9k_deinit_device(struct ath_softc *sc)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
int i = 0;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
wiphy_rfkill_stop_polling(sc->hw->wiphy);
|
||||
ath_deinit_leds(sc);
|
||||
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (aphy == NULL)
|
||||
continue;
|
||||
sc->sec_wiphy[i] = NULL;
|
||||
ieee80211_unregister_hw(aphy->hw);
|
||||
ieee80211_free_hw(aphy->hw);
|
||||
}
|
||||
kfree(sc->sec_wiphy);
|
||||
|
||||
ieee80211_unregister_hw(hw);
|
||||
ath_rx_cleanup(sc);
|
||||
ath_tx_cleanup(sc);
|
||||
ath9k_deinit_softc(sc);
|
||||
}
|
||||
|
||||
void ath_descdma_cleanup(struct ath_softc *sc,
|
||||
struct ath_descdma *dd,
|
||||
struct list_head *head)
|
||||
{
|
||||
dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
|
||||
dd->dd_desc_paddr);
|
||||
|
||||
INIT_LIST_HEAD(head);
|
||||
kfree(dd->dd_bufptr);
|
||||
memset(dd, 0, sizeof(*dd));
|
||||
}
|
||||
|
||||
/************************/
|
||||
/* Module Hooks */
|
||||
/************************/
|
||||
|
||||
static int __init ath9k_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Register rate control algorithm */
|
||||
error = ath_rate_control_register();
|
||||
if (error != 0) {
|
||||
printk(KERN_ERR
|
||||
"ath9k: Unable to register rate control "
|
||||
"algorithm: %d\n",
|
||||
error);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
error = ath9k_debug_create_root();
|
||||
if (error) {
|
||||
printk(KERN_ERR
|
||||
"ath9k: Unable to create debugfs root: %d\n",
|
||||
error);
|
||||
goto err_rate_unregister;
|
||||
}
|
||||
|
||||
error = ath_pci_init();
|
||||
if (error < 0) {
|
||||
printk(KERN_ERR
|
||||
"ath9k: No PCI devices found, driver not installed.\n");
|
||||
error = -ENODEV;
|
||||
goto err_remove_root;
|
||||
}
|
||||
|
||||
error = ath_ahb_init();
|
||||
if (error < 0) {
|
||||
error = -ENODEV;
|
||||
goto err_pci_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_pci_exit:
|
||||
ath_pci_exit();
|
||||
|
||||
err_remove_root:
|
||||
ath9k_debug_remove_root();
|
||||
err_rate_unregister:
|
||||
ath_rate_control_unregister();
|
||||
err_out:
|
||||
return error;
|
||||
}
|
||||
module_init(ath9k_init);
|
||||
|
||||
static void __exit ath9k_exit(void)
|
||||
{
|
||||
ath_ahb_exit();
|
||||
ath_pci_exit();
|
||||
ath9k_debug_remove_root();
|
||||
ath_rate_control_unregister();
|
||||
printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
|
||||
}
|
||||
module_exit(ath9k_exit);
|
|
@ -167,6 +167,40 @@ struct ath_rx_status {
|
|||
#define ATH9K_RXKEYIX_INVALID ((u8)-1)
|
||||
#define ATH9K_TXKEYIX_INVALID ((u32)-1)
|
||||
|
||||
enum ath9k_phyerr {
|
||||
ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */
|
||||
ATH9K_PHYERR_TIMING = 1, /* Timing error */
|
||||
ATH9K_PHYERR_PARITY = 2, /* Illegal parity */
|
||||
ATH9K_PHYERR_RATE = 3, /* Illegal rate */
|
||||
ATH9K_PHYERR_LENGTH = 4, /* Illegal length */
|
||||
ATH9K_PHYERR_RADAR = 5, /* Radar detect */
|
||||
ATH9K_PHYERR_SERVICE = 6, /* Illegal service */
|
||||
ATH9K_PHYERR_TOR = 7, /* Transmit override receive */
|
||||
|
||||
ATH9K_PHYERR_OFDM_TIMING = 17,
|
||||
ATH9K_PHYERR_OFDM_SIGNAL_PARITY = 18,
|
||||
ATH9K_PHYERR_OFDM_RATE_ILLEGAL = 19,
|
||||
ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL = 20,
|
||||
ATH9K_PHYERR_OFDM_POWER_DROP = 21,
|
||||
ATH9K_PHYERR_OFDM_SERVICE = 22,
|
||||
ATH9K_PHYERR_OFDM_RESTART = 23,
|
||||
ATH9K_PHYERR_FALSE_RADAR_EXT = 24,
|
||||
|
||||
ATH9K_PHYERR_CCK_TIMING = 25,
|
||||
ATH9K_PHYERR_CCK_HEADER_CRC = 26,
|
||||
ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27,
|
||||
ATH9K_PHYERR_CCK_SERVICE = 30,
|
||||
ATH9K_PHYERR_CCK_RESTART = 31,
|
||||
ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32,
|
||||
ATH9K_PHYERR_CCK_POWER_DROP = 33,
|
||||
|
||||
ATH9K_PHYERR_HT_CRC_ERROR = 34,
|
||||
ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35,
|
||||
ATH9K_PHYERR_HT_RATE_ILLEGAL = 36,
|
||||
|
||||
ATH9K_PHYERR_MAX = 37,
|
||||
};
|
||||
|
||||
struct ath_desc {
|
||||
u32 ds_link;
|
||||
u32 ds_data;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -113,25 +113,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
u16 subsysid;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
struct ath_hw *ah;
|
||||
char hw_name[64];
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
return -EIO;
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
|
||||
goto bad;
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_ERR "ath9k: 32-bit DMA consistent "
|
||||
"DMA enable failed\n");
|
||||
goto bad;
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -171,22 +168,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (ret) {
|
||||
dev_err(&pdev->dev, "PCI memory region reserve error\n");
|
||||
ret = -ENODEV;
|
||||
goto bad;
|
||||
goto err_region;
|
||||
}
|
||||
|
||||
mem = pci_iomap(pdev, 0, 0);
|
||||
if (!mem) {
|
||||
printk(KERN_ERR "PCI memory map error\n") ;
|
||||
ret = -EIO;
|
||||
goto bad1;
|
||||
goto err_iomap;
|
||||
}
|
||||
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
|
||||
sizeof(struct ath_softc), &ath9k_ops);
|
||||
if (!hw) {
|
||||
dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
|
||||
dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
|
||||
ret = -ENOMEM;
|
||||
goto bad2;
|
||||
goto err_alloc_hw;
|
||||
}
|
||||
|
||||
SET_IEEE80211_DEV(hw, &pdev->dev);
|
||||
|
@ -201,25 +198,25 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
sc->dev = &pdev->dev;
|
||||
sc->mem = mem;
|
||||
|
||||
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
|
||||
ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize device\n");
|
||||
goto bad3;
|
||||
}
|
||||
|
||||
/* setup interrupt service routine */
|
||||
/* Will be cleared in ath9k_start() */
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
|
||||
ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request_irq failed\n");
|
||||
goto bad4;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
sc->irq = pdev->irq;
|
||||
|
||||
ah = sc->sc_ah;
|
||||
ath9k_hw_name(ah, hw_name, sizeof(hw_name));
|
||||
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
|
||||
ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to initialize device\n");
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
|
||||
printk(KERN_INFO
|
||||
"%s: %s mem=0x%lx, irq=%d\n",
|
||||
wiphy_name(hw->wiphy),
|
||||
|
@ -227,15 +224,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
(unsigned long)mem, pdev->irq);
|
||||
|
||||
return 0;
|
||||
bad4:
|
||||
ath_detach(sc);
|
||||
bad3:
|
||||
|
||||
err_init:
|
||||
free_irq(sc->irq, sc);
|
||||
err_irq:
|
||||
ieee80211_free_hw(hw);
|
||||
bad2:
|
||||
err_alloc_hw:
|
||||
pci_iounmap(pdev, mem);
|
||||
bad1:
|
||||
err_iomap:
|
||||
pci_release_region(pdev, 0);
|
||||
bad:
|
||||
err_region:
|
||||
/* Nothing */
|
||||
err_dma:
|
||||
pci_disable_device(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
@ -245,8 +245,12 @@ static void ath_pci_remove(struct pci_dev *pdev)
|
|||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
ath_cleanup(sc);
|
||||
ath9k_deinit_device(sc);
|
||||
free_irq(sc->irq, sc);
|
||||
ieee80211_free_hw(sc->hw);
|
||||
ath_bus_cleanup(common);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
@ -364,10 +364,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
|||
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
|
||||
return; /* not from our current AP */
|
||||
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
|
||||
|
||||
if (sc->sc_flags & SC_OP_BEACON_SYNC) {
|
||||
sc->sc_flags &= ~SC_OP_BEACON_SYNC;
|
||||
if (sc->ps_flags & PS_BEACON_SYNC) {
|
||||
sc->ps_flags &= ~PS_BEACON_SYNC;
|
||||
ath_print(common, ATH_DBG_PS,
|
||||
"Reconfigure Beacon timers based on "
|
||||
"timestamp from the AP\n");
|
||||
|
@ -384,17 +384,17 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
|||
*/
|
||||
ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
|
||||
"buffered broadcast/multicast frame(s)\n");
|
||||
sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
|
||||
sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) {
|
||||
if (sc->ps_flags & PS_WAIT_FOR_CAB) {
|
||||
/*
|
||||
* This can happen if a broadcast frame is dropped or the AP
|
||||
* fails to send a frame indicating that all CAB frames have
|
||||
* been delivered.
|
||||
*/
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_CAB;
|
||||
ath_print(common, ATH_DBG_PS,
|
||||
"PS wait for CAB frames timed out\n");
|
||||
}
|
||||
|
@ -408,10 +408,10 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
|
|||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
/* Process Beacon and CAB receive in PS state */
|
||||
if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
|
||||
if ((sc->ps_flags & PS_WAIT_FOR_BEACON) &&
|
||||
ieee80211_is_beacon(hdr->frame_control))
|
||||
ath_rx_ps_beacon(sc, skb);
|
||||
else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
|
||||
else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
|
||||
(ieee80211_is_data(hdr->frame_control) ||
|
||||
ieee80211_is_action(hdr->frame_control)) &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
|
@ -420,20 +420,20 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
|
|||
* No more broadcast/multicast frames to be received at this
|
||||
* point.
|
||||
*/
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_CAB;
|
||||
ath_print(common, ATH_DBG_PS,
|
||||
"All PS CAB frames received, back to sleep\n");
|
||||
} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
|
||||
} else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
|
||||
!is_multicast_ether_addr(hdr->addr1) &&
|
||||
!ieee80211_has_morefrags(hdr->frame_control)) {
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA;
|
||||
ath_print(common, ATH_DBG_PS,
|
||||
"Going back to sleep after having received "
|
||||
"PS-Poll data (0x%x)\n",
|
||||
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
|
||||
SC_OP_WAIT_FOR_CAB |
|
||||
SC_OP_WAIT_FOR_PSPOLL_DATA |
|
||||
SC_OP_WAIT_FOR_TX_ACK));
|
||||
sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||
PS_WAIT_FOR_CAB |
|
||||
PS_WAIT_FOR_PSPOLL_DATA |
|
||||
PS_WAIT_FOR_TX_ACK));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,6 +571,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
|||
hw = ath_get_virt_hw(sc, hdr);
|
||||
rx_stats = &ds->ds_rxstat;
|
||||
|
||||
ath_debug_stat_rx(sc, bf);
|
||||
|
||||
/*
|
||||
* If we're asked to flush receive queue, directly
|
||||
* chain it back at the queue without processing it.
|
||||
|
@ -631,9 +633,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
|||
sc->rx.rxotherant = 0;
|
||||
}
|
||||
|
||||
if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
|
||||
SC_OP_WAIT_FOR_CAB |
|
||||
SC_OP_WAIT_FOR_PSPOLL_DATA)))
|
||||
if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||
PS_WAIT_FOR_CAB |
|
||||
PS_WAIT_FOR_PSPOLL_DATA)))
|
||||
ath_rx_ps(sc, skb);
|
||||
|
||||
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
|
||||
|
|
|
@ -152,7 +152,7 @@ int ath9k_wiphy_add(struct ath_softc *sc)
|
|||
|
||||
SET_IEEE80211_PERM_ADDR(hw, addr);
|
||||
|
||||
ath_set_hw_capab(sc, hw);
|
||||
ath9k_set_hw_capab(sc, hw);
|
||||
|
||||
error = ieee80211_register_hw(hw);
|
||||
|
||||
|
|
|
@ -1648,7 +1648,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
|||
/* 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;
|
||||
sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
|
||||
} else
|
||||
bf->bf_isnullfunc = false;
|
||||
|
||||
|
@ -1858,15 +1858,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|||
skb_pull(skb, padsize);
|
||||
}
|
||||
|
||||
if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
|
||||
if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
|
||||
ath_print(common, ATH_DBG_PS,
|
||||
"Going back to sleep after having "
|
||||
"received TX status (0x%x)\n",
|
||||
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
|
||||
SC_OP_WAIT_FOR_CAB |
|
||||
SC_OP_WAIT_FOR_PSPOLL_DATA |
|
||||
SC_OP_WAIT_FOR_TX_ACK));
|
||||
sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||
PS_WAIT_FOR_CAB |
|
||||
PS_WAIT_FOR_PSPOLL_DATA |
|
||||
PS_WAIT_FOR_TX_ACK));
|
||||
}
|
||||
|
||||
if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
|
||||
|
@ -2053,11 +2053,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
*/
|
||||
if (bf->bf_isnullfunc &&
|
||||
(ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
|
||||
if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
|
||||
if ((sc->ps_flags & PS_ENABLED)) {
|
||||
sc->ps_enabled = true;
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 1);
|
||||
} else
|
||||
sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
|
||||
sc->ps_flags |= PS_NULLFUNC_COMPLETED;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -253,6 +253,14 @@ enum {
|
|||
#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */
|
||||
#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
|
||||
#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
|
||||
/* SHM_SHARED tx iq workarounds */
|
||||
#define B43_SHM_SH_NPHY_TXIQW0 0x0700
|
||||
#define B43_SHM_SH_NPHY_TXIQW1 0x0702
|
||||
#define B43_SHM_SH_NPHY_TXIQW2 0x0704
|
||||
#define B43_SHM_SH_NPHY_TXIQW3 0x0706
|
||||
/* SHM_SHARED tx pwr ctrl */
|
||||
#define B43_SHM_SH_NPHY_TXPWR_INDX0 0x0708
|
||||
#define B43_SHM_SH_NPHY_TXPWR_INDX1 0x070E
|
||||
|
||||
/* SHM_SCRATCH offsets */
|
||||
#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */
|
||||
|
|
|
@ -67,7 +67,12 @@ MODULE_AUTHOR("Gábor Stefanik");
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
|
||||
|
||||
MODULE_FIRMWARE("b43/ucode11.fw");
|
||||
MODULE_FIRMWARE("b43/ucode13.fw");
|
||||
MODULE_FIRMWARE("b43/ucode14.fw");
|
||||
MODULE_FIRMWARE("b43/ucode15.fw");
|
||||
MODULE_FIRMWARE("b43/ucode5.fw");
|
||||
MODULE_FIRMWARE("b43/ucode9.fw");
|
||||
|
||||
static int modparam_bad_frames_preempt;
|
||||
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
|
||||
|
@ -113,6 +118,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
|
|||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
|
||||
|
|
|
@ -80,6 +80,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
|
|||
dev->phy.lp = NULL;
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
|
||||
static void lpphy_read_band_sprom(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
|
@ -101,6 +102,12 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
|
|||
maxpwr = bus->sprom.maxpwr_bg;
|
||||
lpphy->max_tx_pwr_med_band = maxpwr;
|
||||
cckpo = bus->sprom.cck2gpo;
|
||||
/*
|
||||
* We don't read SPROM's opo as specs say. On rev8 SPROMs
|
||||
* opo == ofdm2gpo and we don't know any SSB with LP-PHY
|
||||
* and SPROM rev below 8.
|
||||
*/
|
||||
B43_WARN_ON(bus->sprom.revision < 8);
|
||||
ofdmpo = bus->sprom.ofdm2gpo;
|
||||
if (cckpo) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
@ -1703,19 +1710,6 @@ static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
|
|||
.c0 = 0,
|
||||
};
|
||||
|
||||
static u8 lpphy_nbits(s32 val)
|
||||
{
|
||||
u32 tmp = abs(val);
|
||||
u8 nbits = 0;
|
||||
|
||||
while (tmp != 0) {
|
||||
nbits++;
|
||||
tmp >>= 1;
|
||||
}
|
||||
|
||||
return nbits;
|
||||
}
|
||||
|
||||
static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
|
||||
{
|
||||
struct lpphy_iq_est iq_est;
|
||||
|
@ -1742,8 +1736,8 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
|
|||
goto out;
|
||||
}
|
||||
|
||||
prod_msb = lpphy_nbits(prod);
|
||||
q_msb = lpphy_nbits(qpwr);
|
||||
prod_msb = fls(abs(prod));
|
||||
q_msb = fls(abs(qpwr));
|
||||
tmp1 = prod_msb - 20;
|
||||
|
||||
if (tmp1 >= 0) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -231,6 +231,7 @@
|
|||
#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
|
||||
#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */
|
||||
#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */
|
||||
#define B43_NPHY_AFECTL_OVER1 B43_PHY_N(0x08F) /* AFE control override 1 */
|
||||
#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */
|
||||
#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */
|
||||
#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0
|
||||
|
@ -705,6 +706,10 @@
|
|||
#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */
|
||||
#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */
|
||||
#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0
|
||||
#define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */
|
||||
#define B43_NPHY_EPS_TABLE_ADJ0 B43_PHY_N(0x298) /* EPS Table Adj0 TBD */
|
||||
#define B43_NPHY_PAPD_EN1 B43_PHY_N(0x29B) /* PAPD Enable1 TBD */
|
||||
#define B43_NPHY_EPS_TABLE_ADJ1 B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */
|
||||
|
||||
|
||||
|
||||
|
@ -919,8 +924,88 @@
|
|||
|
||||
struct b43_wldev;
|
||||
|
||||
struct b43_phy_n_iq_comp {
|
||||
s16 a0;
|
||||
s16 b0;
|
||||
s16 a1;
|
||||
s16 b1;
|
||||
};
|
||||
|
||||
struct b43_phy_n_rssical_cache {
|
||||
u16 rssical_radio_regs_2G[2];
|
||||
u16 rssical_phy_regs_2G[12];
|
||||
|
||||
u16 rssical_radio_regs_5G[2];
|
||||
u16 rssical_phy_regs_5G[12];
|
||||
};
|
||||
|
||||
struct b43_phy_n_cal_cache {
|
||||
u16 txcal_radio_regs_2G[8];
|
||||
u16 txcal_coeffs_2G[8];
|
||||
struct b43_phy_n_iq_comp rxcal_coeffs_2G;
|
||||
|
||||
u16 txcal_radio_regs_5G[8];
|
||||
u16 txcal_coeffs_5G[8];
|
||||
struct b43_phy_n_iq_comp rxcal_coeffs_5G;
|
||||
};
|
||||
|
||||
struct b43_phy_n_txpwrindex {
|
||||
s8 index;
|
||||
s8 index_internal;
|
||||
s8 index_internal_save;
|
||||
u16 AfectrlOverride;
|
||||
u16 AfeCtrlDacGain;
|
||||
u16 rad_gain;
|
||||
u8 bbmult;
|
||||
u16 iqcomp_a;
|
||||
u16 iqcomp_b;
|
||||
u16 locomp;
|
||||
};
|
||||
|
||||
struct b43_phy_n {
|
||||
//TODO lots of missing stuff
|
||||
u8 antsel_type;
|
||||
u8 cal_orig_pwr_idx[2];
|
||||
u8 measure_hold;
|
||||
u8 phyrxchain;
|
||||
u8 perical;
|
||||
u32 deaf_count;
|
||||
u32 rxcalparams;
|
||||
bool hang_avoid;
|
||||
bool mute;
|
||||
u16 papd_epsilon_offset[2];
|
||||
|
||||
u8 mphase_cal_phase_id;
|
||||
u16 mphase_txcal_cmdidx;
|
||||
u16 mphase_txcal_numcmds;
|
||||
u16 mphase_txcal_bestcoeffs[11];
|
||||
|
||||
u8 txpwrctrl;
|
||||
u16 txcal_bbmult;
|
||||
u16 txiqlocal_bestc[11];
|
||||
bool txiqlocal_coeffsvalid;
|
||||
struct b43_phy_n_txpwrindex txpwrindex[2];
|
||||
|
||||
u16 tx_rx_cal_phy_saveregs[11];
|
||||
u16 tx_rx_cal_radio_saveregs[22];
|
||||
|
||||
u16 rfctrl_intc1_save;
|
||||
u16 rfctrl_intc2_save;
|
||||
|
||||
u16 classifier_state;
|
||||
u16 clip_state[2];
|
||||
|
||||
bool ipa2g_on;
|
||||
u8 iqcal_chanspec_2G;
|
||||
u8 rssical_chanspec_2G;
|
||||
|
||||
bool ipa5g_on;
|
||||
u8 iqcal_chanspec_5G;
|
||||
u8 rssical_chanspec_5G;
|
||||
|
||||
struct b43_phy_n_rssical_cache rssical_cache;
|
||||
struct b43_phy_n_cal_cache cal_cache;
|
||||
bool crsminpwr_adjusted;
|
||||
bool noisevars_adjusted;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1336,7 +1336,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
|
|||
}
|
||||
|
||||
|
||||
const u8 b43_ntab_adjustpower0[] = {
|
||||
static const u8 b43_ntab_adjustpower0[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
|
@ -1355,7 +1355,7 @@ const u8 b43_ntab_adjustpower0[] = {
|
|||
0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
|
||||
};
|
||||
|
||||
const u8 b43_ntab_adjustpower1[] = {
|
||||
static const u8 b43_ntab_adjustpower1[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
|
@ -1374,11 +1374,11 @@ const u8 b43_ntab_adjustpower1[] = {
|
|||
0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
|
||||
};
|
||||
|
||||
const u16 b43_ntab_bdi[] = {
|
||||
static const u16 b43_ntab_bdi[] = {
|
||||
0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_channelest[] = {
|
||||
static const u32 b43_ntab_channelest[] = {
|
||||
0x44444444, 0x44444444, 0x44444444, 0x44444444,
|
||||
0x44444444, 0x44444444, 0x44444444, 0x44444444,
|
||||
0x10101010, 0x10101010, 0x10101010, 0x10101010,
|
||||
|
@ -1405,7 +1405,7 @@ const u32 b43_ntab_channelest[] = {
|
|||
0x10101010, 0x10101010, 0x10101010, 0x10101010,
|
||||
};
|
||||
|
||||
const u8 b43_ntab_estimatepowerlt0[] = {
|
||||
static const u8 b43_ntab_estimatepowerlt0[] = {
|
||||
0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
|
||||
0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
|
||||
0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
|
||||
|
@ -1416,7 +1416,7 @@ const u8 b43_ntab_estimatepowerlt0[] = {
|
|||
0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
|
||||
};
|
||||
|
||||
const u8 b43_ntab_estimatepowerlt1[] = {
|
||||
static const u8 b43_ntab_estimatepowerlt1[] = {
|
||||
0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
|
||||
0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
|
||||
0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
|
||||
|
@ -1427,14 +1427,14 @@ const u8 b43_ntab_estimatepowerlt1[] = {
|
|||
0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
|
||||
};
|
||||
|
||||
const u8 b43_ntab_framelookup[] = {
|
||||
static const u8 b43_ntab_framelookup[] = {
|
||||
0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16,
|
||||
0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E,
|
||||
0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A,
|
||||
0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_framestruct[] = {
|
||||
static const u32 b43_ntab_framestruct[] = {
|
||||
0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
|
||||
0x09804506, 0x00100030, 0x09804507, 0x00100030,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
|
@ -1645,7 +1645,7 @@ const u32 b43_ntab_framestruct[] = {
|
|||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_gainctl0[] = {
|
||||
static const u32 b43_ntab_gainctl0[] = {
|
||||
0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
|
||||
0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
|
||||
0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
|
||||
|
@ -1680,7 +1680,7 @@ const u32 b43_ntab_gainctl0[] = {
|
|||
0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_gainctl1[] = {
|
||||
static const u32 b43_ntab_gainctl1[] = {
|
||||
0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
|
||||
0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
|
||||
0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
|
||||
|
@ -1715,12 +1715,12 @@ const u32 b43_ntab_gainctl1[] = {
|
|||
0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_intlevel[] = {
|
||||
static const u32 b43_ntab_intlevel[] = {
|
||||
0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46,
|
||||
0x00C1188D, 0x080024D2, 0x00000070,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_iqlt0[] = {
|
||||
static const u32 b43_ntab_iqlt0[] = {
|
||||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
|
@ -1755,7 +1755,7 @@ const u32 b43_ntab_iqlt0[] = {
|
|||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_iqlt1[] = {
|
||||
static const u32 b43_ntab_iqlt1[] = {
|
||||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
|
@ -1790,7 +1790,7 @@ const u32 b43_ntab_iqlt1[] = {
|
|||
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
|
||||
};
|
||||
|
||||
const u16 b43_ntab_loftlt0[] = {
|
||||
static const u16 b43_ntab_loftlt0[] = {
|
||||
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
|
||||
0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
|
||||
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
|
||||
|
@ -1815,7 +1815,7 @@ const u16 b43_ntab_loftlt0[] = {
|
|||
0x0002, 0x0103,
|
||||
};
|
||||
|
||||
const u16 b43_ntab_loftlt1[] = {
|
||||
static const u16 b43_ntab_loftlt1[] = {
|
||||
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
|
||||
0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
|
||||
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
|
||||
|
@ -1840,7 +1840,7 @@ const u16 b43_ntab_loftlt1[] = {
|
|||
0x0002, 0x0103,
|
||||
};
|
||||
|
||||
const u8 b43_ntab_mcs[] = {
|
||||
static const u8 b43_ntab_mcs[] = {
|
||||
0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C,
|
||||
0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C,
|
||||
0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C,
|
||||
|
@ -1859,7 +1859,7 @@ const u8 b43_ntab_mcs[] = {
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_noisevar10[] = {
|
||||
static const u32 b43_ntab_noisevar10[] = {
|
||||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
|
@ -1926,7 +1926,7 @@ const u32 b43_ntab_noisevar10[] = {
|
|||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_noisevar11[] = {
|
||||
static const u32 b43_ntab_noisevar11[] = {
|
||||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
|
@ -1993,7 +1993,7 @@ const u32 b43_ntab_noisevar11[] = {
|
|||
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
|
||||
};
|
||||
|
||||
const u16 b43_ntab_pilot[] = {
|
||||
static const u16 b43_ntab_pilot[] = {
|
||||
0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08,
|
||||
0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5,
|
||||
0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82,
|
||||
|
@ -2011,12 +2011,12 @@ const u16 b43_ntab_pilot[] = {
|
|||
0xF0A0, 0xF028, 0xFFFF, 0xFFFF,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_pilotlt[] = {
|
||||
static const u32 b43_ntab_pilotlt[] = {
|
||||
0x76540123, 0x62407351, 0x76543201, 0x76540213,
|
||||
0x76540123, 0x76430521,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tdi20a0[] = {
|
||||
static const u32 b43_ntab_tdi20a0[] = {
|
||||
0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0,
|
||||
0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D,
|
||||
0x00020301, 0x00030504, 0x00040708, 0x0005090B,
|
||||
|
@ -2033,7 +2033,7 @@ const u32 b43_ntab_tdi20a0[] = {
|
|||
0x00000000, 0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tdi20a1[] = {
|
||||
static const u32 b43_ntab_tdi20a1[] = {
|
||||
0x00014B26, 0x00028D29, 0x000393AD, 0x00049630,
|
||||
0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D,
|
||||
0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B,
|
||||
|
@ -2050,7 +2050,7 @@ const u32 b43_ntab_tdi20a1[] = {
|
|||
0x00000000, 0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tdi40a0[] = {
|
||||
static const u32 b43_ntab_tdi40a0[] = {
|
||||
0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2,
|
||||
0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C,
|
||||
0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2,
|
||||
|
@ -2081,7 +2081,7 @@ const u32 b43_ntab_tdi40a0[] = {
|
|||
0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tdi40a1[] = {
|
||||
static const u32 b43_ntab_tdi40a1[] = {
|
||||
0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD,
|
||||
0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07,
|
||||
0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D,
|
||||
|
@ -2112,7 +2112,7 @@ const u32 b43_ntab_tdi40a1[] = {
|
|||
0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tdtrn[] = {
|
||||
static const u32 b43_ntab_tdtrn[] = {
|
||||
0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
|
||||
0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
|
||||
0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
|
||||
|
@ -2291,7 +2291,7 @@ const u32 b43_ntab_tdtrn[] = {
|
|||
0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tmap[] = {
|
||||
static const u32 b43_ntab_tmap[] = {
|
||||
0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
|
||||
0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
|
||||
0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
|
||||
|
@ -2406,6 +2406,483 @@ const u32 b43_ntab_tmap[] = {
|
|||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tx_gain_rev0_1_2[] = {
|
||||
0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42,
|
||||
0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44,
|
||||
0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844,
|
||||
0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44,
|
||||
0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844,
|
||||
0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644,
|
||||
0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444,
|
||||
0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44,
|
||||
0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844,
|
||||
0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44,
|
||||
0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944,
|
||||
0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744,
|
||||
0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544,
|
||||
0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44,
|
||||
0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844,
|
||||
0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44,
|
||||
0x03902b42, 0x03902a44, 0x03902a42, 0x03902944,
|
||||
0x03902942, 0x03902844, 0x03902842, 0x03902744,
|
||||
0x03902742, 0x03902644, 0x03902642, 0x03902544,
|
||||
0x03902542, 0x03802b44, 0x03802b42, 0x03802a44,
|
||||
0x03802a42, 0x03802944, 0x03802942, 0x03802844,
|
||||
0x03802842, 0x03802744, 0x03802742, 0x03802644,
|
||||
0x03802642, 0x03802544, 0x03802542, 0x03802444,
|
||||
0x03802442, 0x03802344, 0x03802342, 0x03802244,
|
||||
0x03802242, 0x03802144, 0x03802142, 0x03802044,
|
||||
0x03802042, 0x03801f44, 0x03801f42, 0x03801e44,
|
||||
0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44,
|
||||
0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44,
|
||||
0x03801a42, 0x03801944, 0x03801942, 0x03801844,
|
||||
0x03801842, 0x03801744, 0x03801742, 0x03801644,
|
||||
0x03801642, 0x03801544, 0x03801542, 0x03801444,
|
||||
0x03801442, 0x03801344, 0x03801342, 0x00002b00,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = {
|
||||
0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e,
|
||||
0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037,
|
||||
0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e,
|
||||
0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037,
|
||||
0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e,
|
||||
0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037,
|
||||
0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e,
|
||||
0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037,
|
||||
0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e,
|
||||
0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037,
|
||||
0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e,
|
||||
0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037,
|
||||
0x19410044, 0x19410042, 0x19410040, 0x1941003e,
|
||||
0x1941003c, 0x1941003b, 0x19410039, 0x19410037,
|
||||
0x18410044, 0x18410042, 0x18410040, 0x1841003e,
|
||||
0x1841003c, 0x1841003b, 0x18410039, 0x18410037,
|
||||
0x17410044, 0x17410042, 0x17410040, 0x1741003e,
|
||||
0x1741003c, 0x1741003b, 0x17410039, 0x17410037,
|
||||
0x16410044, 0x16410042, 0x16410040, 0x1641003e,
|
||||
0x1641003c, 0x1641003b, 0x16410039, 0x16410037,
|
||||
0x15410044, 0x15410042, 0x15410040, 0x1541003e,
|
||||
0x1541003c, 0x1541003b, 0x15410039, 0x15410037,
|
||||
0x14410044, 0x14410042, 0x14410040, 0x1441003e,
|
||||
0x1441003c, 0x1441003b, 0x14410039, 0x14410037,
|
||||
0x13410044, 0x13410042, 0x13410040, 0x1341003e,
|
||||
0x1341003c, 0x1341003b, 0x13410039, 0x13410037,
|
||||
0x12410044, 0x12410042, 0x12410040, 0x1241003e,
|
||||
0x1241003c, 0x1241003b, 0x12410039, 0x12410037,
|
||||
0x11410044, 0x11410042, 0x11410040, 0x1141003e,
|
||||
0x1141003c, 0x1141003b, 0x11410039, 0x11410037,
|
||||
0x10410044, 0x10410042, 0x10410040, 0x1041003e,
|
||||
0x1041003c, 0x1041003b, 0x10410039, 0x10410037,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tx_gain_rev3_5ghz[] = {
|
||||
0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e,
|
||||
0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037,
|
||||
0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e,
|
||||
0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037,
|
||||
0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e,
|
||||
0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037,
|
||||
0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e,
|
||||
0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037,
|
||||
0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e,
|
||||
0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037,
|
||||
0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e,
|
||||
0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037,
|
||||
0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e,
|
||||
0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037,
|
||||
0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e,
|
||||
0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037,
|
||||
0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e,
|
||||
0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037,
|
||||
0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e,
|
||||
0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037,
|
||||
0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e,
|
||||
0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037,
|
||||
0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e,
|
||||
0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037,
|
||||
0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e,
|
||||
0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037,
|
||||
0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e,
|
||||
0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037,
|
||||
0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e,
|
||||
0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037,
|
||||
0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e,
|
||||
0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tx_gain_rev4_5ghz[] = {
|
||||
0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e,
|
||||
0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037,
|
||||
0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e,
|
||||
0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037,
|
||||
0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e,
|
||||
0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037,
|
||||
0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e,
|
||||
0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037,
|
||||
0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e,
|
||||
0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037,
|
||||
0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e,
|
||||
0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037,
|
||||
0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e,
|
||||
0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037,
|
||||
0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e,
|
||||
0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037,
|
||||
0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e,
|
||||
0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037,
|
||||
0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e,
|
||||
0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037,
|
||||
0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e,
|
||||
0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037,
|
||||
0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e,
|
||||
0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038,
|
||||
0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e,
|
||||
0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037,
|
||||
0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e,
|
||||
0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037,
|
||||
0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e,
|
||||
0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037,
|
||||
0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c,
|
||||
0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034,
|
||||
};
|
||||
|
||||
const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = {
|
||||
0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044,
|
||||
0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c,
|
||||
0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e,
|
||||
0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a,
|
||||
0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e,
|
||||
0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a,
|
||||
0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e,
|
||||
0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037,
|
||||
0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040,
|
||||
0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a,
|
||||
0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c,
|
||||
0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038,
|
||||
0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b,
|
||||
0x09620039, 0x09620037, 0x09620035, 0x09620033,
|
||||
0x08620044, 0x08620042, 0x08620040, 0x0862003e,
|
||||
0x0862003c, 0x0862003b, 0x0862003a, 0x08620039,
|
||||
0x07620043, 0x07620042, 0x07620040, 0x0762003f,
|
||||
0x0762003d, 0x0762003b, 0x0762003a, 0x07620039,
|
||||
0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b,
|
||||
0x06620039, 0x06620037, 0x06620035, 0x06620033,
|
||||
0x05620046, 0x05620044, 0x05620042, 0x05620040,
|
||||
0x0562003e, 0x0562003c, 0x0562003b, 0x05620039,
|
||||
0x04620044, 0x04620042, 0x04620040, 0x0462003e,
|
||||
0x0462003c, 0x0462003b, 0x04620039, 0x04620038,
|
||||
0x0362003c, 0x0362003b, 0x0362003a, 0x03620039,
|
||||
0x03620038, 0x03620037, 0x03620035, 0x03620033,
|
||||
0x0262004c, 0x0262004a, 0x02620048, 0x02620047,
|
||||
0x02620046, 0x02620044, 0x02620043, 0x02620042,
|
||||
0x0162004a, 0x01620048, 0x01620046, 0x01620044,
|
||||
0x01620043, 0x01620042, 0x01620041, 0x01620040,
|
||||
0x00620042, 0x00620040, 0x0062003e, 0x0062003c,
|
||||
0x0062003b, 0x00620039, 0x00620037, 0x00620035,
|
||||
};
|
||||
|
||||
const u32 txpwrctrl_tx_gain_ipa[] = {
|
||||
0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029,
|
||||
0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025,
|
||||
0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029,
|
||||
0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025,
|
||||
0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029,
|
||||
0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025,
|
||||
0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029,
|
||||
0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025,
|
||||
0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029,
|
||||
0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025,
|
||||
0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029,
|
||||
0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025,
|
||||
0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029,
|
||||
0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025,
|
||||
0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029,
|
||||
0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025,
|
||||
0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029,
|
||||
0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025,
|
||||
0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029,
|
||||
0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025,
|
||||
0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029,
|
||||
0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025,
|
||||
0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029,
|
||||
0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025,
|
||||
0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029,
|
||||
0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025,
|
||||
0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029,
|
||||
0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025,
|
||||
0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029,
|
||||
0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025,
|
||||
0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029,
|
||||
0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025,
|
||||
};
|
||||
|
||||
const u32 txpwrctrl_tx_gain_ipa_rev5[] = {
|
||||
0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029,
|
||||
0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025,
|
||||
0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029,
|
||||
0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025,
|
||||
0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029,
|
||||
0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025,
|
||||
0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029,
|
||||
0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025,
|
||||
0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029,
|
||||
0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025,
|
||||
0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029,
|
||||
0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025,
|
||||
0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029,
|
||||
0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025,
|
||||
0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029,
|
||||
0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025,
|
||||
0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029,
|
||||
0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025,
|
||||
0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029,
|
||||
0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025,
|
||||
0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029,
|
||||
0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025,
|
||||
0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029,
|
||||
0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025,
|
||||
0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029,
|
||||
0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025,
|
||||
0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029,
|
||||
0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025,
|
||||
0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029,
|
||||
0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025,
|
||||
0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029,
|
||||
0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025,
|
||||
};
|
||||
|
||||
const u32 txpwrctrl_tx_gain_ipa_rev6[] = {
|
||||
0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029,
|
||||
0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025,
|
||||
0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029,
|
||||
0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025,
|
||||
0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029,
|
||||
0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025,
|
||||
0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029,
|
||||
0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025,
|
||||
0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029,
|
||||
0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025,
|
||||
0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029,
|
||||
0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025,
|
||||
0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029,
|
||||
0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025,
|
||||
0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029,
|
||||
0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025,
|
||||
0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029,
|
||||
0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025,
|
||||
0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029,
|
||||
0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025,
|
||||
0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029,
|
||||
0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025,
|
||||
0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029,
|
||||
0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025,
|
||||
0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029,
|
||||
0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025,
|
||||
0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029,
|
||||
0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025,
|
||||
0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029,
|
||||
0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025,
|
||||
0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029,
|
||||
0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025,
|
||||
};
|
||||
|
||||
const u32 txpwrctrl_tx_gain_ipa_5g[] = {
|
||||
0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031,
|
||||
0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b,
|
||||
0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027,
|
||||
0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022,
|
||||
0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025,
|
||||
0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027,
|
||||
0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023,
|
||||
0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027,
|
||||
0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022,
|
||||
0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025,
|
||||
0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021,
|
||||
0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026,
|
||||
0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022,
|
||||
0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026,
|
||||
0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022,
|
||||
0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026,
|
||||
0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022,
|
||||
0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026,
|
||||
0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022,
|
||||
0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026,
|
||||
0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021,
|
||||
0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026,
|
||||
0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029,
|
||||
0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024,
|
||||
0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027,
|
||||
0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023,
|
||||
0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026,
|
||||
0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022,
|
||||
0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025,
|
||||
0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027,
|
||||
0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022,
|
||||
0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f,
|
||||
};
|
||||
|
||||
const u16 tbl_iqcal_gainparams[2][9][8] = {
|
||||
{
|
||||
{ 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
|
||||
{ 0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69 },
|
||||
{ 0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68 },
|
||||
{ 0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67 },
|
||||
{ 0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66 },
|
||||
{ 0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65 },
|
||||
{ 0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65 },
|
||||
{ 0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65 },
|
||||
{ 0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65 }
|
||||
},
|
||||
{
|
||||
{ 0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 },
|
||||
{ 0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 },
|
||||
{ 0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79 },
|
||||
{ 0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78 },
|
||||
{ 0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78 },
|
||||
{ 0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78 },
|
||||
{ 0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78 },
|
||||
{ 0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78 },
|
||||
{ 0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78 }
|
||||
}
|
||||
};
|
||||
|
||||
const struct nphy_txiqcal_ladder ladder_lo[] = {
|
||||
{ 3, 0 },
|
||||
{ 4, 0 },
|
||||
{ 6, 0 },
|
||||
{ 9, 0 },
|
||||
{ 13, 0 },
|
||||
{ 18, 0 },
|
||||
{ 25, 0 },
|
||||
{ 25, 1 },
|
||||
{ 25, 2 },
|
||||
{ 25, 3 },
|
||||
{ 25, 4 },
|
||||
{ 25, 5 },
|
||||
{ 25, 6 },
|
||||
{ 25, 7 },
|
||||
{ 35, 7 },
|
||||
{ 50, 7 },
|
||||
{ 71, 7 },
|
||||
{ 100, 7 }
|
||||
};
|
||||
|
||||
const struct nphy_txiqcal_ladder ladder_iq[] = {
|
||||
{ 3, 0 },
|
||||
{ 4, 0 },
|
||||
{ 6, 0 },
|
||||
{ 9, 0 },
|
||||
{ 13, 0 },
|
||||
{ 18, 0 },
|
||||
{ 25, 0 },
|
||||
{ 35, 0 },
|
||||
{ 50, 0 },
|
||||
{ 71, 0 },
|
||||
{ 100, 0 },
|
||||
{ 100, 1 },
|
||||
{ 100, 2 },
|
||||
{ 100, 3 },
|
||||
{ 100, 4 },
|
||||
{ 100, 5 },
|
||||
{ 100, 6 },
|
||||
{ 100, 7 }
|
||||
};
|
||||
|
||||
const u16 loscale[] = {
|
||||
256, 256, 271, 271,
|
||||
287, 256, 256, 271,
|
||||
271, 287, 287, 304,
|
||||
304, 256, 256, 271,
|
||||
271, 287, 287, 304,
|
||||
304, 322, 322, 341,
|
||||
341, 362, 362, 383,
|
||||
383, 256, 256, 271,
|
||||
271, 287, 287, 304,
|
||||
304, 322, 322, 256,
|
||||
256, 271, 271, 287,
|
||||
287, 304, 304, 322,
|
||||
322, 341, 341, 362,
|
||||
362, 256, 256, 271,
|
||||
271, 287, 287, 304,
|
||||
304, 322, 322, 256,
|
||||
256, 271, 271, 287,
|
||||
287, 304, 304, 322,
|
||||
322, 341, 341, 362,
|
||||
362, 256, 256, 271,
|
||||
271, 287, 287, 304,
|
||||
304, 322, 322, 341,
|
||||
341, 362, 362, 383,
|
||||
383, 406, 406, 430,
|
||||
430, 455, 455, 482,
|
||||
482, 511, 511, 541,
|
||||
541, 573, 573, 607,
|
||||
607, 643, 643, 681,
|
||||
681, 722, 722, 764,
|
||||
764, 810, 810, 858,
|
||||
858, 908, 908, 962,
|
||||
962, 1019, 1019, 256
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
|
||||
0x0200, 0x0300, 0x0400, 0x0700,
|
||||
0x0900, 0x0c00, 0x1200, 0x1201,
|
||||
0x1202, 0x1203, 0x1204, 0x1205,
|
||||
0x1206, 0x1207, 0x1907, 0x2307,
|
||||
0x3207, 0x4707
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
|
||||
0x0300, 0x0500, 0x0700, 0x0900,
|
||||
0x0d00, 0x1100, 0x1900, 0x1901,
|
||||
0x1902, 0x1903, 0x1904, 0x1905,
|
||||
0x1906, 0x1907, 0x2407, 0x3207,
|
||||
0x4607, 0x6407
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
|
||||
0x0100, 0x0200, 0x0400, 0x0700,
|
||||
0x0900, 0x0c00, 0x1200, 0x1900,
|
||||
0x2300, 0x3200, 0x4700, 0x4701,
|
||||
0x4702, 0x4703, 0x4704, 0x4705,
|
||||
0x4706, 0x4707
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
|
||||
0x0200, 0x0300, 0x0600, 0x0900,
|
||||
0x0d00, 0x1100, 0x1900, 0x2400,
|
||||
0x3200, 0x4600, 0x6400, 0x6401,
|
||||
0x6402, 0x6403, 0x6404, 0x6405,
|
||||
0x6406, 0x6407
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3] = { };
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_startcoefs[B43_NTAB_TX_IQLO_CAL_STARTCOEFS] = { };
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = {
|
||||
0x8423, 0x8323, 0x8073, 0x8256,
|
||||
0x8045, 0x8223, 0x9423, 0x9323,
|
||||
0x9073, 0x9256, 0x9045, 0x9223
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_cmds_recal[] = {
|
||||
0x8101, 0x8253, 0x8053, 0x8234,
|
||||
0x8034, 0x9101, 0x9253, 0x9053,
|
||||
0x9234, 0x9034
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
|
||||
0x8123, 0x8264, 0x8086, 0x8245,
|
||||
0x8056, 0x9123, 0x9264, 0x9086,
|
||||
0x9245, 0x9056
|
||||
};
|
||||
|
||||
const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
|
||||
0x8434, 0x8334, 0x8084, 0x8267,
|
||||
0x8056, 0x8234, 0x9434, 0x9334,
|
||||
0x9084, 0x9267, 0x9056, 0x9234
|
||||
};
|
||||
|
||||
static inline void assert_ntab_array_sizes(void)
|
||||
{
|
||||
#undef check
|
||||
|
@ -2474,3 +2951,51 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
|
|||
/* Some compiletime assertions... */
|
||||
assert_ntab_array_sizes();
|
||||
}
|
||||
|
||||
#define ntab_upload(dev, offset, data) do { \
|
||||
unsigned int i; \
|
||||
for (i = 0; i < (offset##_SIZE); i++) \
|
||||
b43_ntab_write(dev, (offset) + i, (data)[i]); \
|
||||
} while (0)
|
||||
|
||||
void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
|
||||
{
|
||||
/* Static tables */
|
||||
ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
|
||||
ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
|
||||
ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
|
||||
ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
|
||||
ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
|
||||
ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
|
||||
ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
|
||||
ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
|
||||
ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
|
||||
ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
|
||||
ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
|
||||
ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
|
||||
ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
|
||||
ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
|
||||
|
||||
/* Volatile tables */
|
||||
ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
|
||||
ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
|
||||
ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
|
||||
ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
|
||||
ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
|
||||
ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
|
||||
ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
|
||||
ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
|
||||
ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
|
||||
ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
|
||||
ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
|
||||
ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
|
||||
}
|
||||
|
||||
void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev)
|
||||
{
|
||||
/* Static tables */
|
||||
/* TODO */
|
||||
|
||||
/* Volatile tables */
|
||||
/* TODO */
|
||||
}
|
||||
|
|
|
@ -46,6 +46,11 @@ struct b43_nphy_channeltab_entry {
|
|||
|
||||
struct b43_wldev;
|
||||
|
||||
struct nphy_txiqcal_ladder {
|
||||
u8 percent;
|
||||
u8 g_env;
|
||||
};
|
||||
|
||||
/* Upload the default register value table.
|
||||
* If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
|
||||
* table is uploaded. If "ignore_uploadflag" is true, we upload any value
|
||||
|
@ -126,34 +131,46 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
|
|||
#define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
|
||||
#define B43_NTAB_C1_LOFEEDTH_SIZE 128
|
||||
|
||||
#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18
|
||||
#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18
|
||||
#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18
|
||||
#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_20_SIZE 18
|
||||
#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3 11
|
||||
#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS 9
|
||||
#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3 12
|
||||
#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL 10
|
||||
#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL 10
|
||||
#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12
|
||||
|
||||
void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
|
||||
|
||||
extern const u8 b43_ntab_adjustpower0[];
|
||||
extern const u8 b43_ntab_adjustpower1[];
|
||||
extern const u16 b43_ntab_bdi[];
|
||||
extern const u32 b43_ntab_channelest[];
|
||||
extern const u8 b43_ntab_estimatepowerlt0[];
|
||||
extern const u8 b43_ntab_estimatepowerlt1[];
|
||||
extern const u8 b43_ntab_framelookup[];
|
||||
extern const u32 b43_ntab_framestruct[];
|
||||
extern const u32 b43_ntab_gainctl0[];
|
||||
extern const u32 b43_ntab_gainctl1[];
|
||||
extern const u32 b43_ntab_intlevel[];
|
||||
extern const u32 b43_ntab_iqlt0[];
|
||||
extern const u32 b43_ntab_iqlt1[];
|
||||
extern const u16 b43_ntab_loftlt0[];
|
||||
extern const u16 b43_ntab_loftlt1[];
|
||||
extern const u8 b43_ntab_mcs[];
|
||||
extern const u32 b43_ntab_noisevar10[];
|
||||
extern const u32 b43_ntab_noisevar11[];
|
||||
extern const u16 b43_ntab_pilot[];
|
||||
extern const u32 b43_ntab_pilotlt[];
|
||||
extern const u32 b43_ntab_tdi20a0[];
|
||||
extern const u32 b43_ntab_tdi20a1[];
|
||||
extern const u32 b43_ntab_tdi40a0[];
|
||||
extern const u32 b43_ntab_tdi40a1[];
|
||||
extern const u32 b43_ntab_tdtrn[];
|
||||
extern const u32 b43_ntab_tmap[];
|
||||
void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev);
|
||||
void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev);
|
||||
|
||||
extern const u32 b43_ntab_tx_gain_rev0_1_2[];
|
||||
extern const u32 b43_ntab_tx_gain_rev3plus_2ghz[];
|
||||
extern const u32 b43_ntab_tx_gain_rev3_5ghz[];
|
||||
extern const u32 b43_ntab_tx_gain_rev4_5ghz[];
|
||||
extern const u32 b43_ntab_tx_gain_rev5plus_5ghz[];
|
||||
|
||||
extern const u32 txpwrctrl_tx_gain_ipa[];
|
||||
extern const u32 txpwrctrl_tx_gain_ipa_rev5[];
|
||||
extern const u32 txpwrctrl_tx_gain_ipa_rev6[];
|
||||
extern const u32 txpwrctrl_tx_gain_ipa_5g[];
|
||||
extern const u16 tbl_iqcal_gainparams[2][9][8];
|
||||
extern const struct nphy_txiqcal_ladder ladder_lo[];
|
||||
extern const struct nphy_txiqcal_ladder ladder_iq[];
|
||||
extern const u16 loscale[];
|
||||
|
||||
extern const u16 tbl_tx_iqlo_cal_loft_ladder_40[];
|
||||
extern const u16 tbl_tx_iqlo_cal_loft_ladder_20[];
|
||||
extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[];
|
||||
extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[];
|
||||
extern const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[];
|
||||
extern const u16 tbl_tx_iqlo_cal_startcoefs[];
|
||||
extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[];
|
||||
extern const u16 tbl_tx_iqlo_cal_cmds_recal[];
|
||||
extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[];
|
||||
extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[];
|
||||
|
||||
#endif /* B43_TABLES_NPHY_H_ */
|
||||
|
|
|
@ -61,6 +61,8 @@ MODULE_AUTHOR("Michael Buesch");
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
|
||||
MODULE_FIRMWARE("b43legacy/ucode2.fw");
|
||||
MODULE_FIRMWARE("b43legacy/ucode4.fw");
|
||||
|
||||
#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
|
||||
static int modparam_pio;
|
||||
|
@ -3960,7 +3962,7 @@ static struct ssb_driver b43legacy_ssb_driver = {
|
|||
|
||||
static void b43legacy_print_driverinfo(void)
|
||||
{
|
||||
const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "",
|
||||
const char *feat_pci = "", *feat_leds = "",
|
||||
*feat_pio = "", *feat_dma = "";
|
||||
|
||||
#ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT
|
||||
|
@ -3969,9 +3971,6 @@ static void b43legacy_print_driverinfo(void)
|
|||
#ifdef CONFIG_B43LEGACY_LEDS
|
||||
feat_leds = "L";
|
||||
#endif
|
||||
#ifdef CONFIG_B43LEGACY_RFKILL
|
||||
feat_rfkill = "R";
|
||||
#endif
|
||||
#ifdef CONFIG_B43LEGACY_PIO
|
||||
feat_pio = "I";
|
||||
#endif
|
||||
|
@ -3979,9 +3978,9 @@ static void b43legacy_print_driverinfo(void)
|
|||
feat_dma = "D";
|
||||
#endif
|
||||
printk(KERN_INFO "Broadcom 43xx-legacy driver loaded "
|
||||
"[ Features: %s%s%s%s%s, Firmware-ID: "
|
||||
"[ Features: %s%s%s%s, Firmware-ID: "
|
||||
B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
|
||||
feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma);
|
||||
feat_pci, feat_leds, feat_pio, feat_dma);
|
||||
}
|
||||
|
||||
static int __init b43legacy_init(void)
|
||||
|
|
|
@ -1961,7 +1961,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
|||
struct ieee80211_tx_info *info;
|
||||
struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
|
||||
u32 status = le32_to_cpu(tx_resp->u.status);
|
||||
int tid = MAX_TID_COUNT;
|
||||
int tid = MAX_TID_COUNT - 1;
|
||||
int sta_id;
|
||||
int freed;
|
||||
u8 *qc = NULL;
|
||||
|
|
|
@ -781,7 +781,7 @@ void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
|
|||
|
||||
scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
|
||||
|
||||
if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
|
||||
if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
|
||||
scd_bc_tbl[txq_id].
|
||||
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
|
||||
}
|
||||
|
@ -800,12 +800,12 @@ void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
|
|||
if (txq_id != IWL_CMD_QUEUE_NUM)
|
||||
sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
|
||||
|
||||
bc_ent = cpu_to_le16(1 | (sta_id << 12));
|
||||
bc_ent = cpu_to_le16(1 | (sta_id << 12));
|
||||
scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
|
||||
|
||||
if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
|
||||
if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
|
||||
scd_bc_tbl[txq_id].
|
||||
tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
|
||||
tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
|
||||
}
|
||||
|
||||
static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
|
||||
|
|
|
@ -2955,6 +2955,9 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
else
|
||||
return ret;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
/* do nothing */
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
IWL_DEBUG_HT(priv, "unknown\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -120,7 +120,6 @@ enum {
|
|||
CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
|
||||
|
||||
/* 802.11h related */
|
||||
RADAR_NOTIFICATION = 0x70, /* not used */
|
||||
REPLY_QUIET_CMD = 0x71, /* not used */
|
||||
REPLY_CHANNEL_SWITCH = 0x72,
|
||||
CHANNEL_SWITCH_NOTIFICATION = 0x73,
|
||||
|
@ -2984,7 +2983,7 @@ struct statistics_rx_ht_phy {
|
|||
__le32 agg_crc32_good;
|
||||
__le32 agg_mpdu_cnt;
|
||||
__le32 agg_cnt;
|
||||
__le32 reserved2;
|
||||
__le32 unsupport_mcs;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1)
|
||||
|
@ -3087,8 +3086,8 @@ struct statistics_div {
|
|||
} __attribute__ ((packed));
|
||||
|
||||
struct statistics_general {
|
||||
__le32 temperature;
|
||||
__le32 temperature_m;
|
||||
__le32 temperature; /* radio temperature */
|
||||
__le32 temperature_m; /* for 5000 and up, this is radio voltage */
|
||||
struct statistics_dbg dbg;
|
||||
__le32 sleep_time;
|
||||
__le32 slots_out;
|
||||
|
|
|
@ -63,8 +63,6 @@
|
|||
#ifndef __iwl_core_h__
|
||||
#define __iwl_core_h__
|
||||
|
||||
#include <generated/utsrelease.h>
|
||||
|
||||
/************************
|
||||
* forward declarations *
|
||||
************************/
|
||||
|
@ -72,7 +70,7 @@ struct iwl_host_cmd;
|
|||
struct iwl_cmd;
|
||||
|
||||
|
||||
#define IWLWIFI_VERSION UTS_RELEASE "-k"
|
||||
#define IWLWIFI_VERSION "in-tree:"
|
||||
#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation"
|
||||
#define DRV_AUTHOR "<ilw@linux.intel.com>"
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char *buf;
|
||||
int pos = 0;
|
||||
|
||||
|
@ -184,7 +184,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char *buf;
|
||||
int pos = 0;
|
||||
int cnt;
|
||||
|
@ -232,7 +232,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
|||
ssize_t ret;
|
||||
int i;
|
||||
int pos = 0;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
size_t bufsz;
|
||||
|
||||
/* default is to dump the entire data segment */
|
||||
|
@ -306,7 +306,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file,
|
|||
static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
struct iwl_station_entry *station;
|
||||
int max_sta = priv->hw_params.max_stations;
|
||||
char *buf;
|
||||
|
@ -376,7 +376,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
|
|||
loff_t *ppos)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0, ofs = 0, buf_size = 0;
|
||||
const u8 *ptr;
|
||||
char *buf;
|
||||
|
@ -464,7 +464,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
|
|||
static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
struct ieee80211_channel *channels = NULL;
|
||||
const struct ieee80211_supported_band *supp_band = NULL;
|
||||
int pos = 0, i, bufsz = PAGE_SIZE;
|
||||
|
@ -537,7 +537,7 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[512];
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
@ -585,7 +585,7 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
int cnt = 0;
|
||||
char *buf;
|
||||
|
@ -672,7 +672,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
|
|||
static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0, i;
|
||||
char buf[256];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
@ -695,7 +695,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
|
|||
static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char buf[256];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
@ -721,7 +721,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
struct iwl_tt_restriction *restriction;
|
||||
char buf[100];
|
||||
|
@ -781,7 +781,7 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[100];
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
@ -838,7 +838,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[10];
|
||||
int pos, value;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
@ -856,7 +856,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[200];
|
||||
int pos = 0, i;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
@ -994,7 +994,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
struct iwl_tx_queue *txq;
|
||||
struct iwl_queue *q;
|
||||
char *buf;
|
||||
|
@ -1040,7 +1040,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
struct iwl_rx_queue *rxq = &priv->rxq;
|
||||
char buf[256];
|
||||
int pos = 0;
|
||||
|
@ -1086,7 +1086,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = sizeof(struct statistics_rx_phy) * 20 +
|
||||
|
@ -1387,6 +1387,9 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
|
|||
accum_ht->agg_mpdu_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
|
||||
le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "unsupport_mcs:\t\t%u\t\t\t%u\n",
|
||||
le32_to_cpu(ht->unsupport_mcs),
|
||||
accum_ht->unsupport_mcs);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
|
@ -1397,7 +1400,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
|
||||
|
@ -1539,7 +1542,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = sizeof(struct statistics_general) * 4 + 250;
|
||||
|
@ -1630,7 +1633,7 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
int cnt = 0;
|
||||
char *buf;
|
||||
|
@ -1711,7 +1714,7 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
int cnt = 0;
|
||||
char *buf;
|
||||
|
@ -1769,7 +1772,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[128];
|
||||
int pos = 0;
|
||||
ssize_t ret;
|
||||
|
@ -1820,7 +1823,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
|
|||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[60];
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
|
|
@ -58,7 +58,6 @@ const char *get_cmd_string(u8 cmd)
|
|||
IWL_CMD(COEX_PRIORITY_TABLE_CMD);
|
||||
IWL_CMD(COEX_MEDIUM_NOTIFICATION);
|
||||
IWL_CMD(COEX_EVENT_CMD);
|
||||
IWL_CMD(RADAR_NOTIFICATION);
|
||||
IWL_CMD(REPLY_QUIET_CMD);
|
||||
IWL_CMD(REPLY_CHANNEL_SWITCH);
|
||||
IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
|
||||
|
|
|
@ -268,7 +268,7 @@ struct iwm_priv {
|
|||
|
||||
struct sk_buff_head rx_list;
|
||||
struct list_head rx_tickets;
|
||||
struct list_head rx_packets[IWM_RX_ID_HASH + 1];
|
||||
struct list_head rx_packets[IWM_RX_ID_HASH];
|
||||
struct workqueue_struct *rx_wq;
|
||||
struct work_struct rx_worker;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -245,6 +245,25 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_mcu_request);
|
||||
|
||||
int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 reg;
|
||||
|
||||
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
|
||||
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®);
|
||||
if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
|
||||
!rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
|
||||
return 0;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
|
||||
|
||||
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
|
||||
const struct rt2x00debug rt2800_rt2x00debug = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -339,7 +358,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev,
|
|||
rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off);
|
||||
rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3);
|
||||
rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3);
|
||||
rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12);
|
||||
rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 3);
|
||||
rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3);
|
||||
rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1);
|
||||
rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
|
||||
|
@ -347,7 +366,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
|
||||
static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_led *led, enum led_type type)
|
||||
{
|
||||
led->rt2x00dev = rt2x00dev;
|
||||
|
@ -356,7 +375,6 @@ void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
|
|||
led->led_dev.blink_set = rt2800_blink_set;
|
||||
led->flags = LED_INITIALIZED;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_init_led);
|
||||
#endif /* CONFIG_RT2X00_LIB_LEDS */
|
||||
|
||||
/*
|
||||
|
@ -1862,7 +1880,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
|
|||
!rt2x00_rf(rt2x00dev, RF3020) &&
|
||||
!rt2x00_rf(rt2x00dev, RF2020) &&
|
||||
!rt2x00_rf(rt2x00dev, RF3021) &&
|
||||
!rt2x00_rf(rt2x00dev, RF3022)) {
|
||||
!rt2x00_rf(rt2x00dev, RF3022) &&
|
||||
!rt2x00_rf(rt2x00dev, RF3052)) {
|
||||
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -2047,7 +2066,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
if (rt2x00_rf(rt2x00dev, RF2820) ||
|
||||
rt2x00_rf(rt2x00dev, RF2720) ||
|
||||
(rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) {
|
||||
rt2x00_rf(rt2x00dev, RF3052)) {
|
||||
spec->num_channels = 14;
|
||||
spec->channels = rf_vals;
|
||||
} else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
|
||||
|
|
|
@ -114,8 +114,6 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
|
|||
extern const struct rt2x00debug rt2800_rt2x00debug;
|
||||
|
||||
int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_led *led, enum led_type type);
|
||||
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00lib_crypto *crypto,
|
||||
struct ieee80211_key_conf *key);
|
||||
|
@ -139,6 +137,7 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
|
|||
int rt2800_init_registers(struct rt2x00_dev *rt2x00dev);
|
||||
int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev);
|
||||
int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev);
|
||||
int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
|
||||
|
||||
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
|
||||
|
|
|
@ -453,24 +453,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
|||
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
}
|
||||
|
||||
static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 reg;
|
||||
|
||||
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
|
||||
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®);
|
||||
if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
|
||||
!rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
|
||||
return 0;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
u32 reg;
|
||||
|
@ -479,10 +461,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
/*
|
||||
* Initialize all registers.
|
||||
*/
|
||||
if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) ||
|
||||
if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
|
||||
rt2800pci_init_queues(rt2x00dev) ||
|
||||
rt2800_init_registers(rt2x00dev) ||
|
||||
rt2800pci_wait_wpdma_ready(rt2x00dev) ||
|
||||
rt2800_wait_wpdma_ready(rt2x00dev) ||
|
||||
rt2800_init_bbp(rt2x00dev) ||
|
||||
rt2800_init_rfcsr(rt2x00dev)))
|
||||
return -EIO;
|
||||
|
@ -562,7 +544,7 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
|
||||
|
||||
/* Wait for DMA, ignore error */
|
||||
rt2800pci_wait_wpdma_ready(rt2x00dev);
|
||||
rt2800_wait_wpdma_ready(rt2x00dev);
|
||||
}
|
||||
|
||||
static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
|
||||
|
|
|
@ -248,24 +248,6 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
|
|||
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
|
||||
}
|
||||
|
||||
static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 reg;
|
||||
|
||||
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
|
||||
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®);
|
||||
if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
|
||||
!rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
|
||||
return 0;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
u32 reg;
|
||||
|
@ -274,7 +256,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
/*
|
||||
* Initialize all registers.
|
||||
*/
|
||||
if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) ||
|
||||
if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
|
||||
rt2800_init_registers(rt2x00dev) ||
|
||||
rt2800_init_bbp(rt2x00dev) ||
|
||||
rt2800_init_rfcsr(rt2x00dev)))
|
||||
|
@ -344,7 +326,7 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
|
||||
|
||||
/* Wait for DMA, ignore error */
|
||||
rt2800usb_wait_wpdma_ready(rt2x00dev);
|
||||
rt2800_wait_wpdma_ready(rt2x00dev);
|
||||
|
||||
rt2x00usb_disable_radio(rt2x00dev);
|
||||
}
|
||||
|
|
|
@ -118,6 +118,12 @@
|
|||
#define ALIGN_SIZE(__skb, __header) \
|
||||
( ((unsigned long)((__skb)->data + (__header))) & 3 )
|
||||
|
||||
/*
|
||||
* Constants for extra TX headroom for alignment purposes.
|
||||
*/
|
||||
#define RT2X00_ALIGN_SIZE 4 /* Only whole frame needs alignment */
|
||||
#define RT2X00_L2PAD_SIZE 8 /* Both header & payload need alignment */
|
||||
|
||||
/*
|
||||
* Standard timing and size defines.
|
||||
* These values should follow the ieee80211 specifications.
|
||||
|
|
|
@ -688,7 +688,17 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
/*
|
||||
* Initialize extra TX headroom required.
|
||||
*/
|
||||
rt2x00dev->hw->extra_tx_headroom = rt2x00dev->ops->extra_tx_headroom;
|
||||
rt2x00dev->hw->extra_tx_headroom =
|
||||
max_t(unsigned int, IEEE80211_TX_STATUS_HEADROOM,
|
||||
rt2x00dev->ops->extra_tx_headroom);
|
||||
|
||||
/*
|
||||
* Take TX headroom required for alignment into account.
|
||||
*/
|
||||
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
|
||||
rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE;
|
||||
else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
|
||||
rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
|
||||
|
||||
/*
|
||||
* Register HW.
|
||||
|
|
|
@ -104,7 +104,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
|||
* is also mapped to the DMA so it can be used for transfering
|
||||
* additional descriptor information to the hardware.
|
||||
*/
|
||||
skb_push(skb, rt2x00dev->hw->extra_tx_headroom);
|
||||
skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
|
||||
|
||||
skbdesc->skb_dma =
|
||||
dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
||||
|
@ -112,7 +112,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
|||
/*
|
||||
* Restore data pointer to original location again.
|
||||
*/
|
||||
skb_pull(skb, rt2x00dev->hw->extra_tx_headroom);
|
||||
skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
|
||||
|
||||
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
|||
* by the driver, but it was actually mapped to DMA.
|
||||
*/
|
||||
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
|
||||
skb->len + rt2x00dev->hw->extra_tx_headroom,
|
||||
skb->len + rt2x00dev->ops->extra_tx_headroom,
|
||||
DMA_TO_DEVICE);
|
||||
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
|
||||
}
|
||||
|
|
|
@ -410,3 +410,86 @@ int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
|
|||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
|
||||
struct ieee80211_channel *channels[],
|
||||
unsigned int n_channels, unsigned int n_probes)
|
||||
{
|
||||
struct wl1251_cmd_scan *cmd;
|
||||
int i, ret = 0;
|
||||
|
||||
wl1251_debug(DEBUG_CMD, "cmd scan");
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
|
||||
cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN |
|
||||
CFG_RX_MGMT_EN |
|
||||
CFG_RX_BCN_EN);
|
||||
cmd->params.scan_options = 0;
|
||||
cmd->params.num_channels = n_channels;
|
||||
cmd->params.num_probe_requests = n_probes;
|
||||
cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
|
||||
cmd->params.tid_trigger = 0;
|
||||
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
cmd->channels[i].min_duration =
|
||||
cpu_to_le32(WL1251_SCAN_MIN_DURATION);
|
||||
cmd->channels[i].max_duration =
|
||||
cpu_to_le32(WL1251_SCAN_MAX_DURATION);
|
||||
memset(&cmd->channels[i].bssid_lsb, 0xff, 4);
|
||||
memset(&cmd->channels[i].bssid_msb, 0xff, 2);
|
||||
cmd->channels[i].early_termination = 0;
|
||||
cmd->channels[i].tx_power_att = 0;
|
||||
cmd->channels[i].channel = channels[i]->hw_value;
|
||||
}
|
||||
|
||||
cmd->params.ssid_len = ssid_len;
|
||||
if (ssid)
|
||||
memcpy(cmd->params.ssid, ssid, ssid_len);
|
||||
|
||||
ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
|
||||
if (ret < 0) {
|
||||
wl1251_error("cmd scan failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
|
||||
|
||||
if (cmd->header.status != CMD_STATUS_SUCCESS) {
|
||||
wl1251_error("cmd scan status wasn't success: %d",
|
||||
cmd->header.status);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout)
|
||||
{
|
||||
struct wl1251_cmd_trigger_scan_to *cmd;
|
||||
int ret;
|
||||
|
||||
wl1251_debug(DEBUG_CMD, "cmd trigger scan to");
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->timeout = timeout;
|
||||
|
||||
ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
|
||||
if (ret < 0) {
|
||||
wl1251_error("cmd trigger scan to failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "wl1251.h"
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
struct acx_header;
|
||||
|
||||
int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
|
||||
|
@ -43,6 +45,10 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
|
|||
size_t len);
|
||||
int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
|
||||
void *buf, size_t buf_len);
|
||||
int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
|
||||
struct ieee80211_channel *channels[],
|
||||
unsigned int n_channels, unsigned int n_probes);
|
||||
int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout);
|
||||
|
||||
/* unit ms */
|
||||
#define WL1251_COMMAND_TIMEOUT 2000
|
||||
|
@ -163,8 +169,12 @@ struct cmd_read_write_memory {
|
|||
#define CMDMBOX_HEADER_LEN 4
|
||||
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
|
||||
|
||||
#define WL1251_SCAN_MIN_DURATION 30000
|
||||
#define WL1251_SCAN_MAX_DURATION 60000
|
||||
|
||||
struct basic_scan_parameters {
|
||||
#define WL1251_SCAN_NUM_PROBES 3
|
||||
|
||||
struct wl1251_scan_parameters {
|
||||
u32 rx_config_options;
|
||||
u32 rx_filter_options;
|
||||
|
||||
|
@ -189,11 +199,11 @@ struct basic_scan_parameters {
|
|||
|
||||
u8 tid_trigger;
|
||||
u8 ssid_len;
|
||||
u32 ssid[8];
|
||||
u8 ssid[32];
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct basic_scan_channel_parameters {
|
||||
struct wl1251_scan_ch_parameters {
|
||||
u32 min_duration; /* in TU */
|
||||
u32 max_duration; /* in TU */
|
||||
u32 bssid_lsb;
|
||||
|
@ -213,11 +223,11 @@ struct basic_scan_channel_parameters {
|
|||
/* SCAN parameters */
|
||||
#define SCAN_MAX_NUM_OF_CHANNELS 16
|
||||
|
||||
struct cmd_scan {
|
||||
struct wl1251_cmd_scan {
|
||||
struct wl1251_cmd_header header;
|
||||
|
||||
struct basic_scan_parameters params;
|
||||
struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
|
||||
struct wl1251_scan_parameters params;
|
||||
struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum {
|
||||
|
|
|
@ -563,43 +563,25 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
|
|||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
static int wl1251_build_null_data(struct wl1251 *wl)
|
||||
static int wl1251_build_qos_null_data(struct wl1251 *wl)
|
||||
{
|
||||
struct wl12xx_null_data_template template;
|
||||
struct ieee80211_qos_hdr template;
|
||||
|
||||
if (!is_zero_ether_addr(wl->bssid)) {
|
||||
memcpy(template.header.da, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
|
||||
} else {
|
||||
memset(template.header.da, 0xff, ETH_ALEN);
|
||||
memset(template.header.bssid, 0xff, ETH_ALEN);
|
||||
}
|
||||
memset(&template, 0, sizeof(template));
|
||||
|
||||
memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
|
||||
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
memcpy(template.addr1, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(template.addr3, wl->bssid, ETH_ALEN);
|
||||
|
||||
return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
|
||||
template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
|
||||
/* FIXME: not sure what priority to use here */
|
||||
template.qos_ctrl = cpu_to_le16(0);
|
||||
|
||||
return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template,
|
||||
sizeof(template));
|
||||
|
||||
}
|
||||
|
||||
static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
|
||||
{
|
||||
struct wl12xx_ps_poll_template template;
|
||||
|
||||
memcpy(template.bssid, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.ta, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
/* aid in PS-Poll has its two MSBs each set to 1 */
|
||||
template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
|
||||
|
||||
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
|
||||
|
||||
return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
|
||||
sizeof(template));
|
||||
|
||||
}
|
||||
|
||||
static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
|
@ -870,183 +852,14 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int wl1251_build_basic_rates(char *rates)
|
||||
{
|
||||
u8 index = 0;
|
||||
|
||||
rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
|
||||
rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
|
||||
rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
|
||||
rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int wl1251_build_extended_rates(char *rates)
|
||||
{
|
||||
u8 index = 0;
|
||||
|
||||
rates[index++] = IEEE80211_OFDM_RATE_6MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_9MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_12MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_18MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_24MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_36MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_48MB;
|
||||
rates[index++] = IEEE80211_OFDM_RATE_54MB;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wl12xx_probe_req_template template;
|
||||
struct wl12xx_ie_rates *rates;
|
||||
char *ptr;
|
||||
u16 size;
|
||||
|
||||
ptr = (char *)&template;
|
||||
size = sizeof(struct ieee80211_header);
|
||||
|
||||
memset(template.header.da, 0xff, ETH_ALEN);
|
||||
memset(template.header.bssid, 0xff, ETH_ALEN);
|
||||
memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
|
||||
template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
|
||||
|
||||
/* IEs */
|
||||
/* SSID */
|
||||
template.ssid.header.id = WLAN_EID_SSID;
|
||||
template.ssid.header.len = ssid_len;
|
||||
if (ssid_len && ssid)
|
||||
memcpy(template.ssid.ssid, ssid, ssid_len);
|
||||
size += sizeof(struct wl12xx_ie_header) + ssid_len;
|
||||
ptr += size;
|
||||
|
||||
/* Basic Rates */
|
||||
rates = (struct wl12xx_ie_rates *)ptr;
|
||||
rates->header.id = WLAN_EID_SUPP_RATES;
|
||||
rates->header.len = wl1251_build_basic_rates(rates->rates);
|
||||
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
|
||||
ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
|
||||
|
||||
/* Extended rates */
|
||||
rates = (struct wl12xx_ie_rates *)ptr;
|
||||
rates->header.id = WLAN_EID_EXT_SUPP_RATES;
|
||||
rates->header.len = wl1251_build_extended_rates(rates->rates);
|
||||
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
|
||||
|
||||
wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
|
||||
|
||||
return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
|
||||
size);
|
||||
}
|
||||
|
||||
static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
|
||||
u8 active_scan, u8 high_prio, u8 num_channels,
|
||||
u8 probe_requests)
|
||||
{
|
||||
struct wl1251_cmd_trigger_scan_to *trigger = NULL;
|
||||
struct cmd_scan *params = NULL;
|
||||
int i, ret;
|
||||
u16 scan_options = 0;
|
||||
|
||||
if (wl->scanning)
|
||||
return -EINVAL;
|
||||
|
||||
params = kzalloc(sizeof(*params), GFP_KERNEL);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
|
||||
params->params.rx_filter_options =
|
||||
cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
|
||||
|
||||
/* High priority scan */
|
||||
if (!active_scan)
|
||||
scan_options |= SCAN_PASSIVE;
|
||||
if (high_prio)
|
||||
scan_options |= SCAN_PRIORITY_HIGH;
|
||||
params->params.scan_options = scan_options;
|
||||
|
||||
params->params.num_channels = num_channels;
|
||||
params->params.num_probe_requests = probe_requests;
|
||||
params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
|
||||
params->params.tid_trigger = 0;
|
||||
|
||||
for (i = 0; i < num_channels; i++) {
|
||||
params->channels[i].min_duration = cpu_to_le32(30000);
|
||||
params->channels[i].max_duration = cpu_to_le32(60000);
|
||||
memset(¶ms->channels[i].bssid_lsb, 0xff, 4);
|
||||
memset(¶ms->channels[i].bssid_msb, 0xff, 2);
|
||||
params->channels[i].early_termination = 0;
|
||||
params->channels[i].tx_power_att = 0;
|
||||
params->channels[i].channel = i + 1;
|
||||
memset(params->channels[i].pad, 0, 3);
|
||||
}
|
||||
|
||||
for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++)
|
||||
memset(¶ms->channels[i], 0,
|
||||
sizeof(struct basic_scan_channel_parameters));
|
||||
|
||||
if (len && ssid) {
|
||||
params->params.ssid_len = len;
|
||||
memcpy(params->params.ssid, ssid, len);
|
||||
} else {
|
||||
params->params.ssid_len = 0;
|
||||
memset(params->params.ssid, 0, 32);
|
||||
}
|
||||
|
||||
ret = wl1251_build_probe_req(wl, ssid, len);
|
||||
if (ret < 0) {
|
||||
wl1251_error("PROBE request template failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
|
||||
if (!trigger)
|
||||
goto out;
|
||||
|
||||
trigger->timeout = 0;
|
||||
|
||||
ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
|
||||
sizeof(*trigger));
|
||||
if (ret < 0) {
|
||||
wl1251_error("trigger scan to failed for hw scan");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
|
||||
|
||||
wl->scanning = true;
|
||||
|
||||
ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
|
||||
if (ret < 0)
|
||||
wl1251_error("SCAN failed");
|
||||
|
||||
wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
|
||||
|
||||
if (params->header.status != CMD_STATUS_SUCCESS) {
|
||||
wl1251_error("TEST command answer error: %d",
|
||||
params->header.status);
|
||||
wl->scanning = false;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(params);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct wl1251 *wl = hw->priv;
|
||||
int ret;
|
||||
u8 *ssid = NULL;
|
||||
struct sk_buff *skb;
|
||||
size_t ssid_len = 0;
|
||||
u8 *ssid = NULL;
|
||||
int ret;
|
||||
|
||||
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
|
||||
|
||||
|
@ -1057,12 +870,43 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->scanning) {
|
||||
wl1251_debug(DEBUG_SCAN, "scan already in progress");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1251_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
|
||||
skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
|
||||
req->ie, req->ie_len);
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data,
|
||||
skb->len);
|
||||
dev_kfree_skb(skb);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_cmd_trigger_scan_to(wl, 0);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
wl->scanning = true;
|
||||
|
||||
ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels,
|
||||
req->n_channels, WL1251_SCAN_NUM_PROBES);
|
||||
if (ret < 0) {
|
||||
wl->scanning = false;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
out_sleep:
|
||||
wl1251_ps_elp_sleep(wl);
|
||||
|
||||
out:
|
||||
|
@ -1101,7 +945,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
{
|
||||
enum wl1251_cmd_ps_mode mode;
|
||||
struct wl1251 *wl = hw->priv;
|
||||
struct sk_buff *beacon;
|
||||
struct sk_buff *beacon, *skb;
|
||||
int ret;
|
||||
|
||||
wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
|
||||
|
@ -1115,7 +959,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
if (changed & BSS_CHANGED_BSSID) {
|
||||
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
|
||||
ret = wl1251_build_null_data(wl);
|
||||
skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
|
||||
if (!skb)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA,
|
||||
skb->data, skb->len);
|
||||
dev_kfree_skb(skb);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_build_qos_null_data(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -1136,7 +990,14 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
wl->dtim_period);
|
||||
wl->aid = bss_conf->aid;
|
||||
|
||||
ret = wl1251_build_ps_poll(wl, wl->aid);
|
||||
skb = ieee80211_pspoll_get(wl->hw, wl->vif);
|
||||
if (!skb)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_cmd_template_set(wl, CMD_PS_POLL,
|
||||
skb->data,
|
||||
skb->len);
|
||||
dev_kfree_skb(skb);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
|
@ -1182,7 +1043,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
|
||||
if (ret < 0) {
|
||||
wl1251_warning("Set ctsprotect failed %d", ret);
|
||||
goto out;
|
||||
goto out_sleep;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1193,7 +1054,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
|
||||
|
@ -1202,13 +1063,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
dev_kfree_skb(beacon);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_join(wl, wl->bss_type, wl->beacon_int,
|
||||
wl->channel, wl->dtim_period);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
out_sleep:
|
||||
|
@ -1282,6 +1143,7 @@ static struct ieee80211_channel wl1251_channels[] = {
|
|||
static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
enum wl1251_acx_ps_scheme ps_scheme;
|
||||
struct wl1251 *wl = hw->priv;
|
||||
int ret;
|
||||
|
||||
|
@ -1299,10 +1161,14 @@ static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
|||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
if (params->uapsd)
|
||||
ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER;
|
||||
else
|
||||
ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY;
|
||||
|
||||
ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue),
|
||||
CHANNEL_TYPE_EDCF,
|
||||
wl1251_tx_get_queue(queue),
|
||||
WL1251_ACX_PS_SCHEME_LEGACY,
|
||||
wl1251_tx_get_queue(queue), ps_scheme,
|
||||
WL1251_ACX_ACK_POLICY_LEGACY);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
@ -1376,7 +1242,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
|
|||
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_BEACON_FILTER;
|
||||
IEEE80211_HW_BEACON_FILTER |
|
||||
IEEE80211_HW_SUPPORTS_UAPSD;
|
||||
|
||||
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
wl->hw->wiphy->max_scan_ssids = 1;
|
||||
|
|
|
@ -62,73 +62,10 @@
|
|||
#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008)
|
||||
#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c)
|
||||
#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
|
||||
/*
|
||||
* Interrupt registers.
|
||||
* 64 bit interrupt sources registers ws ced.
|
||||
* sme interupts were removed and new ones were added.
|
||||
* Order was changed.
|
||||
*/
|
||||
#define FIQ_MASK (REGISTERS_BASE + 0x0400)
|
||||
#define FIQ_MASK_L (REGISTERS_BASE + 0x0400)
|
||||
#define FIQ_MASK_H (REGISTERS_BASE + 0x0404)
|
||||
#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408)
|
||||
#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408)
|
||||
#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C)
|
||||
#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410)
|
||||
#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410)
|
||||
#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414)
|
||||
#define IRQ_MASK (REGISTERS_BASE + 0x0418)
|
||||
#define IRQ_MASK_L (REGISTERS_BASE + 0x0418)
|
||||
#define IRQ_MASK_H (REGISTERS_BASE + 0x041C)
|
||||
#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420)
|
||||
#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420)
|
||||
#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424)
|
||||
#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428)
|
||||
#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428)
|
||||
#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C)
|
||||
#define ECPU_MASK (REGISTERS_BASE + 0x0448)
|
||||
#define FIQ_STS_L (REGISTERS_BASE + 0x044C)
|
||||
#define FIQ_STS_H (REGISTERS_BASE + 0x0450)
|
||||
#define IRQ_STS_L (REGISTERS_BASE + 0x0454)
|
||||
#define IRQ_STS_H (REGISTERS_BASE + 0x0458)
|
||||
#define INT_STS_ND (REGISTERS_BASE + 0x0464)
|
||||
#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464)
|
||||
#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468)
|
||||
#define INT_STS_CLR (REGISTERS_BASE + 0x04B4)
|
||||
#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4)
|
||||
#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8)
|
||||
#define INT_ACK (REGISTERS_BASE + 0x046C)
|
||||
#define INT_ACK_L (REGISTERS_BASE + 0x046C)
|
||||
#define INT_ACK_H (REGISTERS_BASE + 0x0470)
|
||||
#define INT_TRIG (REGISTERS_BASE + 0x0474)
|
||||
#define INT_TRIG_L (REGISTERS_BASE + 0x0474)
|
||||
#define INT_TRIG_H (REGISTERS_BASE + 0x0478)
|
||||
#define HOST_STS_L (REGISTERS_BASE + 0x045C)
|
||||
#define HOST_STS_H (REGISTERS_BASE + 0x0460)
|
||||
#define HOST_MASK (REGISTERS_BASE + 0x0430)
|
||||
#define HOST_MASK_L (REGISTERS_BASE + 0x0430)
|
||||
#define HOST_MASK_H (REGISTERS_BASE + 0x0434)
|
||||
#define HOST_MASK_SET (REGISTERS_BASE + 0x0438)
|
||||
#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438)
|
||||
#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C)
|
||||
#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440)
|
||||
#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440)
|
||||
#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444)
|
||||
|
||||
#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
|
||||
#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
|
||||
|
||||
/* Host Interrupts*/
|
||||
#define HINT_MASK (REGISTERS_BASE + 0x0494)
|
||||
#define HINT_MASK_SET (REGISTERS_BASE + 0x0498)
|
||||
#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C)
|
||||
#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0)
|
||||
/*1150 spec calls this HINT_STS_RAW*/
|
||||
#define HINT_STS_ND (REGISTERS_BASE + 0x04B0)
|
||||
#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4)
|
||||
#define HINT_ACK (REGISTERS_BASE + 0x04A8)
|
||||
#define HINT_TRIG (REGISTERS_BASE + 0x04AC)
|
||||
|
||||
/*=============================================
|
||||
Host Interrupt Mask Register - 32bit (RW)
|
||||
------------------------------------------
|
||||
|
@ -432,16 +369,6 @@
|
|||
| CFG_RX_PRSP_EN)
|
||||
|
||||
|
||||
/*===============================================
|
||||
Phy regs
|
||||
===============================================*/
|
||||
#define ACX_PHY_ADDR_REG SBB_ADDR
|
||||
#define ACX_PHY_DATA_REG SBB_DATA
|
||||
#define ACX_PHY_CTRL_REG SBB_CTL
|
||||
#define ACX_PHY_REG_WR_MASK 0x00000001ul
|
||||
#define ACX_PHY_REG_RD_MASK 0x00000002ul
|
||||
|
||||
|
||||
/*===============================================
|
||||
EEPROM Read/Write Request 32bit RW
|
||||
------------------------------------------
|
||||
|
@ -511,28 +438,6 @@
|
|||
#define ACX_CONT_WIND_MIN_MASK 0x0000007f
|
||||
#define ACX_CONT_WIND_MAX 0x03ff0000
|
||||
|
||||
/*
|
||||
* Indirect slave register/memory registers
|
||||
* ----------------------------------------
|
||||
*/
|
||||
#define HW_SLAVE_REG_ADDR_REG 0x00000004
|
||||
#define HW_SLAVE_REG_DATA_REG 0x00000008
|
||||
#define HW_SLAVE_REG_CTRL_REG 0x0000000c
|
||||
|
||||
#define SLAVE_AUTO_INC 0x00010000
|
||||
#define SLAVE_NO_AUTO_INC 0x00000000
|
||||
#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000
|
||||
|
||||
#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR
|
||||
#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA
|
||||
#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL
|
||||
#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL
|
||||
|
||||
#define HW_FUNC_EVENT_INT_EN 0x8000
|
||||
#define HW_FUNC_EVENT_MASK_REG 0x00000034
|
||||
|
||||
#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP)
|
||||
|
||||
/*===============================================
|
||||
HI_CFG Interface Configuration Register Values
|
||||
------------------------------------------
|
||||
|
@ -647,10 +552,6 @@ b12-b0 - Supported Rate indicator bits as defined below.
|
|||
******************************************************************************/
|
||||
|
||||
|
||||
#define TNETW1251_CHIP_ID_PG1_0 0x07010101
|
||||
#define TNETW1251_CHIP_ID_PG1_1 0x07020101
|
||||
#define TNETW1251_CHIP_ID_PG1_2 0x07030101
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
Interrupt Trigger Register (Host -> WiLink)
|
||||
|
|
|
@ -397,8 +397,7 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
|
|||
/* poll for data ready */
|
||||
do {
|
||||
val = wl1271_spi_read32(wl, OCP_DATA_READ);
|
||||
timeout--;
|
||||
} while (!(val & OCP_READY_MASK) && timeout);
|
||||
} while (!(val & OCP_READY_MASK) && --timeout);
|
||||
|
||||
if (!timeout) {
|
||||
wl1271_warning("Top register access timed out.");
|
||||
|
|
|
@ -987,12 +987,13 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
|
|||
changed_flags &= SUPPORTED_FIF_FLAGS;
|
||||
*new_flags &= SUPPORTED_FIF_FLAGS;
|
||||
|
||||
/* changed_flags is always populated but this driver
|
||||
* doesn't support all FIF flags so its possible we don't
|
||||
* need to do anything */
|
||||
if (!changed_flags)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If multicast parameter (as returned by zd_op_prepare_multicast)
|
||||
* has changed, no bit in changed_flags is set. To handle this
|
||||
* situation, we do not return if changed_flags is 0. If we do so,
|
||||
* we will have some issue with IPv6 which uses multicast for link
|
||||
* layer address resolution.
|
||||
*/
|
||||
if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
|
||||
zd_mc_add_all(&hash);
|
||||
|
||||
|
|
|
@ -482,15 +482,6 @@ struct ieee80211_header_data {
|
|||
u16 seq_ctrl;
|
||||
};
|
||||
|
||||
struct ieee80211_hdr_3addr {
|
||||
u16 frame_ctl;
|
||||
u16 duration_id;
|
||||
u8 addr1[ETH_ALEN];
|
||||
u8 addr2[ETH_ALEN];
|
||||
u8 addr3[ETH_ALEN];
|
||||
u16 seq_ctl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_hdr_4addr {
|
||||
u16 frame_ctl;
|
||||
u16 duration_id;
|
||||
|
|
|
@ -203,7 +203,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
|
|||
|
||||
enqueue_mgmt(ieee,skb);
|
||||
}else{
|
||||
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
|
||||
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
|
||||
|
||||
if (ieee->seq_ctrl[0] == 0xFFF)
|
||||
ieee->seq_ctrl[0] = 0;
|
||||
|
@ -220,7 +220,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
|
|||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
|
||||
|
||||
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
|
||||
if (ieee->seq_ctrl[0] == 0xFFF)
|
||||
ieee->seq_ctrl[0] = 0;
|
||||
|
@ -246,7 +246,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
|
|||
|
||||
if(single){
|
||||
|
||||
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
|
||||
if (ieee->seq_ctrl[0] == 0xFFF)
|
||||
ieee->seq_ctrl[0] = 0;
|
||||
|
@ -259,7 +259,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
|
|||
|
||||
}else{
|
||||
|
||||
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
|
||||
if (ieee->seq_ctrl[0] == 0xFFF)
|
||||
ieee->seq_ctrl[0] = 0;
|
||||
|
@ -287,7 +287,7 @@ inline struct sk_buff *ieee80211_disassociate_skb(
|
|||
return NULL;
|
||||
|
||||
disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame));
|
||||
disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
|
||||
disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
|
||||
disass->header.duration_id = 0;
|
||||
|
||||
memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);
|
||||
|
@ -905,7 +905,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
|
|||
assoc = (struct ieee80211_assoc_response_frame *)
|
||||
skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
|
||||
|
||||
assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
|
||||
assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
|
||||
memcpy(assoc->header.addr1, dest,ETH_ALEN);
|
||||
memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
|
||||
|
@ -981,7 +981,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
|
|||
memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
|
||||
|
||||
hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
|
||||
(pwr ? IEEE80211_FCTL_PM:0));
|
||||
|
||||
|
@ -1084,7 +1084,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
|
|||
skb_put(skb, sizeof(struct ieee80211_assoc_request_frame));
|
||||
|
||||
|
||||
hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ;
|
||||
hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
|
||||
hdr->header.duration_id= 37; //FIXME
|
||||
memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
|
||||
memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
|
||||
|
@ -1786,11 +1786,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
|
|||
|
||||
tasklet_schedule(&ieee->ps_task);
|
||||
|
||||
if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP &&
|
||||
WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON)
|
||||
if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP &&
|
||||
WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON)
|
||||
ieee->last_rx_ps_time = jiffies;
|
||||
|
||||
switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
|
||||
switch (WLAN_FC_GET_STYPE(header->frame_control)) {
|
||||
|
||||
case IEEE80211_STYPE_ASSOC_RESP:
|
||||
case IEEE80211_STYPE_REASSOC_RESP:
|
||||
|
@ -2064,7 +2064,7 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
|
|||
|
||||
header = (struct ieee80211_hdr_3addr *) skb->data;
|
||||
|
||||
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
|
||||
|
||||
if (ieee->seq_ctrl[0] == 0xFFF)
|
||||
ieee->seq_ctrl[0] = 0;
|
||||
|
|
|
@ -1890,7 +1890,7 @@ rate)
|
|||
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
||||
int mode;
|
||||
struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
|
||||
short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS;
|
||||
short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
|
||||
unsigned long flags;
|
||||
int priority;
|
||||
|
||||
|
@ -2158,7 +2158,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
|
|||
TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
|
||||
}
|
||||
|
||||
if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment
|
||||
if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
|
||||
// ThisFrame-ACK.
|
||||
Duration = aSifsTime + AckTime;
|
||||
} else { // One or more fragments remained.
|
||||
|
|
|
@ -120,6 +120,24 @@
|
|||
#define IEEE80211_QOS_CTL_TID_MASK 0x000F
|
||||
#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007
|
||||
|
||||
/* U-APSD queue for WMM IEs sent by AP */
|
||||
#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7)
|
||||
|
||||
/* U-APSD queues for WMM IEs sent by STA */
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO (1<<0)
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI (1<<1)
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK (1<<2)
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE (1<<3)
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK 0x0f
|
||||
|
||||
/* U-APSD max SP length for WMM IEs sent by STA */
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0x00
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_2 0x01
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x02
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x03
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5
|
||||
|
||||
struct ieee80211_hdr {
|
||||
__le16 frame_control;
|
||||
__le16 duration_id;
|
||||
|
@ -130,6 +148,25 @@ struct ieee80211_hdr {
|
|||
u8 addr4[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_hdr_3addr {
|
||||
__le16 frame_control;
|
||||
__le16 duration_id;
|
||||
u8 addr1[6];
|
||||
u8 addr2[6];
|
||||
u8 addr3[6];
|
||||
__le16 seq_ctrl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_qos_hdr {
|
||||
__le16 frame_control;
|
||||
__le16 duration_id;
|
||||
u8 addr1[6];
|
||||
u8 addr2[6];
|
||||
u8 addr3[6];
|
||||
__le16 seq_ctrl;
|
||||
__le16 qos_ctrl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
|
|
|
@ -295,6 +295,10 @@
|
|||
* This command is also used as an event to notify when a requested
|
||||
* remain-on-channel duration has expired.
|
||||
*
|
||||
* @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
|
||||
* rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
|
||||
* and @NL80211_ATTR_TX_RATES the set of allowed rates.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -381,6 +385,8 @@ enum nl80211_commands {
|
|||
NL80211_CMD_REMAIN_ON_CHANNEL,
|
||||
NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
|
||||
|
||||
NL80211_CMD_SET_TX_BITRATE_MASK,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -430,6 +436,8 @@ enum nl80211_commands {
|
|||
* @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
|
||||
* larger than or equal to this use RTS/CTS handshake); allowed range:
|
||||
* 0..65536, disable with (u32)-1; dot11RTSThreshold; u32
|
||||
* @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
|
||||
* section 7.3.2.9; dot11CoverageClass; u8
|
||||
*
|
||||
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
|
||||
* @NL80211_ATTR_IFNAME: network interface name
|
||||
|
@ -638,6 +646,13 @@ enum nl80211_commands {
|
|||
*
|
||||
* @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
|
||||
*
|
||||
* @NL80211_ATTR_TX_RATES: Nested set of attributes
|
||||
* (enum nl80211_tx_rate_attributes) describing TX rates per band. The
|
||||
* enum nl80211_band value is used as the index (nla_type() of the nested
|
||||
* data. If a band is not included, it will be configured to allow all
|
||||
* rates based on negotiated supported rates information. This attribute
|
||||
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -779,6 +794,10 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_COOKIE,
|
||||
|
||||
NL80211_ATTR_WIPHY_COVERAGE_CLASS,
|
||||
|
||||
NL80211_ATTR_TX_RATES,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -1359,13 +1378,20 @@ enum nl80211_channel_type {
|
|||
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
|
||||
* @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
|
||||
* @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
|
||||
* raw information elements from the probe response/beacon (bin)
|
||||
* raw information elements from the probe response/beacon (bin);
|
||||
* if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
|
||||
* from a Probe Response frame; otherwise they are from a Beacon frame.
|
||||
* However, if the driver does not indicate the source of the IEs, these
|
||||
* IEs may be from either frame subtype.
|
||||
* @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
|
||||
* in mBm (100 * dBm) (s32)
|
||||
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
|
||||
* in unspecified units, scaled to 0..100 (u8)
|
||||
* @NL80211_BSS_STATUS: status, if this BSS is "used"
|
||||
* @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
|
||||
* @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
|
||||
* elements from a Beacon frame (bin); not present if no Beacon frame has
|
||||
* yet been received
|
||||
* @__NL80211_BSS_AFTER_LAST: internal
|
||||
* @NL80211_BSS_MAX: highest BSS attribute
|
||||
*/
|
||||
|
@ -1381,6 +1407,7 @@ enum nl80211_bss {
|
|||
NL80211_BSS_SIGNAL_UNSPEC,
|
||||
NL80211_BSS_STATUS,
|
||||
NL80211_BSS_SEEN_MS_AGO,
|
||||
NL80211_BSS_BEACON_IES,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_BSS_AFTER_LAST,
|
||||
|
@ -1478,4 +1505,33 @@ enum nl80211_key_attributes {
|
|||
NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_tx_rate_attributes - TX rate set attributes
|
||||
* @__NL80211_TXRATE_INVALID: invalid
|
||||
* @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
|
||||
* in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
|
||||
* 1 = 500 kbps) but without the IE length restriction (at most
|
||||
* %NL80211_MAX_SUPP_RATES in a single array).
|
||||
* @__NL80211_TXRATE_AFTER_LAST: internal
|
||||
* @NL80211_TXRATE_MAX: highest TX rate attribute
|
||||
*/
|
||||
enum nl80211_tx_rate_attributes {
|
||||
__NL80211_TXRATE_INVALID,
|
||||
NL80211_TXRATE_LEGACY,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_TXRATE_AFTER_LAST,
|
||||
NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_band - Frequency band
|
||||
* @NL80211_BAND_2GHZ - 2.4 GHz ISM band
|
||||
* @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz)
|
||||
*/
|
||||
enum nl80211_band {
|
||||
NL80211_BAND_2GHZ,
|
||||
NL80211_BAND_5GHZ,
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
* @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
|
||||
*/
|
||||
enum ieee80211_band {
|
||||
IEEE80211_BAND_2GHZ,
|
||||
IEEE80211_BAND_5GHZ,
|
||||
IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
|
||||
IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ,
|
||||
|
||||
/* keep last */
|
||||
IEEE80211_NUM_BANDS
|
||||
|
@ -626,8 +626,14 @@ enum cfg80211_signal_type {
|
|||
* @beacon_interval: the beacon interval as from the frame
|
||||
* @capability: the capability field in host byte order
|
||||
* @information_elements: the information elements (Note that there
|
||||
* is no guarantee that these are well-formed!)
|
||||
* is no guarantee that these are well-formed!); this is a pointer to
|
||||
* either the beacon_ies or proberesp_ies depending on whether Probe
|
||||
* Response frame has been received
|
||||
* @len_information_elements: total length of the information elements
|
||||
* @beacon_ies: the information elements from the last Beacon frame
|
||||
* @len_beacon_ies: total length of the beacon_ies
|
||||
* @proberesp_ies: the information elements from the last Probe Response frame
|
||||
* @len_proberesp_ies: total length of the proberesp_ies
|
||||
* @signal: signal strength value (type depends on the wiphy's signal_type)
|
||||
* @free_priv: function pointer to free private data
|
||||
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
|
||||
|
@ -641,6 +647,10 @@ struct cfg80211_bss {
|
|||
u16 capability;
|
||||
u8 *information_elements;
|
||||
size_t len_information_elements;
|
||||
u8 *beacon_ies;
|
||||
size_t len_beacon_ies;
|
||||
u8 *proberesp_ies;
|
||||
size_t len_proberesp_ies;
|
||||
|
||||
s32 signal;
|
||||
|
||||
|
@ -837,6 +847,7 @@ enum wiphy_params_flags {
|
|||
WIPHY_PARAM_RETRY_LONG = 1 << 1,
|
||||
WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2,
|
||||
WIPHY_PARAM_RTS_THRESHOLD = 1 << 3,
|
||||
WIPHY_PARAM_COVERAGE_CLASS = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -856,20 +867,11 @@ enum tx_power_setting {
|
|||
* cfg80211_bitrate_mask - masks for bitrate control
|
||||
*/
|
||||
struct cfg80211_bitrate_mask {
|
||||
/*
|
||||
* As discussed in Berlin, this struct really
|
||||
* should look like this:
|
||||
|
||||
struct {
|
||||
u32 legacy;
|
||||
u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
|
||||
/* TODO: add support for masking MCS rates; e.g.: */
|
||||
/* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */
|
||||
} control[IEEE80211_NUM_BANDS];
|
||||
|
||||
* Since we can always fix in-kernel users, let's keep
|
||||
* it simpler for now:
|
||||
*/
|
||||
u32 fixed; /* fixed bitrate, 0 == not fixed */
|
||||
u32 maxrate; /* in kbps, 0 == no limit */
|
||||
};
|
||||
/**
|
||||
* struct cfg80211_pmksa - PMK Security Association
|
||||
|
@ -1236,6 +1238,7 @@ struct wiphy {
|
|||
u8 retry_long;
|
||||
u32 frag_threshold;
|
||||
u32 rts_threshold;
|
||||
u8 coverage_class;
|
||||
|
||||
char fw_version[ETHTOOL_BUSINFO_LEN];
|
||||
u32 hw_version;
|
||||
|
|
|
@ -107,12 +107,14 @@ enum ieee80211_max_queues {
|
|||
* 2^n-1 in the range 1..32767]
|
||||
* @cw_max: maximum contention window [like @cw_min]
|
||||
* @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
|
||||
* @uapsd: is U-APSD mode enabled for the queue
|
||||
*/
|
||||
struct ieee80211_tx_queue_params {
|
||||
u16 txop;
|
||||
u16 cw_min;
|
||||
u16 cw_max;
|
||||
u8 aifs;
|
||||
bool uapsd;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -255,9 +257,6 @@ struct ieee80211_bss_conf {
|
|||
* @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
|
||||
* set by rate control algorithms to indicate probe rate, will
|
||||
* be cleared for fragmented frames (except on the last fragment)
|
||||
* @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or
|
||||
* set this flag in the driver; indicates that the rate control
|
||||
* algorithm was used and should be notified of TX status
|
||||
* @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
|
||||
* used to indicate that a pending frame requires TX processing before
|
||||
* it can be sent out.
|
||||
|
@ -287,7 +286,6 @@ enum mac80211_tx_control_flags {
|
|||
IEEE80211_TX_STAT_AMPDU = BIT(10),
|
||||
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
|
||||
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
|
||||
IEEE80211_TX_INTFL_RCALGO = BIT(13),
|
||||
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
|
||||
IEEE80211_TX_INTFL_RETRIED = BIT(15),
|
||||
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
|
||||
|
@ -571,7 +569,13 @@ struct ieee80211_rx_status {
|
|||
* @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this
|
||||
* to determine for example whether to calculate timestamps for packets
|
||||
* or not, do not use instead of filter flags!
|
||||
* @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only)
|
||||
* @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only).
|
||||
* This is the power save mode defined by IEEE 802.11-2007 section 11.2,
|
||||
* meaning that the hardware still wakes up for beacons, is able to
|
||||
* transmit frames and receive the possible acknowledgment frames.
|
||||
* Not to be confused with hardware specific wakeup/sleep states,
|
||||
* driver is responsible for that. See the section "Powersave support"
|
||||
* for more.
|
||||
* @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set
|
||||
* the driver should be prepared to handle configuration requests but
|
||||
* may turn the device off as much as possible. Typically, this flag will
|
||||
|
@ -611,7 +615,11 @@ enum ieee80211_conf_changed {
|
|||
/**
|
||||
* enum ieee80211_smps_mode - spatial multiplexing power save mode
|
||||
*
|
||||
* @
|
||||
* @IEEE80211_SMPS_AUTOMATIC: automatic
|
||||
* @IEEE80211_SMPS_OFF: off
|
||||
* @IEEE80211_SMPS_STATIC: static
|
||||
* @IEEE80211_SMPS_DYNAMIC: dynamic
|
||||
* @IEEE80211_SMPS_NUM_MODES: internal, don't use
|
||||
*/
|
||||
enum ieee80211_smps_mode {
|
||||
IEEE80211_SMPS_AUTOMATIC,
|
||||
|
@ -933,6 +941,11 @@ enum ieee80211_tkip_key_type {
|
|||
* Hardware supports dynamic spatial multiplexing powersave,
|
||||
* ie. can turn off all but one chain and then wake the rest
|
||||
* up as required after, for example, rts/cts handshake.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_UAPSD:
|
||||
* Hardware supports Unscheduled Automatic Power Save Delivery
|
||||
* (U-APSD) in managed mode. The mode is configured with
|
||||
* conf_tx() operation.
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
|
||||
|
@ -952,6 +965,7 @@ enum ieee80211_hw_flags {
|
|||
IEEE80211_HW_BEACON_FILTER = 1<<14,
|
||||
IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15,
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16,
|
||||
IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1130,18 +1144,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
|
|||
*
|
||||
* mac80211 has support for various powersave implementations.
|
||||
*
|
||||
* First, it can support hardware that handles all powersaving by
|
||||
* itself, such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS
|
||||
* hardware flag. In that case, it will be told about the desired
|
||||
* powersave mode depending on the association status, and the driver
|
||||
* must take care of sending nullfunc frames when necessary, i.e. when
|
||||
* entering and leaving powersave mode. The driver is required to look at
|
||||
* the AID in beacons and signal to the AP that it woke up when it finds
|
||||
* traffic directed to it. This mode supports dynamic PS by simply
|
||||
* enabling/disabling PS.
|
||||
* First, it can support hardware that handles all powersaving by itself,
|
||||
* such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware
|
||||
* flag. In that case, it will be told about the desired powersave mode
|
||||
* with the %IEEE80211_CONF_PS flag depending on the association status.
|
||||
* The hardware must take care of sending nullfunc frames when necessary,
|
||||
* i.e. when entering and leaving powersave mode. The hardware is required
|
||||
* to look at the AID in beacons and signal to the AP that it woke up when
|
||||
* it finds traffic directed to it.
|
||||
*
|
||||
* Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
|
||||
* flag to indicate that it can support dynamic PS mode itself (see below).
|
||||
* %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in
|
||||
* IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
|
||||
* with hardware wakeup and sleep states. Driver is responsible for waking
|
||||
* up the hardware before issueing commands to the hardware and putting it
|
||||
* back to sleep at approriate times.
|
||||
*
|
||||
* When PS is enabled, hardware needs to wakeup for beacons and receive the
|
||||
* buffered multicast/broadcast frames after the beacon. Also it must be
|
||||
* possible to send frames and receive the acknowledment frame.
|
||||
*
|
||||
* Other hardware designs cannot send nullfunc frames by themselves and also
|
||||
* need software support for parsing the TIM bitmap. This is also supported
|
||||
|
@ -1149,14 +1169,35 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
|
|||
* %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still
|
||||
* required to pass up beacons. The hardware is still required to handle
|
||||
* waking up for multicast traffic; if it cannot the driver must handle that
|
||||
* as best as it can, mac80211 is too slow.
|
||||
* as best as it can, mac80211 is too slow to do that.
|
||||
*
|
||||
* Dynamic powersave mode is an extension to normal powersave mode in which
|
||||
* the hardware stays awake for a user-specified period of time after sending
|
||||
* a frame so that reply frames need not be buffered and therefore delayed
|
||||
* to the next wakeup. This can either be supported by hardware, in which case
|
||||
* the driver needs to look at the @dynamic_ps_timeout hardware configuration
|
||||
* value, or by the stack if all nullfunc handling is in the stack.
|
||||
* Dynamic powersave is an extension to normal powersave in which the
|
||||
* hardware stays awake for a user-specified period of time after sending a
|
||||
* frame so that reply frames need not be buffered and therefore delayed to
|
||||
* the next wakeup. It's compromise of getting good enough latency when
|
||||
* there's data traffic and still saving significantly power in idle
|
||||
* periods.
|
||||
*
|
||||
* Dynamic powersave is supported by simply mac80211 enabling and disabling
|
||||
* PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS
|
||||
* flag and mac80211 will handle everything automatically. Additionally,
|
||||
* hardware having support for the dynamic PS feature may set the
|
||||
* %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support
|
||||
* dynamic PS mode itself. The driver needs to look at the
|
||||
* @dynamic_ps_timeout hardware configuration value and use it that value
|
||||
* whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable
|
||||
* dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
|
||||
* enabled whenever user has enabled powersave.
|
||||
*
|
||||
* Driver informs U-APSD client support by enabling
|
||||
* %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
|
||||
* uapsd paramater in conf_tx() operation. Hardware needs to send the QoS
|
||||
* Nullfunc frames and stay awake until the service period has ended. To
|
||||
* utilize U-APSD, dynamic powersave is disabled for voip AC and all frames
|
||||
* from that AC are transmitted with powersave enabled.
|
||||
*
|
||||
* Note: U-APSD client mode is not yet supported with
|
||||
* %IEEE80211_HW_PS_NULLFUNC_STACK.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -1533,6 +1574,10 @@ enum ieee80211_ampdu_mlme_action {
|
|||
* and need to call wiphy_rfkill_set_hw_state() in the callback.
|
||||
* The callback can sleep.
|
||||
*
|
||||
* @set_coverage_class: Set slot time for given coverage class as specified
|
||||
* in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout
|
||||
* accordingly. This callback is not required and may sleep.
|
||||
*
|
||||
* @testmode_cmd: Implement a cfg80211 test mode command.
|
||||
* The callback can sleep.
|
||||
*
|
||||
|
@ -1592,6 +1637,7 @@ struct ieee80211_ops {
|
|||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
|
||||
void (*rfkill_poll)(struct ieee80211_hw *hw);
|
||||
void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
|
||||
#endif
|
||||
|
@ -1873,6 +1919,53 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
return ieee80211_beacon_get_tim(hw, vif, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_pspoll_get - retrieve a PS Poll template
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
*
|
||||
* Creates a PS Poll a template which can, for example, uploaded to
|
||||
* hardware. The template must be updated after association so that correct
|
||||
* AID, BSSID and MAC address is used.
|
||||
*
|
||||
* Note: Caller (or hardware) is responsible for setting the
|
||||
* &IEEE80211_FCTL_PM bit.
|
||||
*/
|
||||
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_nullfunc_get - retrieve a nullfunc template
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
*
|
||||
* Creates a Nullfunc template which can, for example, uploaded to
|
||||
* hardware. The template must be updated after association so that correct
|
||||
* BSSID and address is used.
|
||||
*
|
||||
* Note: Caller (or hardware) is responsible for setting the
|
||||
* &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields.
|
||||
*/
|
||||
struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_probereq_get - retrieve a Probe Request template
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
* @ssid: SSID buffer
|
||||
* @ssid_len: length of SSID
|
||||
* @ie: buffer containing all IEs except SSID for the template
|
||||
* @ie_len: length of the IE buffer
|
||||
*
|
||||
* Creates a Probe Request template which can, for example, be uploaded to
|
||||
* hardware.
|
||||
*/
|
||||
struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len);
|
||||
|
||||
/**
|
||||
* ieee80211_rts_get - RTS frame generation function
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
|
@ -2292,8 +2385,12 @@ enum rate_control_changed {
|
|||
* @short_preamble: whether mac80211 will request short-preamble transmission
|
||||
* if the selected rate supports it
|
||||
* @max_rate_idx: user-requested maximum rate (not MCS for now)
|
||||
* (deprecated; this will be removed once drivers get updated to use
|
||||
* rate_idx_mask)
|
||||
* @rate_idx_mask: user-requested rate mask (not MCS for now)
|
||||
* @skb: the skb that will be transmitted, the control information in it needs
|
||||
* to be filled in
|
||||
* @ap: whether this frame is sent out in AP mode
|
||||
*/
|
||||
struct ieee80211_tx_rate_control {
|
||||
struct ieee80211_hw *hw;
|
||||
|
@ -2303,6 +2400,8 @@ struct ieee80211_tx_rate_control {
|
|||
struct ieee80211_tx_rate reported_rate;
|
||||
bool rts, short_preamble;
|
||||
u8 max_rate_idx;
|
||||
u32 rate_idx_mask;
|
||||
bool ap;
|
||||
};
|
||||
|
||||
struct rate_control_ops {
|
||||
|
|
|
@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data)
|
|||
|
||||
/* check if the TID waits for addBA response */
|
||||
spin_lock_bh(&sta->lock);
|
||||
if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) !=
|
||||
if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK |
|
||||
HT_AGG_STATE_REQ_STOP_BA_MSK)) !=
|
||||
HT_ADDBA_REQUESTED_MSK) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
|
@ -301,7 +302,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
|
|||
* call back right away, it must see that the flow has begun */
|
||||
*state |= HT_ADDBA_REQUESTED_MSK;
|
||||
|
||||
start_seq_num = sta->tid_seq[tid];
|
||||
start_seq_num = sta->tid_seq[tid] >> 4;
|
||||
|
||||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
||||
pubsta, tid, &start_seq_num);
|
||||
|
|
|
@ -148,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
rcu_read_lock();
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata, mac_addr);
|
||||
sta = sta_info_get_bss(sdata, mac_addr);
|
||||
if (!sta) {
|
||||
ieee80211_key_free(key);
|
||||
err = -ENOENT;
|
||||
|
@ -179,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (mac_addr) {
|
||||
ret = -ENOENT;
|
||||
|
||||
sta = sta_info_get(sdata, mac_addr);
|
||||
sta = sta_info_get_bss(sdata, mac_addr);
|
||||
if (!sta)
|
||||
goto out_unlock;
|
||||
|
||||
|
@ -226,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
rcu_read_lock();
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata, mac_addr);
|
||||
sta = sta_info_get_bss(sdata, mac_addr);
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
|
@ -419,7 +419,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(sdata, mac);
|
||||
sta = sta_info_get_bss(sdata, mac);
|
||||
if (sta) {
|
||||
ret = 0;
|
||||
sta_set_sinfo(sta, sinfo);
|
||||
|
@ -775,7 +775,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (mac) {
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(sdata, mac);
|
||||
sta = sta_info_get_bss(sdata, mac);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
|
@ -803,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(sdata, mac);
|
||||
sta = sta_info_get_bss(sdata, mac);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
|
@ -1085,6 +1085,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
|
|||
params->use_short_preamble;
|
||||
changed |= BSS_CHANGED_ERP_PREAMBLE;
|
||||
}
|
||||
|
||||
if (!sdata->vif.bss_conf.use_short_slot &&
|
||||
sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) {
|
||||
sdata->vif.bss_conf.use_short_slot = true;
|
||||
changed |= BSS_CHANGED_ERP_SLOT;
|
||||
}
|
||||
|
||||
if (params->use_short_slot_time >= 0) {
|
||||
sdata->vif.bss_conf.use_short_slot =
|
||||
params->use_short_slot_time;
|
||||
|
@ -1128,6 +1135,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
|||
p.cw_max = params->cwmax;
|
||||
p.cw_min = params->cwmin;
|
||||
p.txop = params->txop;
|
||||
|
||||
/*
|
||||
* Setting tx queue params disables u-apsd because it's only
|
||||
* called in master mode.
|
||||
*/
|
||||
p.uapsd = false;
|
||||
|
||||
if (drv_conf_tx(local, params->queue, &p)) {
|
||||
printk(KERN_DEBUG "%s: failed to set TX queue "
|
||||
"parameters for queue %d\n",
|
||||
|
@ -1230,6 +1244,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
|||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
int err;
|
||||
|
||||
if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
|
||||
err = drv_set_coverage_class(local, wiphy->coverage_class);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
|
||||
err = drv_set_rts_threshold(local, wiphy->rts_threshold);
|
||||
|
||||
|
@ -1399,8 +1420,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
int i;
|
||||
u32 target_rate;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
/*
|
||||
* This _could_ be supported by providing a hook for
|
||||
|
@ -1410,35 +1429,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|||
if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
/*
|
||||
* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
|
||||
* target_rate = X, rate->fixed = 1 means only rate X
|
||||
* target_rate = X, rate->fixed = 0 means all rates <= X
|
||||
*/
|
||||
sdata->max_ratectrl_rateidx = -1;
|
||||
sdata->force_unicast_rateidx = -1;
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
|
||||
sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
|
||||
|
||||
if (mask->fixed)
|
||||
target_rate = mask->fixed / 100;
|
||||
else if (mask->maxrate)
|
||||
target_rate = mask->maxrate / 100;
|
||||
else
|
||||
return 0;
|
||||
|
||||
for (i = 0; i< sband->n_bitrates; i++) {
|
||||
if (target_rate != sband->bitrates[i].bitrate)
|
||||
continue;
|
||||
|
||||
/* requested bitrate found */
|
||||
sdata->max_ratectrl_rateidx = i;
|
||||
if (mask->fixed)
|
||||
sdata->force_unicast_rateidx = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_remain_on_channel(struct wiphy *wiphy,
|
||||
|
|
|
@ -158,6 +158,98 @@ static const struct file_operations noack_ops = {
|
|||
.open = mac80211_open_file_generic
|
||||
};
|
||||
|
||||
static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
int res;
|
||||
char buf[10];
|
||||
|
||||
res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
|
||||
}
|
||||
|
||||
static ssize_t uapsd_queues_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
unsigned long val;
|
||||
char buf[10];
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
buf[len] = '\0';
|
||||
|
||||
ret = strict_strtoul(buf, 0, &val);
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
|
||||
return -ERANGE;
|
||||
|
||||
local->uapsd_queues = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations uapsd_queues_ops = {
|
||||
.read = uapsd_queues_read,
|
||||
.write = uapsd_queues_write,
|
||||
.open = mac80211_open_file_generic
|
||||
};
|
||||
|
||||
static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
int res;
|
||||
char buf[10];
|
||||
|
||||
res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
|
||||
}
|
||||
|
||||
static ssize_t uapsd_max_sp_len_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
unsigned long val;
|
||||
char buf[10];
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
buf[len] = '\0';
|
||||
|
||||
ret = strict_strtoul(buf, 0, &val);
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
|
||||
return -ERANGE;
|
||||
|
||||
local->uapsd_max_sp_len = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations uapsd_max_sp_len_ops = {
|
||||
.read = uapsd_max_sp_len_read,
|
||||
.write = uapsd_max_sp_len_write,
|
||||
.open = mac80211_open_file_generic
|
||||
};
|
||||
|
||||
static ssize_t queues_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -314,6 +406,8 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
|||
DEBUGFS_ADD(queues);
|
||||
DEBUGFS_ADD_MODE(reset, 0200);
|
||||
DEBUGFS_ADD(noack);
|
||||
DEBUGFS_ADD(uapsd_queues);
|
||||
DEBUGFS_ADD(uapsd_max_sp_len);
|
||||
|
||||
statsd = debugfs_create_dir("statistics", phyd);
|
||||
|
||||
|
|
|
@ -127,8 +127,10 @@ __IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
|
|||
|
||||
/* common attributes */
|
||||
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
||||
IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
|
||||
IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
|
||||
HEX);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
|
||||
HEX);
|
||||
|
||||
/* STA attributes */
|
||||
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
||||
|
@ -253,7 +255,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
|
|||
#endif
|
||||
|
||||
|
||||
#define DEBUGFS_ADD(name, type) \
|
||||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
|
||||
sdata, &name##_ops);
|
||||
|
||||
|
@ -263,40 +265,40 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
|
|||
|
||||
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, sta);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, sta);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, sta);
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
|
||||
DEBUGFS_ADD(bssid, sta);
|
||||
DEBUGFS_ADD(aid, sta);
|
||||
DEBUGFS_ADD(bssid);
|
||||
DEBUGFS_ADD(aid);
|
||||
DEBUGFS_ADD_MODE(smps, 0600);
|
||||
}
|
||||
|
||||
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, ap);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, ap);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
|
||||
DEBUGFS_ADD(num_sta_ps, ap);
|
||||
DEBUGFS_ADD(dtim_count, ap);
|
||||
DEBUGFS_ADD(num_buffered_multicast, ap);
|
||||
DEBUGFS_ADD(num_sta_ps);
|
||||
DEBUGFS_ADD(dtim_count);
|
||||
DEBUGFS_ADD(num_buffered_multicast);
|
||||
}
|
||||
|
||||
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, wds);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, wds);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, wds);
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
|
||||
DEBUGFS_ADD(peer, wds);
|
||||
DEBUGFS_ADD(peer);
|
||||
}
|
||||
|
||||
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted, vlan);
|
||||
DEBUGFS_ADD(force_unicast_rateidx, vlan);
|
||||
DEBUGFS_ADD(max_ratectrl_rateidx, vlan);
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
}
|
||||
|
||||
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
|
||||
|
|
|
@ -214,6 +214,21 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int drv_set_coverage_class(struct ieee80211_local *local,
|
||||
u8 value)
|
||||
{
|
||||
int ret = 0;
|
||||
might_sleep();
|
||||
|
||||
if (local->ops->set_coverage_class)
|
||||
local->ops->set_coverage_class(&local->hw, value);
|
||||
else
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
trace_drv_set_coverage_class(local, value, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_sta_notify(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum sta_notify_cmd cmd,
|
||||
|
|
|
@ -491,6 +491,29 @@ TRACE_EVENT(drv_set_rts_threshold,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_set_coverage_class,
|
||||
TP_PROTO(struct ieee80211_local *local, u8 value, int ret),
|
||||
|
||||
TP_ARGS(local, value, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
__field(u8, value)
|
||||
__field(int, ret)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
__entry->ret = ret;
|
||||
__entry->value = value;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT " value:%d ret:%d",
|
||||
LOCAL_PR_ARG, __entry->value, __entry->ret
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_sta_notify,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -58,6 +58,15 @@ struct ieee80211_local;
|
|||
|
||||
#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024))
|
||||
|
||||
#define IEEE80211_DEFAULT_UAPSD_QUEUES \
|
||||
(IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \
|
||||
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \
|
||||
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \
|
||||
IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
|
||||
#define IEEE80211_DEFAULT_MAX_SP_LEN \
|
||||
IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
|
||||
|
||||
struct ieee80211_fragment_entry {
|
||||
unsigned long first_frag_time;
|
||||
unsigned int seq;
|
||||
|
@ -78,6 +87,7 @@ struct ieee80211_bss {
|
|||
u8 dtim_period;
|
||||
|
||||
bool wmm_used;
|
||||
bool uapsd_supported;
|
||||
|
||||
unsigned long last_probe_resp;
|
||||
|
||||
|
@ -285,7 +295,7 @@ struct ieee80211_work {
|
|||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
bool wmm_used, use_11n;
|
||||
bool wmm_used, use_11n, uapsd_used;
|
||||
} assoc;
|
||||
struct {
|
||||
u32 duration;
|
||||
|
@ -306,6 +316,7 @@ enum ieee80211_sta_flags {
|
|||
IEEE80211_STA_DISABLE_11N = BIT(4),
|
||||
IEEE80211_STA_CSA_RECEIVED = BIT(5),
|
||||
IEEE80211_STA_MFP_ENABLED = BIT(6),
|
||||
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
|
||||
};
|
||||
|
||||
struct ieee80211_if_managed {
|
||||
|
@ -494,8 +505,8 @@ struct ieee80211_sub_if_data {
|
|||
*/
|
||||
struct ieee80211_if_ap *bss;
|
||||
|
||||
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
||||
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
||||
/* bitmap of allowed (non-MCS) rate indexes for rate control */
|
||||
u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
|
||||
|
||||
union {
|
||||
struct ieee80211_if_ap ap;
|
||||
|
@ -797,6 +808,20 @@ struct ieee80211_local {
|
|||
int wifi_wme_noack_test;
|
||||
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
|
||||
|
||||
/*
|
||||
* Bitmask of enabled u-apsd queues,
|
||||
* IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association
|
||||
* to take effect.
|
||||
*/
|
||||
unsigned int uapsd_queues;
|
||||
|
||||
/*
|
||||
* Maximum number of buffered frames AP can deliver during a
|
||||
* service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar.
|
||||
* Needs a new association to take effect.
|
||||
*/
|
||||
unsigned int uapsd_max_sp_len;
|
||||
|
||||
bool pspolling;
|
||||
bool offchannel_ps_enabled;
|
||||
/*
|
||||
|
|
|
@ -15,12 +15,14 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "sta_info.h"
|
||||
#include "debugfs_netdev.h"
|
||||
#include "mesh.h"
|
||||
#include "led.h"
|
||||
#include "driver-ops.h"
|
||||
#include "wme.h"
|
||||
|
||||
/**
|
||||
* DOC: Interface list locking
|
||||
|
@ -63,15 +65,16 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
|
|||
static int ieee80211_change_mac(struct net_device *dev, void *addr)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sockaddr *sa = addr;
|
||||
int ret;
|
||||
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
return -EBUSY;
|
||||
|
||||
ret = eth_mac_addr(dev, addr);
|
||||
ret = eth_mac_addr(dev, sa);
|
||||
|
||||
if (ret == 0)
|
||||
memcpy(sdata->vif.addr, addr, ETH_ALEN);
|
||||
memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -326,7 +329,7 @@ static int ieee80211_open(struct net_device *dev)
|
|||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
|
||||
|
||||
netif_start_queue(dev);
|
||||
netif_tx_start_all_queues(dev);
|
||||
|
||||
return 0;
|
||||
err_del_interface:
|
||||
|
@ -354,7 +357,7 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
/*
|
||||
* Stop TX on this interface first.
|
||||
*/
|
||||
netif_stop_queue(dev);
|
||||
netif_tx_stop_all_queues(dev);
|
||||
|
||||
/*
|
||||
* Purge work for this interface.
|
||||
|
@ -657,6 +660,12 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
|
|||
WARN_ON(flushed);
|
||||
}
|
||||
|
||||
static u16 ieee80211_netdev_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
|
||||
}
|
||||
|
||||
static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
.ndo_open = ieee80211_open,
|
||||
.ndo_stop = ieee80211_stop,
|
||||
|
@ -665,8 +674,34 @@ static const struct net_device_ops ieee80211_dataif_ops = {
|
|||
.ndo_set_multicast_list = ieee80211_set_multicast_list,
|
||||
.ndo_change_mtu = ieee80211_change_mtu,
|
||||
.ndo_set_mac_address = ieee80211_change_mac,
|
||||
.ndo_select_queue = ieee80211_netdev_select_queue,
|
||||
};
|
||||
|
||||
static u16 ieee80211_monitor_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_radiotap_header *rtap = (void *)skb->data;
|
||||
|
||||
if (local->hw.queues < 4)
|
||||
return 0;
|
||||
|
||||
if (skb->len < 4 ||
|
||||
skb->len < rtap->it_len + 2 /* frame control */)
|
||||
return 0; /* doesn't matter, frame will be dropped */
|
||||
|
||||
hdr = (void *)((u8 *)skb->data + rtap->it_len);
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control)) {
|
||||
skb->priority = 7;
|
||||
return ieee802_1d_to_ac[skb->priority];
|
||||
}
|
||||
|
||||
return ieee80211_downgrade_queue(local, skb);
|
||||
}
|
||||
|
||||
static const struct net_device_ops ieee80211_monitorif_ops = {
|
||||
.ndo_open = ieee80211_open,
|
||||
.ndo_stop = ieee80211_stop,
|
||||
|
@ -675,6 +710,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
|
|||
.ndo_set_multicast_list = ieee80211_set_multicast_list,
|
||||
.ndo_change_mtu = ieee80211_change_mtu,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_select_queue = ieee80211_monitor_select_queue,
|
||||
};
|
||||
|
||||
static void ieee80211_if_setup(struct net_device *dev)
|
||||
|
@ -781,8 +817,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
|
||||
name, ieee80211_if_setup);
|
||||
ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size,
|
||||
name, ieee80211_if_setup, local->hw.queues);
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
|
||||
|
@ -820,8 +856,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
|
||||
INIT_LIST_HEAD(&sdata->key_list);
|
||||
|
||||
sdata->force_unicast_rateidx = -1;
|
||||
sdata->max_ratectrl_rateidx = -1;
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
sband = local->hw.wiphy->bands[i];
|
||||
sdata->rc_rateidx_mask[i] =
|
||||
sband ? (1 << sband->n_bitrates) - 1 : 0;
|
||||
}
|
||||
|
||||
/* setup type-dependent data */
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/pm_qos_params.h>
|
||||
|
@ -385,6 +384,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
|
||||
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
|
||||
local->user_power_level = -1;
|
||||
local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
|
||||
local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
|
||||
|
||||
INIT_LIST_HEAD(&local->interfaces);
|
||||
mutex_init(&local->iflist_mtx);
|
||||
|
@ -492,6 +493,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
|
||||
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
|
||||
|
||||
WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
|
||||
&& (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
|
||||
"U-APSD not supported with HW_PS_NULLFUNC_STACK\n");
|
||||
|
||||
/*
|
||||
* Calculate scan IE length -- we need this to alloc
|
||||
* memory and to subtract from the driver limit. It
|
||||
|
|
|
@ -249,30 +249,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
void ieee80211_send_pspoll(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_pspoll *pspoll;
|
||||
struct sk_buff *skb;
|
||||
u16 fc;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for "
|
||||
"pspoll frame\n", sdata->name);
|
||||
skb = ieee80211_pspoll_get(&local->hw, &sdata->vif);
|
||||
if (!skb)
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
|
||||
memset(pspoll, 0, sizeof(*pspoll));
|
||||
fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
|
||||
pspoll->frame_control = cpu_to_le16(fc);
|
||||
pspoll->aid = cpu_to_le16(ifmgd->aid);
|
||||
|
||||
/* aid in PS-Poll has its two MSBs each set to 1 */
|
||||
pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
|
||||
|
||||
memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
|
||||
memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN);
|
||||
pspoll = (struct ieee80211_pspoll *) skb->data;
|
||||
pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
|
@ -281,6 +266,24 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
|
|||
void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int powersave)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
|
||||
skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
|
||||
if (powersave)
|
||||
nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr *nullfunc;
|
||||
|
@ -289,24 +292,23 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
|||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
|
||||
return;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
|
||||
"frame\n", sdata->name);
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr "
|
||||
"nullfunc frame\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
|
||||
memset(nullfunc, 0, 24);
|
||||
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30);
|
||||
memset(nullfunc, 0, 30);
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
if (powersave)
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
||||
nullfunc->frame_control = fc;
|
||||
memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
|
@ -567,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
struct ieee80211_tx_queue_params params;
|
||||
size_t left;
|
||||
int count;
|
||||
u8 *pos;
|
||||
u8 *pos, uapsd_queues = 0;
|
||||
|
||||
if (local->hw.queues < 4)
|
||||
return;
|
||||
|
@ -577,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
|
||||
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
|
||||
return;
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
|
||||
uapsd_queues = local->uapsd_queues;
|
||||
|
||||
count = wmm_param[6] & 0x0f;
|
||||
if (count == ifmgd->wmm_last_param_set)
|
||||
return;
|
||||
|
@ -591,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
for (; left >= 4; left -= 4, pos += 4) {
|
||||
int aci = (pos[0] >> 5) & 0x03;
|
||||
int acm = (pos[0] >> 4) & 0x01;
|
||||
bool uapsd = false;
|
||||
int queue;
|
||||
|
||||
switch (aci) {
|
||||
|
@ -598,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
queue = 3;
|
||||
if (acm)
|
||||
local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
|
||||
uapsd = true;
|
||||
break;
|
||||
case 2: /* AC_VI */
|
||||
queue = 1;
|
||||
if (acm)
|
||||
local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
|
||||
uapsd = true;
|
||||
break;
|
||||
case 3: /* AC_VO */
|
||||
queue = 0;
|
||||
if (acm)
|
||||
local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
uapsd = true;
|
||||
break;
|
||||
case 0: /* AC_BE */
|
||||
default:
|
||||
queue = 2;
|
||||
if (acm)
|
||||
local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
|
||||
uapsd = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -621,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
|
||||
params.cw_min = ecw2cw(pos[1] & 0x0f);
|
||||
params.txop = get_unaligned_le16(pos + 2);
|
||||
params.uapsd = uapsd;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
|
||||
"cWmin=%d cWmax=%d txop=%d\n",
|
||||
"cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
|
||||
wiphy_name(local->hw.wiphy), queue, aci, acm,
|
||||
params.aifs, params.cw_min, params.cw_max, params.txop);
|
||||
params.aifs, params.cw_min, params.cw_max, params.txop,
|
||||
params.uapsd);
|
||||
#endif
|
||||
if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx)
|
||||
printk(KERN_DEBUG "%s: failed to set TX queue "
|
||||
|
@ -652,6 +670,8 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
|
||||
if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
|
||||
use_short_slot = true;
|
||||
|
||||
if (use_protection != bss_conf->use_cts_prot) {
|
||||
bss_conf->use_cts_prot = use_protection;
|
||||
|
@ -723,7 +743,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_recalc_smps(local, sdata);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
netif_start_queue(sdata->dev);
|
||||
netif_tx_start_all_queues(sdata->dev);
|
||||
netif_carrier_on(sdata->dev);
|
||||
}
|
||||
|
||||
|
@ -759,7 +779,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
|
|||
* time -- we don't want the scan code to enable queues.
|
||||
*/
|
||||
|
||||
netif_stop_queue(sdata->dev);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
netif_carrier_off(sdata->dev);
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -1096,7 +1116,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
|||
if (err) {
|
||||
printk(KERN_DEBUG "%s: failed to insert STA entry for"
|
||||
" the AP (error %d)\n", sdata->name, err);
|
||||
return RX_MGMT_CFG80211_ASSOC_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elems.wmm_param)
|
||||
|
@ -1119,6 +1139,13 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
|||
bss_conf->assoc_capability = capab_info;
|
||||
ieee80211_set_associated(sdata, cbss, changed);
|
||||
|
||||
/*
|
||||
* If we're using 4-addr mode, let the AP know that we're
|
||||
* doing so, so that it can create the STA VLAN on its side
|
||||
*/
|
||||
if (ifmgd->use_4addr)
|
||||
ieee80211_send_4addr_nullfunc(local, sdata);
|
||||
|
||||
/*
|
||||
* Start timer to probe the connection to the AP now.
|
||||
* Also start the timer that will detect beacon loss.
|
||||
|
@ -1774,7 +1801,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
|||
if (!wk)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);;
|
||||
memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);
|
||||
|
||||
if (req->ie && req->ie_len) {
|
||||
memcpy(wk->ie, req->ie, req->ie_len);
|
||||
|
@ -1897,6 +1924,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
wk->assoc.ht_information_ie =
|
||||
ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION);
|
||||
|
||||
if (bss->wmm_used && bss->uapsd_supported &&
|
||||
(sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
|
||||
wk->assoc.uapsd_used = true;
|
||||
ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
|
||||
} else {
|
||||
wk->assoc.uapsd_used = false;
|
||||
ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED;
|
||||
}
|
||||
|
||||
ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
|
||||
memcpy(wk->assoc.ssid, ssid + 2, ssid[1]);
|
||||
wk->assoc.ssid_len = ssid[1];
|
||||
|
|
|
@ -113,7 +113,7 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
|
|||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
netif_stop_queue(sdata->dev);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
|
|||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
netif_stop_queue(sdata->dev);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
if (sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata);
|
||||
}
|
||||
|
@ -153,9 +153,11 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
|||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_disable(sdata);
|
||||
netif_wake_queue(sdata->dev);
|
||||
}
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
netif_tx_wake_all_queues(sdata->dev);
|
||||
|
||||
/* re-enable beaconing */
|
||||
if (enable_beaconing &&
|
||||
(sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
|
|
|
@ -207,6 +207,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
|
|||
return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
|
||||
}
|
||||
|
||||
static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
if (basic_rates == 0)
|
||||
return; /* assume basic rates unknown and accept rate */
|
||||
if (*idx < 0)
|
||||
return;
|
||||
if (basic_rates & (1 << *idx))
|
||||
return; /* selected rate is a basic rate */
|
||||
|
||||
for (i = *idx + 1; i <= max_rate_idx; i++) {
|
||||
if (basic_rates & (1 << i)) {
|
||||
*idx = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* could not find a basic rate; use original selection */
|
||||
}
|
||||
|
||||
bool rate_control_send_low(struct ieee80211_sta *sta,
|
||||
void *priv_sta,
|
||||
struct ieee80211_tx_rate_control *txrc)
|
||||
|
@ -218,12 +239,48 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
|
|||
info->control.rates[0].count =
|
||||
(info->flags & IEEE80211_TX_CTL_NO_ACK) ?
|
||||
1 : txrc->hw->max_rate_tries;
|
||||
if (!sta && txrc->ap)
|
||||
rc_send_low_broadcast(&info->control.rates[0].idx,
|
||||
txrc->bss_conf->basic_rates,
|
||||
txrc->sband->n_bitrates);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(rate_control_send_low);
|
||||
|
||||
static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
|
||||
int n_bitrates, u32 mask)
|
||||
{
|
||||
int j;
|
||||
|
||||
/* See whether the selected rate or anything below it is allowed. */
|
||||
for (j = rate->idx; j >= 0; j--) {
|
||||
if (mask & (1 << j)) {
|
||||
/* Okay, found a suitable rate. Use it. */
|
||||
rate->idx = j;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to find a higher rate that would be allowed */
|
||||
for (j = rate->idx + 1; j < n_bitrates; j++) {
|
||||
if (mask & (1 << j)) {
|
||||
/* Okay, found a suitable rate. Use it. */
|
||||
rate->idx = j;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Uh.. No suitable rate exists. This should not really happen with
|
||||
* sane TX rate mask configurations. However, should someone manage to
|
||||
* configure supported rates and TX rate mask in incompatible way,
|
||||
* allow the frame to be transmitted with whatever the rate control
|
||||
* selected.
|
||||
*/
|
||||
}
|
||||
|
||||
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_tx_rate_control *txrc)
|
||||
|
@ -233,6 +290,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_sta *ista = NULL;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
|
||||
int i;
|
||||
u32 mask;
|
||||
|
||||
if (sta) {
|
||||
ista = &sta->sta;
|
||||
|
@ -245,23 +303,31 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
|||
info->control.rates[i].count = 1;
|
||||
}
|
||||
|
||||
if (sta && sdata->force_unicast_rateidx > -1) {
|
||||
info->control.rates[0].idx = sdata->force_unicast_rateidx;
|
||||
} else {
|
||||
ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
info->flags |= IEEE80211_TX_INTFL_RCALGO;
|
||||
}
|
||||
ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
|
||||
/*
|
||||
* try to enforce the maximum rate the user wanted
|
||||
* Try to enforce the rateidx mask the user wanted. skip this if the
|
||||
* default mask (allow all rates) is used to save some processing for
|
||||
* the common case.
|
||||
*/
|
||||
if (sdata->max_ratectrl_rateidx > -1)
|
||||
mask = sdata->rc_rateidx_mask[info->band];
|
||||
if (mask != (1 << txrc->sband->n_bitrates) - 1) {
|
||||
if (sta) {
|
||||
/* Filter out rates that the STA does not support */
|
||||
mask &= sta->sta.supp_rates[info->band];
|
||||
}
|
||||
/*
|
||||
* Make sure the rate index selected for each TX rate is
|
||||
* included in the configured mask and change the rate indexes
|
||||
* if needed.
|
||||
*/
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
/* Rate masking supports only legacy rates for now */
|
||||
if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
|
||||
continue;
|
||||
info->control.rates[i].idx =
|
||||
min_t(s8, info->control.rates[i].idx,
|
||||
sdata->max_ratectrl_rateidx);
|
||||
rate_idx_match_mask(&info->control.rates[i],
|
||||
txrc->sband->n_bitrates, mask);
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(info->control.rates[0].idx < 0);
|
||||
|
|
|
@ -44,10 +44,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
|
|||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
struct ieee80211_sta *ista = &sta->sta;
|
||||
void *priv_sta = sta->rate_ctrl_priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO))
|
||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1111,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|||
if (ieee80211_is_nullfunc(hdr->frame_control) ||
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
|
||||
I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
|
||||
|
||||
/*
|
||||
* If we receive a 4-addr nullfunc frame from a STA
|
||||
* that was not moved to a 4-addr STA vlan yet, drop
|
||||
* the frame to the monitor interface, to make sure
|
||||
* that hostapd sees it
|
||||
*/
|
||||
if (ieee80211_has_a4(hdr->frame_control) &&
|
||||
(rx->sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
(rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
!rx->sdata->u.vlan.sta)))
|
||||
return RX_DROP_MONITOR;
|
||||
/*
|
||||
* Update counter and free packet here to avoid
|
||||
* counting this as a dropped packed.
|
||||
|
@ -1665,7 +1677,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
|||
memset(info, 0, sizeof(*info));
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
info->control.vif = &rx->sdata->vif;
|
||||
ieee80211_select_queue(local, fwd_skb);
|
||||
skb_set_queue_mapping(skb,
|
||||
ieee80211_select_queue(rx->sdata, fwd_skb));
|
||||
ieee80211_set_qos_hdr(local, skb);
|
||||
if (is_multicast_ether_addr(fwd_hdr->addr1))
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
|
||||
fwded_mcast);
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/mac80211.h>
|
||||
|
@ -55,6 +54,23 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
|||
cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv));
|
||||
}
|
||||
|
||||
static bool is_uapsd_supported(struct ieee802_11_elems *elems)
|
||||
{
|
||||
u8 qos_info;
|
||||
|
||||
if (elems->wmm_info && elems->wmm_info_len == 7
|
||||
&& elems->wmm_info[5] == 1)
|
||||
qos_info = elems->wmm_info[6];
|
||||
else if (elems->wmm_param && elems->wmm_param_len == 24
|
||||
&& elems->wmm_param[5] == 1)
|
||||
qos_info = elems->wmm_param[6];
|
||||
else
|
||||
/* no valid wmm information or parameter element found */
|
||||
return false;
|
||||
|
||||
return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
|
@ -118,6 +134,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
bss->wmm_used = elems->wmm_param || elems->wmm_info;
|
||||
bss->uapsd_supported = is_uapsd_supported(elems);
|
||||
|
||||
if (!beacon)
|
||||
bss->last_probe_resp = jiffies;
|
||||
|
@ -285,6 +302,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
ieee80211_mlme_notify_scan_completed(local);
|
||||
ieee80211_ibss_notify_scan_completed(local);
|
||||
ieee80211_mesh_notify_scan_completed(local);
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_scan_completed);
|
||||
|
||||
|
|
|
@ -119,6 +119,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
|
|||
return sta;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get sta info either from the specified interface
|
||||
* or from one of its vlans
|
||||
*/
|
||||
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
|
||||
while (sta) {
|
||||
if ((sta->sdata == sdata ||
|
||||
sta->sdata->bss == sdata->bss) &&
|
||||
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
sta = rcu_dereference(sta->hnext);
|
||||
}
|
||||
return sta;
|
||||
}
|
||||
|
||||
struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
|
||||
int idx)
|
||||
{
|
||||
|
|
|
@ -408,6 +408,9 @@ static inline u32 get_sta_flags(struct sta_info *sta)
|
|||
struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *addr);
|
||||
|
||||
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *addr);
|
||||
|
||||
static inline
|
||||
void for_each_sta_info_type_check(struct ieee80211_local *local,
|
||||
const u8 *addr,
|
||||
|
|
|
@ -180,6 +180,71 @@ static int inline is_ieee80211_device(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
/* tx handlers */
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_local *local = tx->local;
|
||||
struct ieee80211_if_managed *ifmgd;
|
||||
|
||||
/* driver doesn't support power save */
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* hardware does dynamic power save */
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* dynamic power save disabled */
|
||||
if (local->hw.conf.dynamic_ps_timeout <= 0)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* we are scanning, don't enable power save */
|
||||
if (local->scanning)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (!local->ps_sdata)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* No point if we're going to suspend */
|
||||
if (local->quiescing)
|
||||
return TX_CONTINUE;
|
||||
|
||||
/* dynamic ps is supported only in managed mode */
|
||||
if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return TX_CONTINUE;
|
||||
|
||||
ifmgd = &tx->sdata->u.mgd;
|
||||
|
||||
/*
|
||||
* Don't wakeup from power save if u-apsd is enabled, voip ac has
|
||||
* u-apsd enabled and the frame is in voip class. This effectively
|
||||
* means that even if all access categories have u-apsd enabled, in
|
||||
* practise u-apsd is only used with the voip ac. This is a
|
||||
* workaround for the case when received voip class packets do not
|
||||
* have correct qos tag for some reason, due the network or the
|
||||
* peer application.
|
||||
*
|
||||
* Note: local->uapsd_queues access is racy here. If the value is
|
||||
* changed via debugfs, user needs to reassociate manually to have
|
||||
* everything in sync.
|
||||
*/
|
||||
if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
|
||||
&& (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
&& skb_get_queue_mapping(tx->skb) == 0)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_PS);
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&local->dynamic_ps_disable_work);
|
||||
}
|
||||
|
||||
mod_timer(&local->dynamic_ps_timer, jiffies +
|
||||
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
||||
|
@ -519,7 +584,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|||
txrc.bss_conf = &tx->sdata->vif.bss_conf;
|
||||
txrc.skb = tx->skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
|
||||
txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band];
|
||||
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
|
||||
txrc.max_rate_idx = -1;
|
||||
else
|
||||
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
|
||||
txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP;
|
||||
|
||||
/* set up RTS protection if desired */
|
||||
if (len > tx->local->hw.wiphy->rts_threshold) {
|
||||
|
@ -1051,8 +1121,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
tx->sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
|
||||
return TX_DROP;
|
||||
}
|
||||
if (!tx->sta)
|
||||
tx->sta = sta_info_get(sdata, hdr->addr1);
|
||||
|
||||
|
@ -1215,6 +1288,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|||
goto txh_done; \
|
||||
} while (0)
|
||||
|
||||
CALL_TXH(ieee80211_tx_h_dynamic_ps);
|
||||
CALL_TXH(ieee80211_tx_h_check_assoc);
|
||||
CALL_TXH(ieee80211_tx_h_ps_buf);
|
||||
CALL_TXH(ieee80211_tx_h_select_key);
|
||||
|
@ -1397,34 +1471,6 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool need_dynamic_ps(struct ieee80211_local *local)
|
||||
{
|
||||
/* driver doesn't support power save */
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
|
||||
return false;
|
||||
|
||||
/* hardware does dynamic power save */
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
return false;
|
||||
|
||||
/* dynamic power save disabled */
|
||||
if (local->hw.conf.dynamic_ps_timeout <= 0)
|
||||
return false;
|
||||
|
||||
/* we are scanning, don't enable power save */
|
||||
if (local->scanning)
|
||||
return false;
|
||||
|
||||
if (!local->ps_sdata)
|
||||
return false;
|
||||
|
||||
/* No point if we're going to suspend */
|
||||
if (local->quiescing)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -1435,18 +1481,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
int headroom;
|
||||
bool may_encrypt;
|
||||
|
||||
if (need_dynamic_ps(local)) {
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_PS);
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&local->dynamic_ps_disable_work);
|
||||
}
|
||||
|
||||
mod_timer(&local->dynamic_ps_timer, jiffies +
|
||||
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
|
||||
|
@ -1511,7 +1545,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
}
|
||||
|
||||
ieee80211_select_queue(local, skb);
|
||||
ieee80211_set_qos_hdr(local, skb);
|
||||
ieee80211_tx(sdata, skb, false);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -2060,6 +2094,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
struct beacon_data *beacon;
|
||||
struct ieee80211_supported_band *sband;
|
||||
enum ieee80211_band band = local->hw.conf.channel->band;
|
||||
struct ieee80211_tx_rate_control txrc;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
|
@ -2167,21 +2202,25 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
info->band = band;
|
||||
/*
|
||||
* XXX: For now, always use the lowest rate
|
||||
*/
|
||||
info->control.rates[0].idx = 0;
|
||||
info->control.rates[0].count = 1;
|
||||
info->control.rates[1].idx = -1;
|
||||
info->control.rates[2].idx = -1;
|
||||
info->control.rates[3].idx = -1;
|
||||
info->control.rates[4].idx = -1;
|
||||
BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
|
||||
|
||||
memset(&txrc, 0, sizeof(txrc));
|
||||
txrc.hw = hw;
|
||||
txrc.sband = sband;
|
||||
txrc.bss_conf = &sdata->vif.bss_conf;
|
||||
txrc.skb = skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
|
||||
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
|
||||
txrc.max_rate_idx = -1;
|
||||
else
|
||||
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
|
||||
txrc.ap = true;
|
||||
rate_control_get_rate(sdata, NULL, &txrc);
|
||||
|
||||
info->control.vif = vif;
|
||||
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
out:
|
||||
|
@ -2190,6 +2229,134 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_beacon_get_tim);
|
||||
|
||||
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_managed *ifmgd;
|
||||
struct ieee80211_pspoll *pspoll;
|
||||
struct ieee80211_local *local;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
|
||||
return NULL;
|
||||
|
||||
sdata = vif_to_sdata(vif);
|
||||
ifmgd = &sdata->u.mgd;
|
||||
local = sdata->local;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for "
|
||||
"pspoll template\n", sdata->name);
|
||||
return NULL;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
|
||||
memset(pspoll, 0, sizeof(*pspoll));
|
||||
pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
|
||||
IEEE80211_STYPE_PSPOLL);
|
||||
pspoll->aid = cpu_to_le16(ifmgd->aid);
|
||||
|
||||
/* aid in PS-Poll has its two MSBs each set to 1 */
|
||||
pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
|
||||
|
||||
memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
|
||||
memcpy(pspoll->ta, vif->addr, ETH_ALEN);
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_pspoll_get);
|
||||
|
||||
struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_managed *ifmgd;
|
||||
struct ieee80211_local *local;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
|
||||
return NULL;
|
||||
|
||||
sdata = vif_to_sdata(vif);
|
||||
ifmgd = &sdata->u.mgd;
|
||||
local = sdata->local;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc));
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
|
||||
"template\n", sdata->name);
|
||||
return NULL;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb,
|
||||
sizeof(*nullfunc));
|
||||
memset(nullfunc, 0, sizeof(*nullfunc));
|
||||
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN);
|
||||
memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN);
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_nullfunc_get);
|
||||
|
||||
struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_hdr_3addr *hdr;
|
||||
struct sk_buff *skb;
|
||||
size_t ie_ssid_len;
|
||||
u8 *pos;
|
||||
|
||||
sdata = vif_to_sdata(vif);
|
||||
local = sdata->local;
|
||||
ie_ssid_len = 2 + ssid_len;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) +
|
||||
ie_ssid_len + ie_len);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
|
||||
"request template\n", sdata->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
|
||||
memset(hdr, 0, sizeof(*hdr));
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_REQ);
|
||||
memset(hdr->addr1, 0xff, ETH_ALEN);
|
||||
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
|
||||
memset(hdr->addr3, 0xff, ETH_ALEN);
|
||||
|
||||
pos = skb_put(skb, ie_ssid_len);
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = ssid_len;
|
||||
if (ssid)
|
||||
memcpy(pos, ssid, ssid_len);
|
||||
pos += ssid_len;
|
||||
|
||||
if (ie) {
|
||||
pos = skb_put(skb, ie_len);
|
||||
memcpy(pos, ie, ie_len);
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_probereq_get);
|
||||
|
||||
void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
const void *frame, size_t frame_len,
|
||||
const struct ieee80211_tx_info *frame_txctl,
|
||||
|
@ -2289,6 +2456,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
|||
skb_set_network_header(skb, 0);
|
||||
skb_set_transport_header(skb, 0);
|
||||
|
||||
/* send all internal mgmt frames on VO */
|
||||
skb_set_queue_mapping(skb, 0);
|
||||
|
||||
/*
|
||||
* The other path calling ieee80211_xmit is from the tasklet,
|
||||
* and while we can handle concurrent transmissions locking
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
@ -269,6 +268,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
|||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (WARN_ON(queue >= hw->queues))
|
||||
return;
|
||||
|
@ -281,6 +281,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
|||
|
||||
if (!skb_queue_empty(&local->pending[queue]))
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
|
@ -305,11 +310,17 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
|||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (WARN_ON(queue >= hw->queues))
|
||||
return;
|
||||
|
||||
__set_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue));
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
|
@ -781,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
|
|||
break;
|
||||
}
|
||||
|
||||
qparam.uapsd = false;
|
||||
|
||||
drv_conf_tx(local, queue, &qparam);
|
||||
}
|
||||
}
|
||||
|
@ -989,40 +1002,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos;
|
||||
size_t buf_len;
|
||||
u8 *buf;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
|
||||
ie_len);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
|
||||
"request\n", sdata->name);
|
||||
/* FIXME: come up with a proper value */
|
||||
buf = kmalloc(200 + ie_len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate temporary IE "
|
||||
"buffer\n", sdata->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_REQ);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
|
||||
local->hw.conf.channel->band);
|
||||
|
||||
skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
|
||||
ssid, ssid_len,
|
||||
buf, buf_len);
|
||||
|
||||
if (dst) {
|
||||
mgmt = (struct ieee80211_mgmt *) skb->data;
|
||||
memcpy(mgmt->da, dst, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, dst, ETH_ALEN);
|
||||
} else {
|
||||
memset(mgmt->da, 0xff, ETH_ALEN);
|
||||
memset(mgmt->bssid, 0xff, ETH_ALEN);
|
||||
}
|
||||
pos = skb_put(skb, 2 + ssid_len);
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = ssid_len;
|
||||
memcpy(pos, ssid, ssid_len);
|
||||
pos += ssid_len;
|
||||
|
||||
skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len,
|
||||
local->hw.conf.channel->band));
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
||||
|
@ -1066,9 +1072,9 @@ void ieee80211_stop_device(struct ieee80211_local *local)
|
|||
ieee80211_led_radio(local, false);
|
||||
|
||||
cancel_work_sync(&local->reconfig_filter);
|
||||
drv_stop(local);
|
||||
|
||||
flush_workqueue(local->workqueue);
|
||||
drv_stop(local);
|
||||
}
|
||||
|
||||
int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
|
@ -1094,7 +1100,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
if (res) {
|
||||
WARN(local->suspended, "Harware became unavailable "
|
||||
"upon resume. This is could be a software issue"
|
||||
"prior to suspend or a harware issue\n");
|
||||
"prior to suspend or a hardware issue\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,22 +44,69 @@ static int wme_downgrade_ac(struct sk_buff *skb)
|
|||
}
|
||||
|
||||
|
||||
/* Indicate which queue to use. */
|
||||
static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
/* Indicate which queue to use. */
|
||||
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta = NULL;
|
||||
u32 sta_flags = 0;
|
||||
const u8 *ra = NULL;
|
||||
bool qos = false;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control)) {
|
||||
/* management frames go on AC_VO queue, but are sent
|
||||
* without QoS control fields */
|
||||
return 0;
|
||||
if (local->hw.queues < 4 || skb->len < 6) {
|
||||
skb->priority = 0; /* required for correct WPA/11i MIC */
|
||||
return min_t(u16, local->hw.queues - 1,
|
||||
ieee802_1d_to_ac[skb->priority]);
|
||||
}
|
||||
|
||||
if (0 /* injected */) {
|
||||
/* use AC from radiotap */
|
||||
rcu_read_lock();
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
rcu_read_lock();
|
||||
sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
if (sta)
|
||||
sta_flags = get_sta_flags(sta);
|
||||
rcu_read_unlock();
|
||||
if (sta)
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
ra = skb->data;
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
ra = sdata->u.wds.remote_addr;
|
||||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
/*
|
||||
* XXX: This is clearly broken ... but already was before,
|
||||
* because ieee80211_fill_mesh_addresses() would clear A1
|
||||
* except for multicast addresses.
|
||||
*/
|
||||
break;
|
||||
#endif
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ra = sdata->u.mgd.bssid;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ra = skb->data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
if (!sta && ra && !is_multicast_ether_addr(ra)) {
|
||||
sta = sta_info_get(sdata, ra);
|
||||
if (sta)
|
||||
sta_flags = get_sta_flags(sta);
|
||||
}
|
||||
|
||||
if (sta_flags & WLAN_STA_WME)
|
||||
qos = true;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!qos) {
|
||||
skb->priority = 0; /* required for correct WPA/11i MIC */
|
||||
return ieee802_1d_to_ac[skb->priority];
|
||||
}
|
||||
|
@ -68,6 +115,12 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
|
|||
* data frame has */
|
||||
skb->priority = cfg80211_classify8021d(skb);
|
||||
|
||||
return ieee80211_downgrade_queue(local, skb);
|
||||
}
|
||||
|
||||
u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
/* in case we are a client verify acm is not set for this ac */
|
||||
while (unlikely(local->wmm_acm & BIT(skb->priority))) {
|
||||
if (wme_downgrade_ac(skb)) {
|
||||
|
@ -85,24 +138,17 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
|
|||
return ieee802_1d_to_ac[skb->priority];
|
||||
}
|
||||
|
||||
void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 queue;
|
||||
u8 tid;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
|
||||
queue = classify80211(local, skb);
|
||||
if (unlikely(queue >= local->hw.queues))
|
||||
queue = local->hw.queues - 1;
|
||||
|
||||
/*
|
||||
* Now we know the 1d priority, fill in the QoS header if
|
||||
* there is one (and we haven't done this before).
|
||||
*/
|
||||
/* Fill in the QoS header if there is one. */
|
||||
if (ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
u8 *p = ieee80211_get_qos_ctl(hdr);
|
||||
u8 ack_policy = 0;
|
||||
u8 ack_policy = 0, tid;
|
||||
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
|
||||
if (unlikely(local->wifi_wme_noack_test))
|
||||
ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
|
||||
QOS_CONTROL_ACK_POLICY_SHIFT;
|
||||
|
@ -110,6 +156,4 @@ void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
|
|||
*p++ = ack_policy | tid;
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
skb_set_queue_mapping(skb, queue);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,11 @@
|
|||
|
||||
extern const int ieee802_1d_to_ac[8];
|
||||
|
||||
void ieee80211_select_queue(struct ieee80211_local *local,
|
||||
struct sk_buff *skb);
|
||||
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb);
|
||||
u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
|
||||
struct sk_buff *skb);
|
||||
|
||||
|
||||
#endif /* _WME_H */
|
||||
|
|
|
@ -202,7 +202,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos;
|
||||
u8 *pos, qos_info;
|
||||
const u8 *ies;
|
||||
size_t offset = 0, noffset;
|
||||
int i, len, count, rates_len, supp_rates_len;
|
||||
|
@ -375,6 +375,14 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (wk->assoc.wmm_used && local->hw.queues >= 4) {
|
||||
if (wk->assoc.uapsd_used) {
|
||||
qos_info = local->uapsd_queues;
|
||||
qos_info |= (local->uapsd_max_sp_len <<
|
||||
IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
|
||||
} else {
|
||||
qos_info = 0;
|
||||
}
|
||||
|
||||
pos = skb_put(skb, 9);
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = 7; /* len */
|
||||
|
@ -384,7 +392,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
*pos++ = 2; /* WME */
|
||||
*pos++ = 0; /* WME info */
|
||||
*pos++ = 1; /* WME ver */
|
||||
*pos++ = 0;
|
||||
*pos++ = qos_info;
|
||||
}
|
||||
|
||||
/* add any remaining custom (i.e. vendor specific here) IEs */
|
||||
|
@ -531,9 +539,9 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
|
|||
wk->remain.started = true;
|
||||
wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
|
||||
|
||||
cfg80211_ready_on_channel(wk->sdata->dev, (u64)wk, wk->chan,
|
||||
wk->chan_type, wk->remain.duration,
|
||||
GFP_KERNEL);
|
||||
cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
|
||||
wk->chan, wk->chan_type,
|
||||
wk->remain.duration, GFP_KERNEL);
|
||||
|
||||
return WORK_ACT_NONE;
|
||||
}
|
||||
|
@ -818,6 +826,7 @@ static void ieee80211_work_work(struct work_struct *work)
|
|||
wk->chan == local->tmp_channel &&
|
||||
wk->chan_type == local->tmp_channel_type) {
|
||||
wk->started = true;
|
||||
wk->timeout = jiffies;
|
||||
}
|
||||
|
||||
if (!wk->started && !local->tmp_channel) {
|
||||
|
@ -935,6 +944,9 @@ void ieee80211_add_work(struct ieee80211_work *wk)
|
|||
if (WARN_ON(!wk->done))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
|
||||
return;
|
||||
|
||||
wk->started = false;
|
||||
|
||||
local = wk->sdata->local;
|
||||
|
@ -1027,7 +1039,7 @@ static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
|
|||
/*
|
||||
* We are done serving the remain-on-channel command.
|
||||
*/
|
||||
cfg80211_remain_on_channel_expired(wk->sdata->dev, (u64)wk,
|
||||
cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
|
||||
wk->chan, wk->chan_type,
|
||||
GFP_KERNEL);
|
||||
|
||||
|
@ -1053,7 +1065,7 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
wk->remain.duration = duration;
|
||||
|
||||
*cookie = (u64)wk;
|
||||
*cookie = (unsigned long) wk;
|
||||
|
||||
ieee80211_add_work(wk);
|
||||
|
||||
|
@ -1069,7 +1081,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
mutex_lock(&local->work_mtx);
|
||||
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
|
||||
if ((u64)wk == cookie) {
|
||||
if ((unsigned long) wk == cookie) {
|
||||
wk->timeout = jiffies;
|
||||
found = true;
|
||||
break;
|
||||
|
|
|
@ -402,6 +402,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
|
|||
rdev->wiphy.retry_long = 4;
|
||||
rdev->wiphy.frag_threshold = (u32) -1;
|
||||
rdev->wiphy.rts_threshold = (u32) -1;
|
||||
rdev->wiphy.coverage_class = 0;
|
||||
|
||||
return &rdev->wiphy;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,8 @@ struct cfg80211_internal_bss {
|
|||
unsigned long ts;
|
||||
struct kref ref;
|
||||
atomic_t hold;
|
||||
bool ies_allocated;
|
||||
bool beacon_ies_allocated;
|
||||
bool proberesp_ies_allocated;
|
||||
|
||||
/* must be last because of priv member */
|
||||
struct cfg80211_bss pub;
|
||||
|
|
|
@ -69,6 +69,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
|
|||
[NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
|
||||
|
||||
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
|
||||
|
@ -143,6 +144,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
|
|||
.len = WLAN_PMKID_LEN },
|
||||
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
|
||||
[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
/* policy for the attributes */
|
||||
|
@ -444,6 +446,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
dev->wiphy.frag_threshold);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
|
||||
dev->wiphy.rts_threshold);
|
||||
NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
|
||||
dev->wiphy.coverage_class);
|
||||
|
||||
NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
|
||||
dev->wiphy.max_scan_ssids);
|
||||
|
@ -572,6 +576,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
CMD(del_pmksa, DEL_PMKSA);
|
||||
CMD(flush_pmksa, FLUSH_PMKSA);
|
||||
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
||||
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
|
||||
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
|
||||
i++;
|
||||
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
|
||||
|
@ -684,6 +689,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
u32 changed;
|
||||
u8 retry_short = 0, retry_long = 0;
|
||||
u32 frag_threshold = 0, rts_threshold = 0;
|
||||
u8 coverage_class = 0;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
|
@ -806,9 +812,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
changed |= WIPHY_PARAM_RTS_THRESHOLD;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
|
||||
coverage_class = nla_get_u8(
|
||||
info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
|
||||
changed |= WIPHY_PARAM_COVERAGE_CLASS;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
u8 old_retry_short, old_retry_long;
|
||||
u32 old_frag_threshold, old_rts_threshold;
|
||||
u8 old_coverage_class;
|
||||
|
||||
if (!rdev->ops->set_wiphy_params) {
|
||||
result = -EOPNOTSUPP;
|
||||
|
@ -819,6 +832,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
old_retry_long = rdev->wiphy.retry_long;
|
||||
old_frag_threshold = rdev->wiphy.frag_threshold;
|
||||
old_rts_threshold = rdev->wiphy.rts_threshold;
|
||||
old_coverage_class = rdev->wiphy.coverage_class;
|
||||
|
||||
if (changed & WIPHY_PARAM_RETRY_SHORT)
|
||||
rdev->wiphy.retry_short = retry_short;
|
||||
|
@ -828,6 +842,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
rdev->wiphy.frag_threshold = frag_threshold;
|
||||
if (changed & WIPHY_PARAM_RTS_THRESHOLD)
|
||||
rdev->wiphy.rts_threshold = rts_threshold;
|
||||
if (changed & WIPHY_PARAM_COVERAGE_CLASS)
|
||||
rdev->wiphy.coverage_class = coverage_class;
|
||||
|
||||
result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
|
||||
if (result) {
|
||||
|
@ -835,6 +851,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
rdev->wiphy.retry_long = old_retry_long;
|
||||
rdev->wiphy.frag_threshold = old_frag_threshold;
|
||||
rdev->wiphy.rts_threshold = old_rts_threshold;
|
||||
rdev->wiphy.coverage_class = old_coverage_class;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3146,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
|
||||
res->len_information_elements,
|
||||
res->information_elements);
|
||||
if (res->beacon_ies && res->len_beacon_ies &&
|
||||
res->beacon_ies != res->information_elements)
|
||||
NLA_PUT(msg, NL80211_BSS_BEACON_IES,
|
||||
res->len_beacon_ies, res->beacon_ies);
|
||||
if (res->tsf)
|
||||
NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
|
||||
if (res->beacon_interval)
|
||||
|
@ -4423,6 +4444,109 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
|
|||
return err;
|
||||
}
|
||||
|
||||
static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
|
||||
u8 *rates, u8 rates_len)
|
||||
{
|
||||
u8 i;
|
||||
u32 mask = 0;
|
||||
|
||||
for (i = 0; i < rates_len; i++) {
|
||||
int rate = (rates[i] & 0x7f) * 5;
|
||||
int ridx;
|
||||
for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
|
||||
struct ieee80211_rate *srate =
|
||||
&sband->bitrates[ridx];
|
||||
if (rate == srate->bitrate) {
|
||||
mask |= 1 << ridx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ridx == sband->n_bitrates)
|
||||
return 0; /* rate not found */
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static struct nla_policy
|
||||
nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = {
|
||||
[NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
|
||||
.len = NL80211_MAX_SUPP_RATES },
|
||||
};
|
||||
|
||||
static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct nlattr *tb[NL80211_TXRATE_MAX + 1];
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct cfg80211_bitrate_mask mask;
|
||||
int err, rem, i;
|
||||
struct net_device *dev;
|
||||
struct nlattr *tx_rates;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
|
||||
if (err)
|
||||
goto unlock_rtnl;
|
||||
|
||||
if (!rdev->ops->set_bitrate_mask) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
memset(&mask, 0, sizeof(mask));
|
||||
/* Default to all rates enabled */
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
|
||||
sband = rdev->wiphy.bands[i];
|
||||
mask.control[i].legacy =
|
||||
sband ? (1 << sband->n_bitrates) - 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The nested attribute uses enum nl80211_band as the index. This maps
|
||||
* directly to the enum ieee80211_band values used in cfg80211.
|
||||
*/
|
||||
nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
|
||||
{
|
||||
enum ieee80211_band band = nla_type(tx_rates);
|
||||
if (band < 0 || band >= IEEE80211_NUM_BANDS) {
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
sband = rdev->wiphy.bands[band];
|
||||
if (sband == NULL) {
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
|
||||
nla_len(tx_rates), nl80211_txattr_policy);
|
||||
if (tb[NL80211_TXRATE_LEGACY]) {
|
||||
mask.control[band].legacy = rateset_to_mask(
|
||||
sband,
|
||||
nla_data(tb[NL80211_TXRATE_LEGACY]),
|
||||
nla_len(tb[NL80211_TXRATE_LEGACY]));
|
||||
if (mask.control[band].legacy == 0) {
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
|
||||
|
||||
unlock:
|
||||
dev_put(dev);
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
unlock_rtnl:
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct genl_ops nl80211_ops[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
|
@ -4697,6 +4821,12 @@ static struct genl_ops nl80211_ops[] = {
|
|||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
|
||||
.doit = nl80211_set_tx_bitrate_mask,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
||||
|
|
|
@ -43,6 +43,15 @@
|
|||
#include "regdb.h"
|
||||
#include "nl80211.h"
|
||||
|
||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
||||
#define REG_DBG_PRINT(format, args...) \
|
||||
do { \
|
||||
printk(KERN_DEBUG format , ## args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define REG_DBG_PRINT(args...)
|
||||
#endif
|
||||
|
||||
/* Receipt of information from last regulatory request */
|
||||
static struct regulatory_request *last_request;
|
||||
|
||||
|
@ -475,6 +484,205 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
|
|||
#undef ONE_GHZ_IN_KHZ
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a work around for sanity checking ieee80211_channel_to_frequency()'s
|
||||
* work. ieee80211_channel_to_frequency() can for example currently provide a
|
||||
* 2 GHz channel when in fact a 5 GHz channel was desired. An example would be
|
||||
* an AP providing channel 8 on a country IE triplet when it sent this on the
|
||||
* 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz
|
||||
* channel.
|
||||
*
|
||||
* This can be removed once ieee80211_channel_to_frequency() takes in a band.
|
||||
*/
|
||||
static bool chan_in_band(int chan, enum ieee80211_band band)
|
||||
{
|
||||
int center_freq = ieee80211_channel_to_frequency(chan);
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (center_freq <= 2484)
|
||||
return true;
|
||||
return false;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
if (center_freq >= 5005)
|
||||
return true;
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some APs may send a country IE triplet for each channel they
|
||||
* support and while this is completely overkill and silly we still
|
||||
* need to support it. We avoid making a single rule for each channel
|
||||
* though and to help us with this we use this helper to find the
|
||||
* actual subband end channel. These type of country IE triplet
|
||||
* scenerios are handled then, all yielding two regulaotry rules from
|
||||
* parsing a country IE:
|
||||
*
|
||||
* [1]
|
||||
* [2]
|
||||
* [36]
|
||||
* [40]
|
||||
*
|
||||
* [1]
|
||||
* [2-4]
|
||||
* [5-12]
|
||||
* [36]
|
||||
* [40-44]
|
||||
*
|
||||
* [1-4]
|
||||
* [5-7]
|
||||
* [36-44]
|
||||
* [48-64]
|
||||
*
|
||||
* [36-36]
|
||||
* [40-40]
|
||||
* [44-44]
|
||||
* [48-48]
|
||||
* [52-52]
|
||||
* [56-56]
|
||||
* [60-60]
|
||||
* [64-64]
|
||||
* [100-100]
|
||||
* [104-104]
|
||||
* [108-108]
|
||||
* [112-112]
|
||||
* [116-116]
|
||||
* [120-120]
|
||||
* [124-124]
|
||||
* [128-128]
|
||||
* [132-132]
|
||||
* [136-136]
|
||||
* [140-140]
|
||||
*
|
||||
* Returns 0 if the IE has been found to be invalid in the middle
|
||||
* somewhere.
|
||||
*/
|
||||
static int max_subband_chan(enum ieee80211_band band,
|
||||
int orig_cur_chan,
|
||||
int orig_end_channel,
|
||||
s8 orig_max_power,
|
||||
u8 **country_ie,
|
||||
u8 *country_ie_len)
|
||||
{
|
||||
u8 *triplets_start = *country_ie;
|
||||
u8 len_at_triplet = *country_ie_len;
|
||||
int end_subband_chan = orig_end_channel;
|
||||
|
||||
/*
|
||||
* We'll deal with padding for the caller unless
|
||||
* its not immediate and we don't process any channels
|
||||
*/
|
||||
if (*country_ie_len == 1) {
|
||||
*country_ie += 1;
|
||||
*country_ie_len -= 1;
|
||||
return orig_end_channel;
|
||||
}
|
||||
|
||||
/* Move to the next triplet and then start search */
|
||||
*country_ie += 3;
|
||||
*country_ie_len -= 3;
|
||||
|
||||
if (!chan_in_band(orig_cur_chan, band))
|
||||
return 0;
|
||||
|
||||
while (*country_ie_len >= 3) {
|
||||
int end_channel = 0;
|
||||
struct ieee80211_country_ie_triplet *triplet =
|
||||
(struct ieee80211_country_ie_triplet *) *country_ie;
|
||||
int cur_channel = 0, next_expected_chan;
|
||||
|
||||
/* means last triplet is completely unrelated to this one */
|
||||
if (triplet->ext.reg_extension_id >=
|
||||
IEEE80211_COUNTRY_EXTENSION_ID) {
|
||||
*country_ie -= 3;
|
||||
*country_ie_len += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (triplet->chans.first_channel == 0) {
|
||||
*country_ie += 1;
|
||||
*country_ie_len -= 1;
|
||||
if (*country_ie_len != 0)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (triplet->chans.num_channels == 0)
|
||||
return 0;
|
||||
|
||||
/* Monitonically increasing channel order */
|
||||
if (triplet->chans.first_channel <= end_subband_chan)
|
||||
return 0;
|
||||
|
||||
if (!chan_in_band(triplet->chans.first_channel, band))
|
||||
return 0;
|
||||
|
||||
/* 2 GHz */
|
||||
if (triplet->chans.first_channel <= 14) {
|
||||
end_channel = triplet->chans.first_channel +
|
||||
triplet->chans.num_channels - 1;
|
||||
}
|
||||
else {
|
||||
end_channel = triplet->chans.first_channel +
|
||||
(4 * (triplet->chans.num_channels - 1));
|
||||
}
|
||||
|
||||
if (!chan_in_band(end_channel, band))
|
||||
return 0;
|
||||
|
||||
if (orig_max_power != triplet->chans.max_power) {
|
||||
*country_ie -= 3;
|
||||
*country_ie_len += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
cur_channel = triplet->chans.first_channel;
|
||||
|
||||
/* The key is finding the right next expected channel */
|
||||
if (band == IEEE80211_BAND_2GHZ)
|
||||
next_expected_chan = end_subband_chan + 1;
|
||||
else
|
||||
next_expected_chan = end_subband_chan + 4;
|
||||
|
||||
if (cur_channel != next_expected_chan) {
|
||||
*country_ie -= 3;
|
||||
*country_ie_len += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
end_subband_chan = end_channel;
|
||||
|
||||
/* Move to the next one */
|
||||
*country_ie += 3;
|
||||
*country_ie_len -= 3;
|
||||
|
||||
/*
|
||||
* Padding needs to be dealt with if we processed
|
||||
* some channels.
|
||||
*/
|
||||
if (*country_ie_len == 1) {
|
||||
*country_ie += 1;
|
||||
*country_ie_len -= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If seen, the IE is invalid */
|
||||
if (*country_ie_len == 2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (end_subband_chan == orig_end_channel) {
|
||||
*country_ie = triplets_start;
|
||||
*country_ie_len = len_at_triplet;
|
||||
return orig_end_channel;
|
||||
}
|
||||
|
||||
return end_subband_chan;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a country IE to a regulatory domain. A regulatory domain
|
||||
* structure has a lot of information which the IE doesn't yet have,
|
||||
|
@ -482,6 +690,7 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
|
|||
* with our userspace regulatory agent to get lower bounds.
|
||||
*/
|
||||
static struct ieee80211_regdomain *country_ie_2_rd(
|
||||
enum ieee80211_band band,
|
||||
u8 *country_ie,
|
||||
u8 country_ie_len,
|
||||
u32 *checksum)
|
||||
|
@ -543,10 +752,29 @@ static struct ieee80211_regdomain *country_ie_2_rd(
|
|||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* APs can add padding to make length divisible
|
||||
* by two, required by the spec.
|
||||
*/
|
||||
if (triplet->chans.first_channel == 0) {
|
||||
country_ie++;
|
||||
country_ie_len--;
|
||||
/* This is expected to be at the very end only */
|
||||
if (country_ie_len != 0)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (triplet->chans.num_channels == 0)
|
||||
return NULL;
|
||||
|
||||
if (!chan_in_band(triplet->chans.first_channel, band))
|
||||
return NULL;
|
||||
|
||||
/* 2 GHz */
|
||||
if (triplet->chans.first_channel <= 14)
|
||||
if (band == IEEE80211_BAND_2GHZ)
|
||||
end_channel = triplet->chans.first_channel +
|
||||
triplet->chans.num_channels;
|
||||
triplet->chans.num_channels - 1;
|
||||
else
|
||||
/*
|
||||
* 5 GHz -- For example in country IEs if the first
|
||||
|
@ -561,6 +789,24 @@ static struct ieee80211_regdomain *country_ie_2_rd(
|
|||
(4 * (triplet->chans.num_channels - 1));
|
||||
|
||||
cur_channel = triplet->chans.first_channel;
|
||||
|
||||
/*
|
||||
* Enhancement for APs that send a triplet for every channel
|
||||
* or for whatever reason sends triplets with multiple channels
|
||||
* separated when in fact they should be together.
|
||||
*/
|
||||
end_channel = max_subband_chan(band,
|
||||
cur_channel,
|
||||
end_channel,
|
||||
triplet->chans.max_power,
|
||||
&country_ie,
|
||||
&country_ie_len);
|
||||
if (!end_channel)
|
||||
return NULL;
|
||||
|
||||
if (!chan_in_band(end_channel, band))
|
||||
return NULL;
|
||||
|
||||
cur_sub_max_channel = end_channel;
|
||||
|
||||
/* Basic sanity check */
|
||||
|
@ -591,10 +837,13 @@ static struct ieee80211_regdomain *country_ie_2_rd(
|
|||
|
||||
last_sub_max_channel = cur_sub_max_channel;
|
||||
|
||||
country_ie += 3;
|
||||
country_ie_len -= 3;
|
||||
num_rules++;
|
||||
|
||||
if (country_ie_len >= 3) {
|
||||
country_ie += 3;
|
||||
country_ie_len -= 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: this is not a IEEE requirement but
|
||||
* simply a memory requirement
|
||||
|
@ -637,6 +886,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (triplet->chans.first_channel == 0) {
|
||||
country_ie++;
|
||||
country_ie_len--;
|
||||
break;
|
||||
}
|
||||
|
||||
reg_rule = &rd->reg_rules[i];
|
||||
freq_range = ®_rule->freq_range;
|
||||
power_rule = ®_rule->power_rule;
|
||||
|
@ -644,13 +899,20 @@ static struct ieee80211_regdomain *country_ie_2_rd(
|
|||
reg_rule->flags = flags;
|
||||
|
||||
/* 2 GHz */
|
||||
if (triplet->chans.first_channel <= 14)
|
||||
if (band == IEEE80211_BAND_2GHZ)
|
||||
end_channel = triplet->chans.first_channel +
|
||||
triplet->chans.num_channels;
|
||||
triplet->chans.num_channels -1;
|
||||
else
|
||||
end_channel = triplet->chans.first_channel +
|
||||
(4 * (triplet->chans.num_channels - 1));
|
||||
|
||||
end_channel = max_subband_chan(band,
|
||||
triplet->chans.first_channel,
|
||||
end_channel,
|
||||
triplet->chans.max_power,
|
||||
&country_ie,
|
||||
&country_ie_len);
|
||||
|
||||
/*
|
||||
* The +10 is since the regulatory domain expects
|
||||
* the actual band edge, not the center of freq for
|
||||
|
@ -671,12 +933,15 @@ static struct ieee80211_regdomain *country_ie_2_rd(
|
|||
*/
|
||||
freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
|
||||
power_rule->max_antenna_gain = DBI_TO_MBI(100);
|
||||
power_rule->max_eirp = DBM_TO_MBM(100);
|
||||
power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power);
|
||||
|
||||
country_ie += 3;
|
||||
country_ie_len -= 3;
|
||||
i++;
|
||||
|
||||
if (country_ie_len >= 3) {
|
||||
country_ie += 3;
|
||||
country_ie_len -= 3;
|
||||
}
|
||||
|
||||
BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
|
||||
}
|
||||
|
||||
|
@ -972,25 +1237,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
|
|||
if (r == -ERANGE &&
|
||||
last_request->initiator ==
|
||||
NL80211_REGDOM_SET_BY_COUNTRY_IE) {
|
||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
||||
printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
|
||||
REG_DBG_PRINT("cfg80211: Leaving channel %d MHz "
|
||||
"intact on %s - no rule found in band on "
|
||||
"Country IE\n",
|
||||
chan->center_freq, wiphy_name(wiphy));
|
||||
#endif
|
||||
chan->center_freq, wiphy_name(wiphy));
|
||||
} else {
|
||||
/*
|
||||
* In this case we know the country IE has at least one reg rule
|
||||
* for the band so we respect its band definitions
|
||||
*/
|
||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
||||
if (last_request->initiator ==
|
||||
NL80211_REGDOM_SET_BY_COUNTRY_IE)
|
||||
printk(KERN_DEBUG "cfg80211: Disabling "
|
||||
REG_DBG_PRINT("cfg80211: Disabling "
|
||||
"channel %d MHz on %s due to "
|
||||
"Country IE\n",
|
||||
chan->center_freq, wiphy_name(wiphy));
|
||||
#endif
|
||||
flags |= IEEE80211_CHAN_DISABLED;
|
||||
chan->flags = flags;
|
||||
}
|
||||
|
@ -1685,7 +1946,7 @@ int regulatory_hint_user(const char *alpha2)
|
|||
request->wiphy_idx = WIPHY_IDX_STALE;
|
||||
request->alpha2[0] = alpha2[0];
|
||||
request->alpha2[1] = alpha2[1];
|
||||
request->initiator = NL80211_REGDOM_SET_BY_USER,
|
||||
request->initiator = NL80211_REGDOM_SET_BY_USER;
|
||||
|
||||
queue_regulatory_request(request);
|
||||
|
||||
|
@ -1753,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
|
|||
* therefore cannot iterate over the rdev list here.
|
||||
*/
|
||||
void regulatory_hint_11d(struct wiphy *wiphy,
|
||||
u8 *country_ie,
|
||||
u8 country_ie_len)
|
||||
enum ieee80211_band band,
|
||||
u8 *country_ie,
|
||||
u8 country_ie_len)
|
||||
{
|
||||
struct ieee80211_regdomain *rd = NULL;
|
||||
char alpha2[2];
|
||||
|
@ -1800,9 +2062,11 @@ void regulatory_hint_11d(struct wiphy *wiphy,
|
|||
wiphy_idx_valid(last_request->wiphy_idx)))
|
||||
goto out;
|
||||
|
||||
rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
|
||||
if (!rd)
|
||||
rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum);
|
||||
if (!rd) {
|
||||
REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will not happen right now but we leave it here for the
|
||||
|
@ -1870,13 +2134,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
|
|||
if (!reg_beacon)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
||||
printk(KERN_DEBUG "cfg80211: Found new beacon on "
|
||||
"frequency: %d MHz (Ch %d) on %s\n",
|
||||
beacon_chan->center_freq,
|
||||
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
||||
wiphy_name(wiphy));
|
||||
#endif
|
||||
REG_DBG_PRINT("cfg80211: Found new beacon on "
|
||||
"frequency: %d MHz (Ch %d) on %s\n",
|
||||
beacon_chan->center_freq,
|
||||
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
||||
wiphy_name(wiphy));
|
||||
|
||||
memcpy(®_beacon->chan, beacon_chan,
|
||||
sizeof(struct ieee80211_channel));
|
||||
|
||||
|
|
|
@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
|
|||
* regulatory_hint_11d - hints a country IE as a regulatory domain
|
||||
* @wiphy: the wireless device giving the hint (used only for reporting
|
||||
* conflicts)
|
||||
* @band: the band on which the country IE was received on. This determines
|
||||
* the band we'll process the country IE channel triplets for.
|
||||
* @country_ie: pointer to the country IE
|
||||
* @country_ie_len: length of the country IE
|
||||
*
|
||||
* We will intersect the rd with the what CRDA tells us should apply
|
||||
* for the alpha2 this country IE belongs to, this prevents APs from
|
||||
* sending us incorrect or outdated information against a country.
|
||||
*
|
||||
* The AP is expected to provide Country IE channel triplets for the
|
||||
* band it is on. It is technically possible for APs to send channel
|
||||
* country IE triplets even for channels outside of the band they are
|
||||
* in but for that they would have to use the regulatory extension
|
||||
* in combination with a triplet but this behaviour is currently
|
||||
* not observed. For this reason if a triplet is seen with channel
|
||||
* information for a band the BSS is not present in it will be ignored.
|
||||
*/
|
||||
void regulatory_hint_11d(struct wiphy *wiphy,
|
||||
enum ieee80211_band band,
|
||||
u8 *country_ie,
|
||||
u8 country_ie_len);
|
||||
|
||||
|
|
|
@ -100,8 +100,10 @@ static void bss_release(struct kref *ref)
|
|||
if (bss->pub.free_priv)
|
||||
bss->pub.free_priv(&bss->pub);
|
||||
|
||||
if (bss->ies_allocated)
|
||||
kfree(bss->pub.information_elements);
|
||||
if (bss->beacon_ies_allocated)
|
||||
kfree(bss->pub.beacon_ies);
|
||||
if (bss->proberesp_ies_allocated)
|
||||
kfree(bss->pub.proberesp_ies);
|
||||
|
||||
BUG_ON(atomic_read(&bss->hold));
|
||||
|
||||
|
@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
|
|||
|
||||
static struct cfg80211_internal_bss *
|
||||
cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *res,
|
||||
bool overwrite)
|
||||
struct cfg80211_internal_bss *res)
|
||||
{
|
||||
struct cfg80211_internal_bss *found = NULL;
|
||||
const u8 *meshid, *meshcfg;
|
||||
|
@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
|||
found->pub.capability = res->pub.capability;
|
||||
found->ts = res->ts;
|
||||
|
||||
/* overwrite IEs */
|
||||
if (overwrite) {
|
||||
/* Update IEs */
|
||||
if (res->pub.proberesp_ies) {
|
||||
size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
|
||||
size_t ielen = res->pub.len_information_elements;
|
||||
size_t ielen = res->pub.len_proberesp_ies;
|
||||
|
||||
if (!found->ies_allocated && ksize(found) >= used + ielen) {
|
||||
memcpy(found->pub.information_elements,
|
||||
res->pub.information_elements, ielen);
|
||||
found->pub.len_information_elements = ielen;
|
||||
if (found->pub.proberesp_ies &&
|
||||
!found->proberesp_ies_allocated &&
|
||||
ksize(found) >= used + ielen) {
|
||||
memcpy(found->pub.proberesp_ies,
|
||||
res->pub.proberesp_ies, ielen);
|
||||
found->pub.len_proberesp_ies = ielen;
|
||||
} else {
|
||||
u8 *ies = found->pub.information_elements;
|
||||
u8 *ies = found->pub.proberesp_ies;
|
||||
|
||||
if (found->ies_allocated)
|
||||
if (found->proberesp_ies_allocated)
|
||||
ies = krealloc(ies, ielen, GFP_ATOMIC);
|
||||
else
|
||||
ies = kmalloc(ielen, GFP_ATOMIC);
|
||||
|
||||
if (ies) {
|
||||
memcpy(ies, res->pub.information_elements, ielen);
|
||||
found->ies_allocated = true;
|
||||
found->pub.information_elements = ies;
|
||||
found->pub.len_information_elements = ielen;
|
||||
memcpy(ies, res->pub.proberesp_ies,
|
||||
ielen);
|
||||
found->proberesp_ies_allocated = true;
|
||||
found->pub.proberesp_ies = ies;
|
||||
found->pub.len_proberesp_ies = ielen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Override possible earlier Beacon frame IEs */
|
||||
found->pub.information_elements =
|
||||
found->pub.proberesp_ies;
|
||||
found->pub.len_information_elements =
|
||||
found->pub.len_proberesp_ies;
|
||||
}
|
||||
if (res->pub.beacon_ies) {
|
||||
size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
|
||||
size_t ielen = res->pub.len_beacon_ies;
|
||||
|
||||
if (found->pub.beacon_ies &&
|
||||
!found->beacon_ies_allocated &&
|
||||
ksize(found) >= used + ielen) {
|
||||
memcpy(found->pub.beacon_ies,
|
||||
res->pub.beacon_ies, ielen);
|
||||
found->pub.len_beacon_ies = ielen;
|
||||
} else {
|
||||
u8 *ies = found->pub.beacon_ies;
|
||||
|
||||
if (found->beacon_ies_allocated)
|
||||
ies = krealloc(ies, ielen, GFP_ATOMIC);
|
||||
else
|
||||
ies = kmalloc(ielen, GFP_ATOMIC);
|
||||
|
||||
if (ies) {
|
||||
memcpy(ies, res->pub.beacon_ies,
|
||||
ielen);
|
||||
found->beacon_ies_allocated = true;
|
||||
found->pub.beacon_ies = ies;
|
||||
found->pub.len_beacon_ies = ielen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy,
|
|||
res->pub.tsf = timestamp;
|
||||
res->pub.beacon_interval = beacon_interval;
|
||||
res->pub.capability = capability;
|
||||
/* point to after the private area */
|
||||
res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
|
||||
memcpy(res->pub.information_elements, ie, ielen);
|
||||
res->pub.len_information_elements = ielen;
|
||||
/*
|
||||
* Since we do not know here whether the IEs are from a Beacon or Probe
|
||||
* Response frame, we need to pick one of the options and only use it
|
||||
* with the driver that does not provide the full Beacon/Probe Response
|
||||
* frame. Use Beacon frame pointer to avoid indicating that this should
|
||||
* override the information_elements pointer should we have received an
|
||||
* earlier indication of Probe Response data.
|
||||
*
|
||||
* The initial buffer for the IEs is allocated with the BSS entry and
|
||||
* is located after the private area.
|
||||
*/
|
||||
res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz;
|
||||
memcpy(res->pub.beacon_ies, ie, ielen);
|
||||
res->pub.len_beacon_ies = ielen;
|
||||
res->pub.information_elements = res->pub.beacon_ies;
|
||||
res->pub.len_information_elements = res->pub.len_beacon_ies;
|
||||
|
||||
kref_init(&res->ref);
|
||||
|
||||
res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0);
|
||||
res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
|
@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
|||
struct cfg80211_internal_bss *res;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
bool overwrite;
|
||||
size_t privsz = wiphy->bss_priv_size;
|
||||
|
||||
if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
|
||||
|
@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
|||
res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
/* point to after the private area */
|
||||
res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
|
||||
memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen);
|
||||
res->pub.len_information_elements = ielen;
|
||||
/*
|
||||
* The initial buffer for the IEs is allocated with the BSS entry and
|
||||
* is located after the private area.
|
||||
*/
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz;
|
||||
memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable,
|
||||
ielen);
|
||||
res->pub.len_proberesp_ies = ielen;
|
||||
res->pub.information_elements = res->pub.proberesp_ies;
|
||||
res->pub.len_information_elements = res->pub.len_proberesp_ies;
|
||||
} else {
|
||||
res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
|
||||
memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
|
||||
res->pub.len_beacon_ies = ielen;
|
||||
res->pub.information_elements = res->pub.beacon_ies;
|
||||
res->pub.len_information_elements = res->pub.len_beacon_ies;
|
||||
}
|
||||
|
||||
kref_init(&res->ref);
|
||||
|
||||
overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
|
||||
|
||||
res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
|
||||
res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
* - and country_ie[1] which is the IE length
|
||||
*/
|
||||
regulatory_hint_11d(wdev->wiphy,
|
||||
bss->channel->band,
|
||||
country_ie + 2,
|
||||
country_ie[1]);
|
||||
}
|
||||
|
|
|
@ -1204,21 +1204,47 @@ int cfg80211_wext_siwrate(struct net_device *dev,
|
|||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct cfg80211_bitrate_mask mask;
|
||||
u32 fixed, maxrate;
|
||||
struct ieee80211_supported_band *sband;
|
||||
int band, ridx;
|
||||
bool match = false;
|
||||
|
||||
if (!rdev->ops->set_bitrate_mask)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mask.fixed = 0;
|
||||
mask.maxrate = 0;
|
||||
memset(&mask, 0, sizeof(mask));
|
||||
fixed = 0;
|
||||
maxrate = 0;
|
||||
|
||||
if (rate->value < 0) {
|
||||
/* nothing */
|
||||
} else if (rate->fixed) {
|
||||
mask.fixed = rate->value / 1000; /* kbps */
|
||||
fixed = rate->value / 100000;
|
||||
} else {
|
||||
mask.maxrate = rate->value / 1000; /* kbps */
|
||||
maxrate = rate->value / 100000;
|
||||
}
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
sband = wdev->wiphy->bands[band];
|
||||
if (sband == NULL)
|
||||
continue;
|
||||
for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
|
||||
struct ieee80211_rate *srate = &sband->bitrates[ridx];
|
||||
if (fixed == srate->bitrate) {
|
||||
mask.control[band].legacy = 1 << ridx;
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
if (srate->bitrate <= maxrate) {
|
||||
mask.control[band].legacy |= 1 << ridx;
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
|
||||
|
|
Loading…
Reference in a new issue