mirror of https://gitee.com/openkylin/linux.git
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: net/mac80211/pm.c
This commit is contained in:
commit
495a1b4eff
|
@ -12,38 +12,22 @@ following format:
|
|||
The radiotap format is discussed in
|
||||
./Documentation/networking/radiotap-headers.txt.
|
||||
|
||||
Despite 13 radiotap argument types are currently defined, most only make sense
|
||||
Despite many radiotap parameters being currently defined, most only make sense
|
||||
to appear on received packets. The following information is parsed from the
|
||||
radiotap headers and used to control injection:
|
||||
|
||||
* IEEE80211_RADIOTAP_RATE
|
||||
|
||||
rate in 500kbps units, automatic if invalid or not present
|
||||
|
||||
|
||||
* IEEE80211_RADIOTAP_ANTENNA
|
||||
|
||||
antenna to use, automatic if not present
|
||||
|
||||
|
||||
* IEEE80211_RADIOTAP_DBM_TX_POWER
|
||||
|
||||
transmit power in dBm, automatic if not present
|
||||
|
||||
|
||||
* IEEE80211_RADIOTAP_FLAGS
|
||||
|
||||
IEEE80211_RADIOTAP_F_FCS: FCS will be removed and recalculated
|
||||
IEEE80211_RADIOTAP_F_WEP: frame will be encrypted if key available
|
||||
IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
|
||||
current fragmentation threshold. Note that
|
||||
this flag is only reliable when software
|
||||
fragmentation is enabled)
|
||||
current fragmentation threshold.
|
||||
|
||||
|
||||
The injection code can also skip all other currently defined radiotap fields
|
||||
facilitating replay of captured radiotap headers directly.
|
||||
|
||||
Here is an example valid radiotap header defining these three parameters
|
||||
Here is an example valid radiotap header defining some parameters
|
||||
|
||||
0x00, 0x00, // <-- radiotap version
|
||||
0x0b, 0x00, // <- radiotap header length
|
||||
|
@ -72,8 +56,8 @@ interface), along the following lines:
|
|||
...
|
||||
r = pcap_inject(ppcap, u8aSendBuffer, nLength);
|
||||
|
||||
You can also find sources for a complete inject test applet here:
|
||||
You can also find a link to a complete inject application here:
|
||||
|
||||
http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer
|
||||
http://wireless.kernel.org/en/users/Documentation/packetspammer
|
||||
|
||||
Andy Green <andy@warmcat.com>
|
||||
|
|
|
@ -521,16 +521,12 @@ status of the system.
|
|||
Input devices may issue events that are related to rfkill. These are the
|
||||
various KEY_* events and SW_* events supported by rfkill-input.c.
|
||||
|
||||
******IMPORTANT******
|
||||
When rfkill-input is ACTIVE, userspace is NOT TO CHANGE THE STATE OF AN RFKILL
|
||||
SWITCH IN RESPONSE TO AN INPUT EVENT also handled by rfkill-input, unless it
|
||||
has set to true the user_claim attribute for that particular switch. This rule
|
||||
is *absolute*; do NOT violate it.
|
||||
******IMPORTANT******
|
||||
Userspace may not change the state of an rfkill switch in response to an
|
||||
input event, it should refrain from changing states entirely.
|
||||
|
||||
Userspace must not assume it is the only source of control for rfkill switches.
|
||||
Their state CAN and WILL change due to firmware actions, direct user actions,
|
||||
and the rfkill-input EPO override for *_RFKILL_ALL.
|
||||
Userspace cannot assume it is the only source of control for rfkill switches.
|
||||
Their state can change due to firmware actions, direct user actions, and the
|
||||
rfkill-input EPO override for *_RFKILL_ALL.
|
||||
|
||||
When rfkill-input is not active, userspace must initiate a rfkill status
|
||||
change by writing to the "state" attribute in order for anything to happen.
|
||||
|
|
10
MAINTAINERS
10
MAINTAINERS
|
@ -888,6 +888,12 @@ P: Luis R. Rodriguez
|
|||
M: lrodriguez@atheros.com
|
||||
P: Jouni Malinen
|
||||
M: jmalinen@atheros.com
|
||||
P: Sujith Manoharan
|
||||
M: Sujith.Manoharan@atheros.com
|
||||
P: Vasanthakumar Thiagarajan
|
||||
M: vasanth@atheros.com
|
||||
P: Senthil Balasubramanian
|
||||
M: senthilkumar@atheros.com
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: ath9k-devel@lists.ath9k.org
|
||||
S: Supported
|
||||
|
@ -4421,8 +4427,8 @@ S: Maintained
|
|||
F: drivers/ata/sata_promise.*
|
||||
|
||||
PS3 NETWORK SUPPORT
|
||||
P: Masakazu Mokuno
|
||||
M: mokuno@sm.sony.co.jp
|
||||
P: Geoff Levand
|
||||
M: geoffrey.levand@am.sony.com
|
||||
L: netdev@vger.kernel.org
|
||||
L: cbe-oss-dev@ozlabs.org
|
||||
S: Supported
|
||||
|
|
|
@ -38,9 +38,9 @@ static void tosa_bt_off(struct tosa_bt_data *data)
|
|||
static int tosa_bt_toggle_radio(void *data, enum rfkill_state state)
|
||||
{
|
||||
pr_info("BT_RADIO going: %s\n",
|
||||
state == RFKILL_STATE_ON ? "on" : "off");
|
||||
state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
|
||||
|
||||
if (state == RFKILL_STATE_ON) {
|
||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
||||
pr_info("TOSA_BT: going ON\n");
|
||||
tosa_bt_on(data);
|
||||
} else {
|
||||
|
|
|
@ -2484,7 +2484,7 @@ static int add_net_device(struct hso_device *hso_dev)
|
|||
static int hso_radio_toggle(void *data, enum rfkill_state state)
|
||||
{
|
||||
struct hso_device *hso_dev = data;
|
||||
int enabled = (state == RFKILL_STATE_ON);
|
||||
int enabled = (state == RFKILL_STATE_UNBLOCKED);
|
||||
int rv;
|
||||
|
||||
mutex_lock(&hso_dev->mutex);
|
||||
|
@ -2522,7 +2522,7 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
|
|||
snprintf(rfkn, 20, "hso-%d",
|
||||
interface->altsetting->desc.bInterfaceNumber);
|
||||
hso_net->rfkill->name = rfkn;
|
||||
hso_net->rfkill->state = RFKILL_STATE_ON;
|
||||
hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
hso_net->rfkill->data = hso_dev;
|
||||
hso_net->rfkill->toggle_radio = hso_radio_toggle;
|
||||
if (rfkill_register(hso_net->rfkill) < 0) {
|
||||
|
|
|
@ -146,10 +146,10 @@ config LIBERTAS_CS
|
|||
A driver for Marvell Libertas 8385 CompactFlash devices.
|
||||
|
||||
config LIBERTAS_SDIO
|
||||
tristate "Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards"
|
||||
tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
|
||||
depends on LIBERTAS && MMC
|
||||
---help---
|
||||
A driver for Marvell Libertas 8385 and 8686 SDIO devices.
|
||||
A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
|
||||
|
||||
config LIBERTAS_SPI
|
||||
tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
|
||||
|
@ -337,6 +337,7 @@ config USB_NET_RNDIS_WLAN
|
|||
select USB_NET_CDCETHER
|
||||
select USB_NET_RNDIS_HOST
|
||||
select WIRELESS_EXT
|
||||
select CFG80211
|
||||
---help---
|
||||
This is a driver for wireless RNDIS devices.
|
||||
These are USB based adapters found in devices such as:
|
||||
|
@ -433,6 +434,13 @@ config RTL8187
|
|||
|
||||
Thanks to Realtek for their support!
|
||||
|
||||
# If possible, automatically enable LEDs for RTL8187.
|
||||
|
||||
config RTL8187_LEDS
|
||||
bool
|
||||
depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
|
||||
default y
|
||||
|
||||
config ADM8211
|
||||
tristate "ADMtek ADM8211 support"
|
||||
depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
|
||||
|
@ -483,9 +491,7 @@ config MWL8K
|
|||
will be called mwl8k. If unsure, say N.
|
||||
|
||||
source "drivers/net/wireless/p54/Kconfig"
|
||||
source "drivers/net/wireless/ath5k/Kconfig"
|
||||
source "drivers/net/wireless/ath9k/Kconfig"
|
||||
source "drivers/net/wireless/ar9170/Kconfig"
|
||||
source "drivers/net/wireless/ath/Kconfig"
|
||||
source "drivers/net/wireless/ipw2x00/Kconfig"
|
||||
source "drivers/net/wireless/iwlwifi/Kconfig"
|
||||
source "drivers/net/wireless/hostap/Kconfig"
|
||||
|
|
|
@ -55,8 +55,6 @@ obj-$(CONFIG_RT2X00) += rt2x00/
|
|||
|
||||
obj-$(CONFIG_P54_COMMON) += p54/
|
||||
|
||||
obj-$(CONFIG_ATH5K) += ath5k/
|
||||
obj-$(CONFIG_ATH9K) += ath9k/
|
||||
obj-$(CONFIG_AR9170_USB) += ar9170/
|
||||
obj-$(CONFIG_ATH_COMMON) += ath/
|
||||
|
||||
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
|
||||
|
|
|
@ -2250,6 +2250,7 @@ static int at76_init_new_device(struct at76_priv *priv,
|
|||
|
||||
/* mac80211 initialisation */
|
||||
priv->hw->wiphy->max_scan_ssids = 1;
|
||||
priv->hw->wiphy->max_scan_ie_len = 0;
|
||||
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
|
||||
priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
config ATH_COMMON
|
||||
tristate "Atheros Wireless Cards"
|
||||
depends on ATH5K || ATH9K || AR9170_USB
|
||||
|
||||
source "drivers/net/wireless/ath/ath5k/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath9k/Kconfig"
|
||||
source "drivers/net/wireless/ath/ar9170/Kconfig"
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
obj-$(CONFIG_ATH5K) += ath5k/
|
||||
obj-$(CONFIG_ATH9K) += ath9k/
|
||||
obj-$(CONFIG_AR9170_USB) += ar9170/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
ath-objs := main.o regd.o
|
|
@ -2,6 +2,7 @@ config AR9170_USB
|
|||
tristate "Atheros AR9170 802.11n USB support"
|
||||
depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
|
||||
select FW_LOADER
|
||||
select ATH_COMMON
|
||||
help
|
||||
This is a driver for the Atheros "otus" 802.11n USB devices.
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#ifdef CONFIG_AR9170_LEDS
|
||||
#include <linux/leds.h>
|
||||
|
@ -48,6 +48,8 @@
|
|||
#include "eeprom.h"
|
||||
#include "hw.h"
|
||||
|
||||
#include "../regd.h"
|
||||
|
||||
#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1)
|
||||
|
||||
enum ar9170_bw {
|
||||
|
@ -58,6 +60,21 @@ enum ar9170_bw {
|
|||
__AR9170_NUM_BW,
|
||||
};
|
||||
|
||||
static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
case NL80211_CHAN_HT20:
|
||||
return AR9170_BW_20;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
return AR9170_BW_40_BELOW;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
return AR9170_BW_40_ABOVE;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
enum ar9170_rf_init_mode {
|
||||
AR9170_RFI_NONE,
|
||||
AR9170_RFI_WARM,
|
||||
|
@ -87,10 +104,16 @@ enum ar9170_device_state {
|
|||
AR9170_ASSOCIATED,
|
||||
};
|
||||
|
||||
struct ar9170_rxstream_mpdu_merge {
|
||||
struct ar9170_rx_head plcp;
|
||||
bool has_plcp;
|
||||
};
|
||||
|
||||
struct ar9170 {
|
||||
struct ieee80211_hw *hw;
|
||||
struct mutex mutex;
|
||||
enum ar9170_device_state state;
|
||||
unsigned long bad_hw_nagger;
|
||||
|
||||
int (*open)(struct ar9170 *);
|
||||
void (*stop)(struct ar9170 *);
|
||||
|
@ -118,6 +141,7 @@ struct ar9170 {
|
|||
u64 cur_mc_hash, want_mc_hash;
|
||||
u32 cur_filter, want_filter;
|
||||
unsigned int filter_changed;
|
||||
unsigned int filter_state;
|
||||
bool sniffer_enabled;
|
||||
|
||||
/* PHY */
|
||||
|
@ -151,11 +175,17 @@ struct ar9170 {
|
|||
|
||||
/* EEPROM */
|
||||
struct ar9170_eeprom eeprom;
|
||||
struct ath_regulatory regulatory;
|
||||
|
||||
/* global tx status for unregistered Stations. */
|
||||
struct sk_buff_head global_tx_status;
|
||||
struct sk_buff_head global_tx_status_waste;
|
||||
struct delayed_work tx_status_janitor;
|
||||
|
||||
/* rxstream mpdu merge */
|
||||
struct ar9170_rxstream_mpdu_merge rx_mpdu;
|
||||
struct sk_buff *rx_failover;
|
||||
int rx_failover_missing;
|
||||
};
|
||||
|
||||
struct ar9170_sta_info {
|
|
@ -312,7 +312,7 @@ struct ar9170_rx_head {
|
|||
u8 plcp[12];
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_tail {
|
||||
struct ar9170_rx_phystatus {
|
||||
union {
|
||||
struct {
|
||||
u8 rssi_ant0, rssi_ant1, rssi_ant2,
|
||||
|
@ -324,6 +324,9 @@ struct ar9170_rx_tail {
|
|||
|
||||
u8 evm_stream0[6], evm_stream1[6];
|
||||
u8 phy_err;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_macstatus {
|
||||
u8 SAidx, DAidx;
|
||||
u8 error;
|
||||
u8 status;
|
||||
|
@ -339,7 +342,7 @@ struct ar9170_rx_tail {
|
|||
|
||||
#define AR9170_RX_ENC_SOFTWARE 0x8
|
||||
|
||||
static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
|
||||
static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
|
||||
{
|
||||
return (t->SAidx & 0xc0) >> 4 |
|
||||
(t->DAidx & 0xc0) >> 6;
|
||||
|
@ -357,10 +360,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
|
|||
|
||||
#define AR9170_RX_STATUS_MPDU_MASK 0x30
|
||||
#define AR9170_RX_STATUS_MPDU_SINGLE 0x00
|
||||
#define AR9170_RX_STATUS_MPDU_FIRST 0x10
|
||||
#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20
|
||||
#define AR9170_RX_STATUS_MPDU_LAST 0x30
|
||||
|
||||
#define AR9170_RX_STATUS_MPDU_FIRST 0x20
|
||||
#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30
|
||||
#define AR9170_RX_STATUS_MPDU_LAST 0x10
|
||||
|
||||
#define AR9170_RX_ERROR_RXTO 0x01
|
||||
#define AR9170_RX_ERROR_OVERRUN 0x02
|
||||
|
@ -369,6 +371,7 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
|
|||
#define AR9170_RX_ERROR_WRONG_RA 0x10
|
||||
#define AR9170_RX_ERROR_PLCP 0x20
|
||||
#define AR9170_RX_ERROR_MMIC 0x40
|
||||
#define AR9170_RX_ERROR_FATAL 0x80
|
||||
|
||||
struct ar9170_cmd_tx_status {
|
||||
__le16 unkn;
|
|
@ -142,11 +142,36 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
|
|||
};
|
||||
#undef CHAN
|
||||
|
||||
#define AR9170_HT_CAP \
|
||||
{ \
|
||||
.ht_supported = true, \
|
||||
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
|
||||
IEEE80211_HT_CAP_SM_PS | \
|
||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
|
||||
IEEE80211_HT_CAP_SGI_40 | \
|
||||
IEEE80211_HT_CAP_DSSSCCK40 | \
|
||||
IEEE80211_HT_CAP_SM_PS, \
|
||||
.ampdu_factor = 3, /* ?? */ \
|
||||
.ampdu_density = 7, /* ?? */ \
|
||||
.mcs = { \
|
||||
.rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static struct ieee80211_supported_band ar9170_band_2GHz = {
|
||||
.channels = ar9170_2ghz_chantable,
|
||||
.n_channels = ARRAY_SIZE(ar9170_2ghz_chantable),
|
||||
.bitrates = ar9170_g_ratetable,
|
||||
.n_bitrates = ar9170_g_ratetable_size,
|
||||
.ht_cap = AR9170_HT_CAP,
|
||||
};
|
||||
|
||||
static struct ieee80211_supported_band ar9170_band_5GHz = {
|
||||
.channels = ar9170_5ghz_chantable,
|
||||
.n_channels = ARRAY_SIZE(ar9170_5ghz_chantable),
|
||||
.bitrates = ar9170_a_ratetable,
|
||||
.n_bitrates = ar9170_a_ratetable_size,
|
||||
.ht_cap = AR9170_HT_CAP,
|
||||
};
|
||||
|
||||
#ifdef AR9170_QUEUE_DEBUG
|
||||
|
@ -190,13 +215,6 @@ static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar,
|
|||
}
|
||||
#endif /* AR9170_QUEUE_DEBUG */
|
||||
|
||||
static struct ieee80211_supported_band ar9170_band_5GHz = {
|
||||
.channels = ar9170_5ghz_chantable,
|
||||
.n_channels = ARRAY_SIZE(ar9170_5ghz_chantable),
|
||||
.bitrates = ar9170_a_ratetable,
|
||||
.n_bitrates = ar9170_a_ratetable_size,
|
||||
};
|
||||
|
||||
void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
|
||||
bool valid_status, u16 tx_status)
|
||||
{
|
||||
|
@ -436,214 +454,430 @@ static void ar9170_handle_command_response(struct ar9170 *ar,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the frame alignment is right (or the kernel has
|
||||
* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
|
||||
* is only a single MPDU in the USB frame, then we can
|
||||
* submit to mac80211 the SKB directly. However, since
|
||||
* there may be multiple packets in one SKB in stream
|
||||
* mode, and we need to observe the proper ordering,
|
||||
* this is non-trivial.
|
||||
*/
|
||||
static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
|
||||
static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct ar9170_rx_head *head = (void *)buf;
|
||||
struct ar9170_rx_tail *tail;
|
||||
struct ieee80211_rx_status status;
|
||||
int mpdu_len, i;
|
||||
u8 error, antennas = 0, decrypt;
|
||||
__le16 fc;
|
||||
int reserved;
|
||||
memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head));
|
||||
ar->rx_mpdu.has_plcp = false;
|
||||
}
|
||||
|
||||
if (unlikely(!IS_STARTED(ar)))
|
||||
return ;
|
||||
static int ar9170_nag_limiter(struct ar9170 *ar)
|
||||
{
|
||||
bool print_message;
|
||||
|
||||
/*
|
||||
* we expect all sorts of errors in promiscuous mode.
|
||||
* don't bother with it, it's OK!
|
||||
*/
|
||||
if (ar->sniffer_enabled)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* only go for frequent errors! The hardware tends to
|
||||
* do some stupid thing once in a while under load, in
|
||||
* noisy environments or just for fun!
|
||||
*/
|
||||
if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit())
|
||||
print_message = true;
|
||||
else
|
||||
print_message = false;
|
||||
|
||||
/* reset threshold for "once in a while" */
|
||||
ar->bad_hw_nagger = jiffies + HZ / 4;
|
||||
return print_message;
|
||||
}
|
||||
|
||||
static int ar9170_rx_mac_status(struct ar9170 *ar,
|
||||
struct ar9170_rx_head *head,
|
||||
struct ar9170_rx_macstatus *mac,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
u8 error, decrypt;
|
||||
|
||||
/* Received MPDU */
|
||||
mpdu_len = len;
|
||||
mpdu_len -= sizeof(struct ar9170_rx_head);
|
||||
mpdu_len -= sizeof(struct ar9170_rx_tail);
|
||||
BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
|
||||
BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24);
|
||||
|
||||
if (mpdu_len <= FCS_LEN)
|
||||
return;
|
||||
|
||||
tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (tail->rssi[i] != 0x80)
|
||||
antennas |= BIT(i);
|
||||
|
||||
/* post-process RSSI */
|
||||
for (i = 0; i < 7; i++)
|
||||
if (tail->rssi[i] & 0x80)
|
||||
tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f;
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
|
||||
status.band = ar->channel->band;
|
||||
status.freq = ar->channel->center_freq;
|
||||
status.signal = ar->noise[0] + tail->rssi_combined;
|
||||
status.noise = ar->noise[0];
|
||||
status.antenna = antennas;
|
||||
|
||||
switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) {
|
||||
case AR9170_RX_STATUS_MODULATION_CCK:
|
||||
if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
|
||||
status.flag |= RX_FLAG_SHORTPRE;
|
||||
switch (head->plcp[0]) {
|
||||
case 0x0a:
|
||||
status.rate_idx = 0;
|
||||
break;
|
||||
case 0x14:
|
||||
status.rate_idx = 1;
|
||||
break;
|
||||
case 0x37:
|
||||
status.rate_idx = 2;
|
||||
break;
|
||||
case 0x6e:
|
||||
status.rate_idx = 3;
|
||||
break;
|
||||
default:
|
||||
if ((!ar->sniffer_enabled) && (net_ratelimit()))
|
||||
printk(KERN_ERR "%s: invalid plcp cck rate "
|
||||
"(%x).\n", wiphy_name(ar->hw->wiphy),
|
||||
head->plcp[0]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AR9170_RX_STATUS_MODULATION_OFDM:
|
||||
switch (head->plcp[0] & 0xF) {
|
||||
case 0xB:
|
||||
status.rate_idx = 0;
|
||||
break;
|
||||
case 0xF:
|
||||
status.rate_idx = 1;
|
||||
break;
|
||||
case 0xA:
|
||||
status.rate_idx = 2;
|
||||
break;
|
||||
case 0xE:
|
||||
status.rate_idx = 3;
|
||||
break;
|
||||
case 0x9:
|
||||
status.rate_idx = 4;
|
||||
break;
|
||||
case 0xD:
|
||||
status.rate_idx = 5;
|
||||
break;
|
||||
case 0x8:
|
||||
status.rate_idx = 6;
|
||||
break;
|
||||
case 0xC:
|
||||
status.rate_idx = 7;
|
||||
break;
|
||||
default:
|
||||
if ((!ar->sniffer_enabled) && (net_ratelimit()))
|
||||
printk(KERN_ERR "%s: invalid plcp ofdm rate "
|
||||
"(%x).\n", wiphy_name(ar->hw->wiphy),
|
||||
head->plcp[0]);
|
||||
return;
|
||||
}
|
||||
if (status.band == IEEE80211_BAND_2GHZ)
|
||||
status.rate_idx += 4;
|
||||
break;
|
||||
case AR9170_RX_STATUS_MODULATION_HT:
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
/* XXX */
|
||||
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "%s: invalid modulation\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
return;
|
||||
}
|
||||
|
||||
error = tail->error;
|
||||
BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
|
||||
|
||||
error = mac->error;
|
||||
if (error & AR9170_RX_ERROR_MMIC) {
|
||||
status.flag |= RX_FLAG_MMIC_ERROR;
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
error &= ~AR9170_RX_ERROR_MMIC;
|
||||
}
|
||||
|
||||
if (error & AR9170_RX_ERROR_PLCP) {
|
||||
status.flag |= RX_FLAG_FAILED_PLCP_CRC;
|
||||
status->flag |= RX_FLAG_FAILED_PLCP_CRC;
|
||||
error &= ~AR9170_RX_ERROR_PLCP;
|
||||
|
||||
if (!(ar->filter_state & FIF_PLCPFAIL))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (error & AR9170_RX_ERROR_FCS) {
|
||||
status.flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
error &= ~AR9170_RX_ERROR_FCS;
|
||||
|
||||
if (!(ar->filter_state & FIF_FCSFAIL))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
decrypt = ar9170_get_decrypt_type(tail);
|
||||
decrypt = ar9170_get_decrypt_type(mac);
|
||||
if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
|
||||
decrypt != AR9170_ENC_ALG_NONE)
|
||||
status.flag |= RX_FLAG_DECRYPTED;
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
/* ignore wrong RA errors */
|
||||
error &= ~AR9170_RX_ERROR_WRONG_RA;
|
||||
|
||||
if (error & AR9170_RX_ERROR_DECRYPT) {
|
||||
error &= ~AR9170_RX_ERROR_DECRYPT;
|
||||
|
||||
/*
|
||||
* Rx decryption is done in place,
|
||||
* the original data is lost anyway.
|
||||
*/
|
||||
return ;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* drop any other error frames */
|
||||
if ((error) && (net_ratelimit())) {
|
||||
printk(KERN_DEBUG "%s: errors: %#x\n",
|
||||
wiphy_name(ar->hw->wiphy), error);
|
||||
return;
|
||||
if (unlikely(error)) {
|
||||
/* TODO: update netdevice's RX dropped/errors statistics */
|
||||
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_DEBUG "%s: received frame with "
|
||||
"suspicious error code (%#x).\n",
|
||||
wiphy_name(ar->hw->wiphy), error);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf += sizeof(struct ar9170_rx_head);
|
||||
fc = *(__le16 *)buf;
|
||||
status->band = ar->channel->band;
|
||||
status->freq = ar->channel->center_freq;
|
||||
|
||||
if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc))
|
||||
reserved = 32 + 2;
|
||||
else
|
||||
reserved = 32;
|
||||
switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) {
|
||||
case AR9170_RX_STATUS_MODULATION_CCK:
|
||||
if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
|
||||
status->flag |= RX_FLAG_SHORTPRE;
|
||||
switch (head->plcp[0]) {
|
||||
case 0x0a:
|
||||
status->rate_idx = 0;
|
||||
break;
|
||||
case 0x14:
|
||||
status->rate_idx = 1;
|
||||
break;
|
||||
case 0x37:
|
||||
status->rate_idx = 2;
|
||||
break;
|
||||
case 0x6e:
|
||||
status->rate_idx = 3;
|
||||
break;
|
||||
default:
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: invalid plcp cck rate "
|
||||
"(%x).\n", wiphy_name(ar->hw->wiphy),
|
||||
head->plcp[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
skb = dev_alloc_skb(mpdu_len + reserved);
|
||||
if (!skb)
|
||||
return;
|
||||
case AR9170_RX_STATUS_MODULATION_OFDM:
|
||||
switch (head->plcp[0] & 0xf) {
|
||||
case 0xb:
|
||||
status->rate_idx = 0;
|
||||
break;
|
||||
case 0xf:
|
||||
status->rate_idx = 1;
|
||||
break;
|
||||
case 0xa:
|
||||
status->rate_idx = 2;
|
||||
break;
|
||||
case 0xe:
|
||||
status->rate_idx = 3;
|
||||
break;
|
||||
case 0x9:
|
||||
status->rate_idx = 4;
|
||||
break;
|
||||
case 0xd:
|
||||
status->rate_idx = 5;
|
||||
break;
|
||||
case 0x8:
|
||||
status->rate_idx = 6;
|
||||
break;
|
||||
case 0xc:
|
||||
status->rate_idx = 7;
|
||||
break;
|
||||
default:
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: invalid plcp ofdm rate "
|
||||
"(%x).\n", wiphy_name(ar->hw->wiphy),
|
||||
head->plcp[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (status->band == IEEE80211_BAND_2GHZ)
|
||||
status->rate_idx += 4;
|
||||
break;
|
||||
|
||||
skb_reserve(skb, reserved);
|
||||
memcpy(skb_put(skb, mpdu_len), buf, mpdu_len);
|
||||
ieee80211_rx_irqsafe(ar->hw, skb, &status);
|
||||
case AR9170_RX_STATUS_MODULATION_HT:
|
||||
if (head->plcp[3] & 0x80)
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
if (head->plcp[6] & 0x80)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
|
||||
status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f);
|
||||
status->flag |= RX_FLAG_HT;
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
/* XXX */
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: invalid modulation\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ar9170_rx_phy_status(struct ar9170 *ar,
|
||||
struct ar9170_rx_phystatus *phy,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (phy->rssi[i] != 0x80)
|
||||
status->antenna |= BIT(i);
|
||||
|
||||
/* post-process RSSI */
|
||||
for (i = 0; i < 7; i++)
|
||||
if (phy->rssi[i] & 0x80)
|
||||
phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
|
||||
|
||||
/* TODO: we could do something with phy_errors */
|
||||
status->signal = ar->noise[0] + phy->rssi_combined;
|
||||
status->noise = ar->noise[0];
|
||||
}
|
||||
|
||||
static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int reserved = 0;
|
||||
struct ieee80211_hdr *hdr = (void *) buf;
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
u8 *qc = ieee80211_get_qos_ctl(hdr);
|
||||
reserved += NET_IP_ALIGN;
|
||||
|
||||
if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
|
||||
reserved += NET_IP_ALIGN;
|
||||
}
|
||||
|
||||
if (ieee80211_has_a4(hdr->frame_control))
|
||||
reserved += NET_IP_ALIGN;
|
||||
|
||||
reserved = 32 + (reserved & NET_IP_ALIGN);
|
||||
|
||||
skb = dev_alloc_skb(len + reserved);
|
||||
if (likely(skb)) {
|
||||
skb_reserve(skb, reserved);
|
||||
memcpy(skb_put(skb, len), buf, len);
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the frame alignment is right (or the kernel has
|
||||
* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
|
||||
* is only a single MPDU in the USB frame, then we could
|
||||
* submit to mac80211 the SKB directly. However, since
|
||||
* there may be multiple packets in one SKB in stream
|
||||
* mode, and we need to observe the proper ordering,
|
||||
* this is non-trivial.
|
||||
*/
|
||||
|
||||
static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
|
||||
{
|
||||
struct ar9170_rx_head *head;
|
||||
struct ar9170_rx_macstatus *mac;
|
||||
struct ar9170_rx_phystatus *phy = NULL;
|
||||
struct ieee80211_rx_status status;
|
||||
struct sk_buff *skb;
|
||||
int mpdu_len;
|
||||
|
||||
if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac))))
|
||||
return ;
|
||||
|
||||
/* Received MPDU */
|
||||
mpdu_len = len - sizeof(*mac);
|
||||
|
||||
mac = (void *)(buf + mpdu_len);
|
||||
if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) {
|
||||
/* this frame is too damaged and can't be used - drop it */
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) {
|
||||
case AR9170_RX_STATUS_MPDU_FIRST:
|
||||
/* first mpdu packet has the plcp header */
|
||||
if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
|
||||
head = (void *) buf;
|
||||
memcpy(&ar->rx_mpdu.plcp, (void *) buf,
|
||||
sizeof(struct ar9170_rx_head));
|
||||
|
||||
mpdu_len -= sizeof(struct ar9170_rx_head);
|
||||
buf += sizeof(struct ar9170_rx_head);
|
||||
ar->rx_mpdu.has_plcp = true;
|
||||
} else {
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: plcp info is clipped.\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
return ;
|
||||
}
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_LAST:
|
||||
/* last mpdu has a extra tail with phy status information */
|
||||
|
||||
if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
|
||||
mpdu_len -= sizeof(struct ar9170_rx_phystatus);
|
||||
phy = (void *)(buf + mpdu_len);
|
||||
} else {
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: frame tail is clipped.\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
return ;
|
||||
}
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_MIDDLE:
|
||||
/* middle mpdus are just data */
|
||||
if (unlikely(!ar->rx_mpdu.has_plcp)) {
|
||||
if (!ar9170_nag_limiter(ar))
|
||||
return ;
|
||||
|
||||
printk(KERN_ERR "%s: rx stream did not start "
|
||||
"with a first_mpdu frame tag.\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
head = &ar->rx_mpdu.plcp;
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_SINGLE:
|
||||
/* single mpdu - has plcp (head) and phy status (tail) */
|
||||
head = (void *) buf;
|
||||
|
||||
mpdu_len -= sizeof(struct ar9170_rx_head);
|
||||
mpdu_len -= sizeof(struct ar9170_rx_phystatus);
|
||||
|
||||
buf += sizeof(struct ar9170_rx_head);
|
||||
phy = (void *)(buf + mpdu_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(mpdu_len < FCS_LEN))
|
||||
return ;
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status)))
|
||||
return ;
|
||||
|
||||
if (phy)
|
||||
ar9170_rx_phy_status(ar, phy, &status);
|
||||
|
||||
skb = ar9170_rx_copy_data(buf, mpdu_len);
|
||||
if (likely(skb))
|
||||
ieee80211_rx_irqsafe(ar->hw, skb, &status);
|
||||
}
|
||||
|
||||
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
|
||||
{
|
||||
unsigned int i, tlen, resplen;
|
||||
unsigned int i, tlen, resplen, wlen = 0, clen = 0;
|
||||
u8 *tbuf, *respbuf;
|
||||
|
||||
tbuf = skb->data;
|
||||
tlen = skb->len;
|
||||
|
||||
while (tlen >= 4) {
|
||||
int clen = tbuf[1] << 8 | tbuf[0];
|
||||
int wlen = (clen + 3) & ~3;
|
||||
clen = tbuf[1] << 8 | tbuf[0];
|
||||
wlen = ALIGN(clen, 4);
|
||||
|
||||
/*
|
||||
* parse stream (if any)
|
||||
*/
|
||||
/* check if this is stream has a valid tag.*/
|
||||
if (tbuf[2] != 0 || tbuf[3] != 0x4e) {
|
||||
printk(KERN_ERR "%s: missing tag!\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
/*
|
||||
* TODO: handle the highly unlikely event that the
|
||||
* corrupted stream has the TAG at the right position.
|
||||
*/
|
||||
|
||||
/* check if the frame can be repaired. */
|
||||
if (!ar->rx_failover_missing) {
|
||||
/* this is no "short read". */
|
||||
if (ar9170_nag_limiter(ar)) {
|
||||
printk(KERN_ERR "%s: missing tag!\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
goto err_telluser;
|
||||
} else
|
||||
goto err_silent;
|
||||
}
|
||||
|
||||
if (ar->rx_failover_missing > tlen) {
|
||||
if (ar9170_nag_limiter(ar)) {
|
||||
printk(KERN_ERR "%s: possible multi "
|
||||
"stream corruption!\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
goto err_telluser;
|
||||
} else
|
||||
goto err_silent;
|
||||
}
|
||||
|
||||
memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
|
||||
ar->rx_failover_missing -= tlen;
|
||||
|
||||
if (ar->rx_failover_missing <= 0) {
|
||||
/*
|
||||
* nested ar9170_rx call!
|
||||
* termination is guranteed, even when the
|
||||
* combined frame also have a element with
|
||||
* a bad tag.
|
||||
*/
|
||||
|
||||
ar->rx_failover_missing = 0;
|
||||
ar9170_rx(ar, ar->rx_failover);
|
||||
|
||||
skb_reset_tail_pointer(ar->rx_failover);
|
||||
skb_trim(ar->rx_failover, 0);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* check if stream is clipped */
|
||||
if (wlen > tlen - 4) {
|
||||
printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n",
|
||||
wiphy_name(ar->hw->wiphy), clen, wlen, tlen);
|
||||
print_hex_dump(KERN_DEBUG, "data: ",
|
||||
DUMP_PREFIX_OFFSET,
|
||||
16, 1, tbuf, tlen, true);
|
||||
if (ar->rx_failover_missing) {
|
||||
/* TODO: handle double stream corruption. */
|
||||
if (ar9170_nag_limiter(ar)) {
|
||||
printk(KERN_ERR "%s: double rx stream "
|
||||
"corruption!\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
goto err_telluser;
|
||||
} else
|
||||
goto err_silent;
|
||||
}
|
||||
|
||||
/*
|
||||
* save incomplete data set.
|
||||
* the firmware will resend the missing bits when
|
||||
* the rx - descriptor comes round again.
|
||||
*/
|
||||
|
||||
memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
|
||||
ar->rx_failover_missing = clen - tlen;
|
||||
return ;
|
||||
}
|
||||
resplen = clen;
|
||||
|
@ -668,12 +902,44 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
|
|||
if (i == 12)
|
||||
ar9170_handle_command_response(ar, respbuf, resplen);
|
||||
else
|
||||
ar9170_handle_mpdu(ar, respbuf, resplen);
|
||||
ar9170_handle_mpdu(ar, respbuf, clen);
|
||||
}
|
||||
|
||||
if (tlen)
|
||||
printk(KERN_ERR "%s: buffer remains!\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
if (tlen) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "%s: %d bytes of unprocessed "
|
||||
"data left in rx stream!\n",
|
||||
wiphy_name(ar->hw->wiphy), tlen);
|
||||
|
||||
goto err_telluser;
|
||||
}
|
||||
|
||||
return ;
|
||||
|
||||
err_telluser:
|
||||
printk(KERN_ERR "%s: damaged RX stream data [want:%d, "
|
||||
"data:%d, rx:%d, pending:%d ]\n",
|
||||
wiphy_name(ar->hw->wiphy), clen, wlen, tlen,
|
||||
ar->rx_failover_missing);
|
||||
|
||||
if (ar->rx_failover_missing)
|
||||
print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
|
||||
ar->rx_failover->data,
|
||||
ar->rx_failover->len);
|
||||
|
||||
print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
|
||||
skb->data, skb->len);
|
||||
|
||||
printk(KERN_ERR "%s: please check your hardware and cables, if "
|
||||
"you see this message frequently.\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
|
||||
err_silent:
|
||||
if (ar->rx_failover_missing) {
|
||||
skb_reset_tail_pointer(ar->rx_failover);
|
||||
skb_trim(ar->rx_failover, 0);
|
||||
ar->rx_failover_missing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \
|
||||
|
@ -703,6 +969,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
|
|||
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
|
||||
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
|
||||
|
||||
ar->bad_hw_nagger = jiffies;
|
||||
|
||||
err = ar->open(ar);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -742,8 +1010,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
|
|||
if (IS_STARTED(ar))
|
||||
ar->state = AR9170_IDLE;
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
flush_workqueue(ar->hw->workqueue);
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
cancel_delayed_work_sync(&ar->tx_status_janitor);
|
||||
cancel_work_sync(&ar->filter_config_work);
|
||||
cancel_work_sync(&ar->beacon_work);
|
||||
|
@ -1076,7 +1345,8 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
err = ar9170_set_channel(ar, hw->conf.channel,
|
||||
AR9170_RFI_NONE, AR9170_BW_20);
|
||||
AR9170_RFI_NONE,
|
||||
nl80211_to_ar9170(hw->conf.channel_type));
|
||||
if (err)
|
||||
goto out;
|
||||
/* adjust slot time for 5 GHz */
|
||||
|
@ -1123,10 +1393,10 @@ static void ar9170_set_filters(struct work_struct *work)
|
|||
filter_config_work);
|
||||
int err;
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
if (unlikely(!IS_STARTED(ar)))
|
||||
goto unlock;
|
||||
return ;
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) {
|
||||
err = ar9170_set_operating_mode(ar);
|
||||
if (err)
|
||||
|
@ -1155,8 +1425,8 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
|||
|
||||
/* mask supported flags */
|
||||
*new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
|
||||
FIF_PROMISC_IN_BSS;
|
||||
|
||||
FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
|
||||
ar->filter_state = *new_flags;
|
||||
/*
|
||||
* We can support more by setting the sniffer bit and
|
||||
* then checking the error flags, later.
|
||||
|
@ -1498,6 +1768,24 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
{
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
/*
|
||||
* Something goes wrong -- RX locks up
|
||||
* after a while of receiving aggregated
|
||||
* frames -- not enabling for now.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ar9170_ops = {
|
||||
.start = ar9170_op_start,
|
||||
.stop = ar9170_op_stop,
|
||||
|
@ -1514,26 +1802,40 @@ static const struct ieee80211_ops ar9170_ops = {
|
|||
.sta_notify = ar9170_sta_notify,
|
||||
.get_stats = ar9170_get_stats,
|
||||
.get_tx_stats = ar9170_get_tx_stats,
|
||||
.ampdu_action = ar9170_ampdu_action,
|
||||
};
|
||||
|
||||
void *ar9170_alloc(size_t priv_size)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
struct ar9170 *ar;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* this buffer is used for rx stream reconstruction.
|
||||
* Under heavy load this device (or the transport layer?)
|
||||
* tends to split the streams into seperate rx descriptors.
|
||||
*/
|
||||
|
||||
skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto err_nomem;
|
||||
|
||||
hw = ieee80211_alloc_hw(priv_size, &ar9170_ops);
|
||||
if (!hw)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto err_nomem;
|
||||
|
||||
ar = hw->priv;
|
||||
ar->hw = hw;
|
||||
ar->rx_failover = skb;
|
||||
|
||||
mutex_init(&ar->mutex);
|
||||
spin_lock_init(&ar->cmdlock);
|
||||
spin_lock_init(&ar->tx_stats_lock);
|
||||
skb_queue_head_init(&ar->global_tx_status);
|
||||
skb_queue_head_init(&ar->global_tx_status_waste);
|
||||
ar9170_rx_reset_rx_mpdu(ar);
|
||||
INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
|
||||
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
|
||||
INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor);
|
||||
|
@ -1561,6 +1863,10 @@ void *ar9170_alloc(size_t priv_size)
|
|||
ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
|
||||
|
||||
return ar;
|
||||
|
||||
err_nomem:
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static int ar9170_read_eeprom(struct ar9170 *ar)
|
||||
|
@ -1619,12 +1925,24 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
|
|||
else
|
||||
ar->hw->channel_change_time = 80 * 1000;
|
||||
|
||||
ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
|
||||
ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
|
||||
|
||||
/* second part of wiphy init */
|
||||
SET_IEEE80211_PERM_ADDR(ar->hw, addr);
|
||||
|
||||
return bands ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int ar9170_reg_notifier(struct wiphy *wiphy,
|
||||
struct regulatory_request *request)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ar9170 *ar = hw->priv;
|
||||
|
||||
return ath_reg_notifier_apply(wiphy, request, &ar->regulatory);
|
||||
}
|
||||
|
||||
int ar9170_register(struct ar9170 *ar, struct device *pdev)
|
||||
{
|
||||
int err;
|
||||
|
@ -1634,10 +1952,18 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
|
|||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = ath_regd_init(&ar->regulatory, ar->hw->wiphy,
|
||||
ar9170_reg_notifier);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = ieee80211_register_hw(ar->hw);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
if (!ath_is_world_regd(&ar->regulatory))
|
||||
regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2);
|
||||
|
||||
err = ar9170_init_leds(ar);
|
||||
if (err)
|
||||
goto err_unreg;
|
||||
|
@ -1666,6 +1992,7 @@ void ar9170_unregister(struct ar9170 *ar)
|
|||
ar9170_unregister_leds(ar);
|
||||
#endif /* CONFIG_AR9170_LEDS */
|
||||
|
||||
kfree_skb(ar->rx_failover);
|
||||
ieee80211_unregister_hw(ar->hw);
|
||||
mutex_destroy(&ar->mutex);
|
||||
}
|
|
@ -43,7 +43,7 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/leds.h>
|
||||
#include <net/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "eeprom.h"
|
|
@ -1,6 +1,7 @@
|
|||
config ATH5K
|
||||
tristate "Atheros 5xxx wireless cards support"
|
||||
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
|
||||
select ATH_COMMON
|
||||
select MAC80211_LEDS
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
|
@ -27,6 +27,8 @@
|
|||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "../regd.h"
|
||||
|
||||
/* RX/TX descriptor hw structs
|
||||
* TODO: Driver part should only see sw structs */
|
||||
#include "desc.h"
|
||||
|
@ -1039,8 +1041,6 @@ struct ath5k_hw {
|
|||
bool ah_5ghz;
|
||||
bool ah_2ghz;
|
||||
|
||||
#define ah_regdomain ah_capabilities.cap_regdomain.reg_current
|
||||
#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw
|
||||
#define ah_modes ah_capabilities.cap_mode
|
||||
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
|
||||
|
||||
|
@ -1065,6 +1065,7 @@ struct ath5k_hw {
|
|||
u32 ah_gpio[AR5K_MAX_GPIO];
|
||||
int ah_gpio_npins;
|
||||
|
||||
struct ath_regulatory ah_regulatory;
|
||||
struct ath5k_capabilities ah_capabilities;
|
||||
|
||||
struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES];
|
|
@ -61,9 +61,13 @@
|
|||
|
||||
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
|
||||
static int modparam_nohwcrypt;
|
||||
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
|
||||
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
|
||||
|
||||
static int modparam_all_channels;
|
||||
module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(all_channels, "Expose all channels the device can use.");
|
||||
|
||||
|
||||
/******************\
|
||||
* Internal defines *
|
||||
|
@ -705,6 +709,15 @@ ath5k_pci_resume(struct pci_dev *pdev)
|
|||
* Driver Initialization *
|
||||
\***********************/
|
||||
|
||||
static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
struct ath_regulatory *reg = &sc->ah->ah_regulatory;
|
||||
|
||||
return ath_reg_notifier_apply(wiphy, request, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
||||
{
|
||||
|
@ -793,12 +806,23 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|||
memset(sc->bssidmask, 0xff, ETH_ALEN);
|
||||
ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
|
||||
|
||||
ah->ah_regulatory.current_rd =
|
||||
ah->ah_capabilities.cap_eeprom.ee_regdomain;
|
||||
ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "can't initialize regulatory system\n");
|
||||
goto err_queues;
|
||||
}
|
||||
|
||||
ret = ieee80211_register_hw(hw);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "can't register ieee80211 hw\n");
|
||||
goto err_queues;
|
||||
}
|
||||
|
||||
if (!ath_is_world_regd(&sc->ah->ah_regulatory))
|
||||
regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2);
|
||||
|
||||
ath5k_init_leds(sc);
|
||||
|
||||
return 0;
|
||||
|
@ -862,6 +886,20 @@ ath5k_ieee2mhz(short chan)
|
|||
return 2212 + chan * 20;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true for the channel numbers used without all_channels modparam.
|
||||
*/
|
||||
static bool ath5k_is_standard_channel(short chan)
|
||||
{
|
||||
return ((chan <= 14) ||
|
||||
/* UNII 1,2 */
|
||||
((chan & 3) == 0 && chan >= 36 && chan <= 64) ||
|
||||
/* midband */
|
||||
((chan & 3) == 0 && chan >= 100 && chan <= 140) ||
|
||||
/* UNII-3 */
|
||||
((chan & 3) == 1 && chan >= 149 && chan <= 165));
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ath5k_copy_channels(struct ath5k_hw *ah,
|
||||
struct ieee80211_channel *channels,
|
||||
|
@ -899,6 +937,9 @@ ath5k_copy_channels(struct ath5k_hw *ah,
|
|||
if (!ath5k_channel_ok(ah, freq, chfreq))
|
||||
continue;
|
||||
|
||||
if (!modparam_all_channels && !ath5k_is_standard_channel(ch))
|
||||
continue;
|
||||
|
||||
/* Write channel info and increment counter */
|
||||
channels[count].center_freq = freq;
|
||||
channels[count].band = (chfreq == CHANNEL_2GHZ) ?
|
||||
|
@ -1577,9 +1618,8 @@ ath5k_rx_start(struct ath5k_softc *sc)
|
|||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
|
||||
sc->cachelsz, sc->rxbufsize);
|
||||
|
||||
sc->rxlink = NULL;
|
||||
|
||||
spin_lock_bh(&sc->rxbuflock);
|
||||
sc->rxlink = NULL;
|
||||
list_for_each_entry(bf, &sc->rxbuf, list) {
|
||||
ret = ath5k_rxbuf_setup(sc, bf);
|
||||
if (ret != 0) {
|
||||
|
@ -1588,9 +1628,9 @@ ath5k_rx_start(struct ath5k_softc *sc)
|
|||
}
|
||||
}
|
||||
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
|
||||
ath5k_hw_set_rxdp(ah, bf->daddr);
|
||||
spin_unlock_bh(&sc->rxbuflock);
|
||||
|
||||
ath5k_hw_set_rxdp(ah, bf->daddr);
|
||||
ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */
|
||||
ath5k_mode_setup(sc); /* set filters, etc. */
|
||||
ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */
|
||||
|
@ -1739,7 +1779,7 @@ ath5k_tasklet_rx(unsigned long data)
|
|||
struct sk_buff *skb, *next_skb;
|
||||
dma_addr_t next_skb_addr;
|
||||
struct ath5k_softc *sc = (void *)data;
|
||||
struct ath5k_buf *bf, *bf_last;
|
||||
struct ath5k_buf *bf;
|
||||
struct ath5k_desc *ds;
|
||||
int ret;
|
||||
int hdrlen;
|
||||
|
@ -1750,7 +1790,6 @@ ath5k_tasklet_rx(unsigned long data)
|
|||
ATH5K_WARN(sc, "empty rx buf pool\n");
|
||||
goto unlock;
|
||||
}
|
||||
bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
|
||||
do {
|
||||
rxs.flag = 0;
|
||||
|
||||
|
@ -1759,24 +1798,9 @@ ath5k_tasklet_rx(unsigned long data)
|
|||
skb = bf->skb;
|
||||
ds = bf->desc;
|
||||
|
||||
/*
|
||||
* last buffer must not be freed to ensure proper hardware
|
||||
* function. When the hardware finishes also a packet next to
|
||||
* it, we are sure, it doesn't use it anymore and we can go on.
|
||||
*/
|
||||
if (bf_last == bf)
|
||||
bf->flags |= 1;
|
||||
if (bf->flags) {
|
||||
struct ath5k_buf *bf_next = list_entry(bf->list.next,
|
||||
struct ath5k_buf, list);
|
||||
ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
|
||||
&rs);
|
||||
if (ret)
|
||||
break;
|
||||
bf->flags &= ~1;
|
||||
/* skip the overwritten one (even status is martian) */
|
||||
goto next;
|
||||
}
|
||||
/* bail if HW is still using self-linked descriptor */
|
||||
if (ath5k_hw_get_rxdp(sc->ah) == bf->daddr)
|
||||
break;
|
||||
|
||||
ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
|
||||
if (unlikely(ret == -EINPROGRESS))
|
||||
|
@ -2455,7 +2479,7 @@ ath5k_intr(int irq, void *dev_id)
|
|||
tasklet_schedule(&sc->restq);
|
||||
} else {
|
||||
if (status & AR5K_INT_SWBA) {
|
||||
tasklet_schedule(&sc->beacontq);
|
||||
tasklet_hi_schedule(&sc->beacontq);
|
||||
}
|
||||
if (status & AR5K_INT_RXEOL) {
|
||||
/*
|
|
@ -56,7 +56,6 @@
|
|||
|
||||
struct ath5k_buf {
|
||||
struct list_head list;
|
||||
unsigned int flags; /* rx descriptor flags */
|
||||
struct ath5k_desc *desc; /* virtual addr of desc */
|
||||
dma_addr_t daddr; /* physical addr of desc */
|
||||
struct sk_buff *skb; /* skbuff for buf */
|
|
@ -80,8 +80,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
|
|||
* ath5k_hw_get_rxdp - Get RX Descriptor's address
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*
|
||||
* XXX: Is RXDP read and clear ?
|
||||
*/
|
||||
u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
|
||||
{
|
|
@ -537,8 +537,6 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
|
|||
{ AR5K_DCU_TX_FILTER_1(15), 0x00000000 },
|
||||
{ AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
|
||||
{ AR5K_DCU_TX_FILTER_SET, 0x00000000 },
|
||||
{ AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
|
||||
{ AR5K_DCU_TX_FILTER_SET, 0x00000000 },
|
||||
{ AR5K_STA_ID1, 0x00000000 },
|
||||
{ AR5K_BSS_ID0, 0x00000000 },
|
||||
{ AR5K_BSS_ID1, 0x00000000 },
|
||||
|
@ -669,7 +667,7 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
|
|||
/*{ AR5K_PHY(650), 0x000001b5 },*/
|
||||
{ AR5K_PHY(651), 0x00000000 },
|
||||
{ AR5K_PHY_TXPOWER_RATE3, 0x20202020 },
|
||||
{ AR5K_PHY_TXPOWER_RATE2, 0x20202020 },
|
||||
{ AR5K_PHY_TXPOWER_RATE4, 0x20202020 },
|
||||
/*{ AR5K_PHY(655), 0x13c889af },*/
|
||||
{ AR5K_PHY(656), 0x38490a20 },
|
||||
{ AR5K_PHY(657), 0x00007bb6 },
|
||||
|
@ -718,7 +716,7 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
|
|||
{ AR5K_PHY_SETTLING,
|
||||
{ 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
|
||||
{ AR5K_PHY_AGCCTL,
|
||||
{ 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
|
||||
{ 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
|
||||
{ AR5K_PHY_NF,
|
||||
{ 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
|
||||
{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
|
||||
|
@ -799,7 +797,7 @@ static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
|
|||
{ AR5K_PHY_DESIRED_SIZE,
|
||||
{ 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
|
||||
{ AR5K_PHY_SIG,
|
||||
{ 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
|
||||
{ 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
|
||||
{ AR5K_PHY_AGCCOARSE,
|
||||
{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
|
||||
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
|
|
@ -67,6 +67,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
|
|||
{ ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) },
|
||||
/* Acer Extensa 5620z (nekoreeve@gmail.com) */
|
||||
{ ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) },
|
||||
/* Fukato Datacask Jupiter 1014a (mrb74@gmx.at) */
|
||||
{ ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -78,7 +80,7 @@ void ath5k_led_enable(struct ath5k_softc *sc)
|
|||
}
|
||||
}
|
||||
|
||||
void ath5k_led_on(struct ath5k_softc *sc)
|
||||
static void ath5k_led_on(struct ath5k_softc *sc)
|
||||
{
|
||||
if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
|
||||
return;
|
|
@ -1487,28 +1487,35 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
|
|||
{
|
||||
s8 tmp;
|
||||
s16 min_pwrL, min_pwrR;
|
||||
s16 pwr_i = pwrL[0];
|
||||
s16 pwr_i;
|
||||
|
||||
do {
|
||||
pwr_i--;
|
||||
tmp = (s8) ath5k_get_interpolated_value(pwr_i,
|
||||
pwrL[0], pwrL[1],
|
||||
stepL[0], stepL[1]);
|
||||
if (pwrL[0] == pwrL[1])
|
||||
min_pwrL = pwrL[0];
|
||||
else {
|
||||
pwr_i = pwrL[0];
|
||||
do {
|
||||
pwr_i--;
|
||||
tmp = (s8) ath5k_get_interpolated_value(pwr_i,
|
||||
pwrL[0], pwrL[1],
|
||||
stepL[0], stepL[1]);
|
||||
} while (tmp > 1);
|
||||
|
||||
} while (tmp > 1);
|
||||
min_pwrL = pwr_i;
|
||||
}
|
||||
|
||||
min_pwrL = pwr_i;
|
||||
if (pwrR[0] == pwrR[1])
|
||||
min_pwrR = pwrR[0];
|
||||
else {
|
||||
pwr_i = pwrR[0];
|
||||
do {
|
||||
pwr_i--;
|
||||
tmp = (s8) ath5k_get_interpolated_value(pwr_i,
|
||||
pwrR[0], pwrR[1],
|
||||
stepR[0], stepR[1]);
|
||||
} while (tmp > 1);
|
||||
|
||||
pwr_i = pwrR[0];
|
||||
do {
|
||||
pwr_i--;
|
||||
tmp = (s8) ath5k_get_interpolated_value(pwr_i,
|
||||
pwrR[0], pwrR[1],
|
||||
stepR[0], stepR[1]);
|
||||
|
||||
} while (tmp > 1);
|
||||
|
||||
min_pwrR = pwr_i;
|
||||
min_pwrR = pwr_i;
|
||||
}
|
||||
|
||||
/* Keep the right boundary so that it works for both curves */
|
||||
return max(min_pwrL, min_pwrR);
|
|
@ -358,7 +358,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
mode |= AR5K_PHY_MODE_FREQ_5GHZ;
|
||||
|
||||
if (ah->ah_radio == AR5K_RF5413)
|
||||
clock |= AR5K_PHY_PLL_40MHZ_5413;
|
||||
clock = AR5K_PHY_PLL_40MHZ_5413;
|
||||
else
|
||||
clock |= AR5K_PHY_PLL_40MHZ;
|
||||
|
|
@ -2,6 +2,7 @@ config ATH9K
|
|||
tristate "Atheros 802.11n wireless cards support"
|
||||
depends on PCI && MAC80211 && WLAN_80211
|
||||
depends on RFKILL || RFKILL=n
|
||||
select ATH_COMMON
|
||||
select MAC80211_LEDS
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
|
@ -4,7 +4,6 @@ ath9k-y += hw.o \
|
|||
calib.o \
|
||||
ani.o \
|
||||
phy.o \
|
||||
regd.o \
|
||||
beacon.o \
|
||||
main.o \
|
||||
recv.o \
|
|
@ -569,8 +569,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
|||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"phyCnt1 0x%x, resetting "
|
||||
"counter value to 0x%x\n",
|
||||
phyCnt1,
|
||||
aniState->ofdmPhyErrBase);
|
||||
phyCnt1, aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1,
|
||||
aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
|
||||
|
@ -580,8 +579,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
|||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"phyCnt2 0x%x, resetting "
|
||||
"counter value to 0x%x\n",
|
||||
phyCnt2,
|
||||
aniState->cckPhyErrBase);
|
||||
phyCnt2, aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2,
|
||||
aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
|
||||
|
@ -667,7 +665,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
|
|||
u32 cc = REG_READ(ah, AR_CCCNT);
|
||||
|
||||
if (cycles == 0 || cycles > cc) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"cycle counter wrap. ExtBusy = 0\n");
|
||||
good = 0;
|
||||
} else {
|
|
@ -66,7 +66,6 @@ struct ath_config {
|
|||
u32 ath_aggr_prot;
|
||||
u16 txpowlimit;
|
||||
u8 cabqReadytime;
|
||||
u8 swBeaconProcess;
|
||||
};
|
||||
|
||||
/*************************/
|
||||
|
@ -74,13 +73,17 @@ struct ath_config {
|
|||
/*************************/
|
||||
|
||||
#define ATH_TXBUF_RESET(_bf) do { \
|
||||
(_bf)->bf_status = 0; \
|
||||
(_bf)->bf_stale = false; \
|
||||
(_bf)->bf_lastbf = NULL; \
|
||||
(_bf)->bf_next = NULL; \
|
||||
memset(&((_bf)->bf_state), 0, \
|
||||
sizeof(struct ath_buf_state)); \
|
||||
} while (0)
|
||||
|
||||
#define ATH_RXBUF_RESET(_bf) do { \
|
||||
(_bf)->bf_stale = false; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* enum buffer_type - Buffer type flags
|
||||
*
|
||||
|
@ -106,7 +109,7 @@ struct ath_buf_state {
|
|||
int bfs_seqno;
|
||||
int bfs_tidno;
|
||||
int bfs_retries;
|
||||
u32 bf_type;
|
||||
u8 bf_type;
|
||||
u32 bfs_keyix;
|
||||
enum ath9k_key_type bfs_keytype;
|
||||
};
|
||||
|
@ -130,26 +133,21 @@ struct ath_buf {
|
|||
struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
|
||||
an aggregate) */
|
||||
struct ath_buf *bf_next; /* next subframe in the aggregate */
|
||||
void *bf_mpdu; /* enclosing frame structure */
|
||||
struct sk_buff *bf_mpdu; /* enclosing frame structure */
|
||||
struct ath_desc *bf_desc; /* virtual addr of desc */
|
||||
dma_addr_t bf_daddr; /* physical addr of desc */
|
||||
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
|
||||
u32 bf_status;
|
||||
bool bf_stale;
|
||||
u16 bf_flags;
|
||||
struct ath_buf_state bf_state;
|
||||
dma_addr_t bf_dmacontext;
|
||||
};
|
||||
|
||||
#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0)
|
||||
#define ATH_BUFSTATUS_STALE 0x00000002
|
||||
|
||||
struct ath_descdma {
|
||||
const char *dd_name;
|
||||
struct ath_desc *dd_desc;
|
||||
dma_addr_t dd_desc_paddr;
|
||||
u32 dd_desc_len;
|
||||
struct ath_buf *dd_bufptr;
|
||||
dma_addr_t dd_dmacontext;
|
||||
};
|
||||
|
||||
int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
||||
|
@ -295,26 +293,6 @@ struct ath_tx_control {
|
|||
#define ATH_TX_XRETRY 0x02
|
||||
#define ATH_TX_BAR 0x04
|
||||
|
||||
/* All RSSI values are noise floor adjusted */
|
||||
struct ath_tx_stat {
|
||||
int rssi;
|
||||
int rssictl[ATH_MAX_ANTENNA];
|
||||
int rssiextn[ATH_MAX_ANTENNA];
|
||||
int rateieee;
|
||||
int rateKbps;
|
||||
int ratecode;
|
||||
int flags;
|
||||
u32 airtime; /* time on air per final tx rate */
|
||||
};
|
||||
|
||||
struct aggr_rifs_param {
|
||||
int param_max_frames;
|
||||
int param_max_len;
|
||||
int param_rl;
|
||||
int param_al;
|
||||
struct ath_rc_series *param_rcs;
|
||||
};
|
||||
|
||||
struct ath_node {
|
||||
struct ath_softc *an_sc;
|
||||
struct ath_atx_tid tid[WME_NUM_TID];
|
||||
|
@ -362,7 +340,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
|
|||
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
|
||||
int ath_tx_init(struct ath_softc *sc, int nbufs);
|
||||
int ath_tx_cleanup(struct ath_softc *sc);
|
||||
void ath_tx_cleanup(struct ath_softc *sc);
|
||||
struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
|
||||
int ath_txq_update(struct ath_softc *sc, int qnum,
|
||||
struct ath9k_tx_queue_info *q);
|
||||
|
@ -525,19 +503,18 @@ struct ath_rfkill {
|
|||
#define SC_OP_BEACONS BIT(1)
|
||||
#define SC_OP_RXAGGR BIT(2)
|
||||
#define SC_OP_TXAGGR BIT(3)
|
||||
#define SC_OP_CHAINMASK_UPDATE BIT(4)
|
||||
#define SC_OP_FULL_RESET BIT(5)
|
||||
#define SC_OP_PREAMBLE_SHORT BIT(6)
|
||||
#define SC_OP_PROTECT_ENABLE BIT(7)
|
||||
#define SC_OP_RXFLUSH BIT(8)
|
||||
#define SC_OP_LED_ASSOCIATED BIT(9)
|
||||
#define SC_OP_RFKILL_REGISTERED BIT(10)
|
||||
#define SC_OP_RFKILL_SW_BLOCKED BIT(11)
|
||||
#define SC_OP_RFKILL_HW_BLOCKED BIT(12)
|
||||
#define SC_OP_WAIT_FOR_BEACON BIT(13)
|
||||
#define SC_OP_LED_ON BIT(14)
|
||||
#define SC_OP_SCANNING BIT(15)
|
||||
#define SC_OP_TSF_RESET BIT(16)
|
||||
#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_RFKILL_REGISTERED BIT(9)
|
||||
#define SC_OP_RFKILL_SW_BLOCKED BIT(10)
|
||||
#define SC_OP_RFKILL_HW_BLOCKED BIT(11)
|
||||
#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)
|
||||
|
||||
struct ath_bus_ops {
|
||||
void (*read_cachesize)(struct ath_softc *sc, int *csz);
|
|
@ -43,7 +43,7 @@ static int ath_beaconq_config(struct ath_softc *sc)
|
|||
|
||||
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"unable to update h/w beacon queue parameters\n");
|
||||
"Unable to update h/w beacon queue parameters\n");
|
||||
return 0;
|
||||
} else {
|
||||
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
|
||||
|
@ -59,7 +59,7 @@ static int ath_beaconq_config(struct ath_softc *sc)
|
|||
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
|
||||
struct ath_buf *bf)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_desc *ds;
|
||||
struct ath9k_11n_rate_series series[4];
|
||||
|
@ -132,16 +132,13 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
|
|||
avp = (void *)vif->drv_priv;
|
||||
cabq = sc->beacon.cabq;
|
||||
|
||||
if (avp->av_bcbuf == NULL) {
|
||||
DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
|
||||
avp, avp->av_bcbuf);
|
||||
if (avp->av_bcbuf == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Release the old beacon first */
|
||||
|
||||
bf = avp->av_bcbuf;
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
skb = bf->bf_mpdu;
|
||||
if (skb) {
|
||||
dma_unmap_single(sc->dev, bf->bf_dmacontext,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
|
@ -229,7 +226,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
|
|||
return;
|
||||
|
||||
bf = avp->av_bcbuf;
|
||||
skb = (struct sk_buff *) bf->bf_mpdu;
|
||||
skb = bf->bf_mpdu;
|
||||
|
||||
ath_beacon_setup(sc, avp, bf);
|
||||
|
||||
|
@ -302,7 +299,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
|
|||
/* release the previous beacon frame, if it already exists. */
|
||||
bf = avp->av_bcbuf;
|
||||
if (bf->bf_mpdu != NULL) {
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
skb = bf->bf_mpdu;
|
||||
dma_unmap_single(sc->dev, bf->bf_dmacontext,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
|
@ -374,7 +371,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
|
|||
|
||||
bf = avp->av_bcbuf;
|
||||
if (bf->bf_mpdu != NULL) {
|
||||
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
dma_unmap_single(sc->dev, bf->bf_dmacontext,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
|
@ -186,7 +186,7 @@ static bool getNoiseFloorThresh(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
|
||||
struct hal_cal_list *currCal)
|
||||
struct ath9k_cal_list *currCal)
|
||||
{
|
||||
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
|
||||
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
|
||||
|
@ -220,7 +220,7 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
||||
struct hal_cal_list *currCal)
|
||||
struct ath9k_cal_list *currCal)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -238,13 +238,12 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
|||
ah->cal_samples = 0;
|
||||
}
|
||||
|
||||
static void ath9k_hw_per_calibration(struct ath_hw *ah,
|
||||
static bool ath9k_hw_per_calibration(struct ath_hw *ah,
|
||||
struct ath9k_channel *ichan,
|
||||
u8 rxchainmask,
|
||||
struct hal_cal_list *currCal,
|
||||
bool *isCalDone)
|
||||
struct ath9k_cal_list *currCal)
|
||||
{
|
||||
*isCalDone = false;
|
||||
bool iscaldone = false;
|
||||
|
||||
if (currCal->calState == CAL_RUNNING) {
|
||||
if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
|
||||
|
@ -263,7 +262,7 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah,
|
|||
currCal->calData->calPostProc(ah, numChains);
|
||||
ichan->CalValid |= currCal->calData->calType;
|
||||
currCal->calState = CAL_DONE;
|
||||
*isCalDone = true;
|
||||
iscaldone = true;
|
||||
} else {
|
||||
ath9k_hw_setup_calibration(ah, currCal);
|
||||
}
|
||||
|
@ -271,11 +270,13 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah,
|
|||
} else if (!(ichan->CalValid & currCal->calData->calType)) {
|
||||
ath9k_hw_reset_calibration(ah, currCal);
|
||||
}
|
||||
|
||||
return iscaldone;
|
||||
}
|
||||
|
||||
/* Assumes you are talking about the currently configured channel */
|
||||
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
|
||||
enum hal_cal_types calType)
|
||||
enum ath9k_cal_types calType)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
|
||||
|
||||
|
@ -284,8 +285,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
|
|||
return true;
|
||||
case ADC_GAIN_CAL:
|
||||
case ADC_DC_CAL:
|
||||
if (conf->channel->band == IEEE80211_BAND_5GHZ &&
|
||||
conf_is_ht20(conf))
|
||||
if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
|
||||
conf_is_ht20(conf)))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
@ -498,7 +499,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
|
|||
{
|
||||
u32 iOddMeasOffset, iEvenMeasOffset, val, i;
|
||||
int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
|
||||
const struct hal_percal_data *calData =
|
||||
const struct ath9k_percal_data *calData =
|
||||
ah->cal_list_curr->calData;
|
||||
u32 numSamples =
|
||||
(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
|
||||
|
@ -555,7 +556,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
|
|||
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
|
||||
struct hal_cal_list *currCal = ah->cal_list_curr;
|
||||
struct ath9k_cal_list *currCal = ah->cal_list_curr;
|
||||
|
||||
if (!ah->curchan)
|
||||
return true;
|
||||
|
@ -841,23 +842,21 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
|
|||
}
|
||||
|
||||
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
u8 rxchainmask, bool longcal,
|
||||
bool *isCalDone)
|
||||
u8 rxchainmask, bool longcal)
|
||||
{
|
||||
struct hal_cal_list *currCal = ah->cal_list_curr;
|
||||
|
||||
*isCalDone = true;
|
||||
bool iscaldone = true;
|
||||
struct ath9k_cal_list *currCal = ah->cal_list_curr;
|
||||
|
||||
if (currCal &&
|
||||
(currCal->calState == CAL_RUNNING ||
|
||||
currCal->calState == CAL_WAITING)) {
|
||||
ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
|
||||
isCalDone);
|
||||
if (*isCalDone) {
|
||||
iscaldone = ath9k_hw_per_calibration(ah, chan,
|
||||
rxchainmask, currCal);
|
||||
if (iscaldone) {
|
||||
ah->cal_list_curr = currCal = currCal->calNext;
|
||||
|
||||
if (currCal->calState == CAL_WAITING) {
|
||||
*isCalDone = false;
|
||||
iscaldone = false;
|
||||
ath9k_hw_reset_calibration(ah, currCal);
|
||||
}
|
||||
}
|
||||
|
@ -872,18 +871,15 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
ath9k_hw_getnf(ah, chan);
|
||||
ath9k_hw_loadnf(ah, ah->curchan);
|
||||
ath9k_hw_start_nfcal(ah);
|
||||
|
||||
if (chan->channelFlags & CHANNEL_CW_INT)
|
||||
chan->channelFlags &= ~CHANNEL_CW_INT;
|
||||
}
|
||||
|
||||
return true;
|
||||
return iscaldone;
|
||||
}
|
||||
|
||||
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
|
||||
if (chan->channelFlags & CHANNEL_HT20) {
|
||||
if (IS_CHAN_HT20(chan)) {
|
||||
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
|
||||
REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
|
||||
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||
|
@ -919,83 +915,66 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_init_cal(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
|
||||
if (!ar9285_clc(ah, chan))
|
||||
return false;
|
||||
} else if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
|
||||
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
|
||||
REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
|
||||
} else {
|
||||
if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
|
||||
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
|
||||
}
|
||||
|
||||
/* Kick off the cal */
|
||||
/* Calibrate the AGC */
|
||||
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) |
|
||||
AR_PHY_AGC_CONTROL_CAL);
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) |
|
||||
AR_PHY_AGC_CONTROL_CAL);
|
||||
|
||||
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
|
||||
AR_PHY_AGC_CONTROL_CAL, 0,
|
||||
AH_WAIT_TIMEOUT)) {
|
||||
/* Poll for offset calibration complete */
|
||||
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
|
||||
0, AH_WAIT_TIMEOUT)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"offset calibration failed to complete in 1ms; "
|
||||
"noisy environment?\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
|
||||
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
|
||||
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
|
||||
}
|
||||
|
||||
/* Calibrate the AGC */
|
||||
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) |
|
||||
AR_PHY_AGC_CONTROL_CAL);
|
||||
|
||||
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
|
||||
0, AH_WAIT_TIMEOUT)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"offset calibration failed to complete in 1ms; "
|
||||
"noisy environment?\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
|
||||
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
|
||||
if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
|
||||
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do PA Calibration */
|
||||
if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
|
||||
ath9k_hw_9285_pa_cal(ah);
|
||||
|
||||
/* Do NF Calibration */
|
||||
/* Do NF Calibration after DC offset and other calibrations */
|
||||
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) |
|
||||
AR_PHY_AGC_CONTROL_NF);
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
|
||||
|
||||
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
|
||||
|
||||
/* Enable IQ, ADC Gain and ADC DC offset CALs */
|
||||
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
|
||||
if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
|
||||
INIT_CAL(&ah->adcgain_caldata);
|
||||
INSERT_CAL(ah, &ah->adcgain_caldata);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"enabling ADC Gain Calibration.\n");
|
||||
"enabling ADC Gain Calibration.\n");
|
||||
}
|
||||
if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
|
||||
INIT_CAL(&ah->adcdc_caldata);
|
||||
INSERT_CAL(ah, &ah->adcdc_caldata);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"enabling ADC DC Calibration.\n");
|
||||
"enabling ADC DC Calibration.\n");
|
||||
}
|
||||
if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
|
||||
INIT_CAL(&ah->iq_caldata);
|
||||
INSERT_CAL(ah, &ah->iq_caldata);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"enabling IQ Calibration.\n");
|
||||
"enabling IQ Calibration.\n");
|
||||
}
|
||||
|
||||
ah->cal_list_curr = ah->cal_list;
|
||||
|
@ -1009,49 +988,49 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
|
|||
return true;
|
||||
}
|
||||
|
||||
const struct hal_percal_data iq_cal_multi_sample = {
|
||||
const struct ath9k_percal_data iq_cal_multi_sample = {
|
||||
IQ_MISMATCH_CAL,
|
||||
MAX_CAL_SAMPLES,
|
||||
PER_MIN_LOG_COUNT,
|
||||
ath9k_hw_iqcal_collect,
|
||||
ath9k_hw_iqcalibrate
|
||||
};
|
||||
const struct hal_percal_data iq_cal_single_sample = {
|
||||
const struct ath9k_percal_data iq_cal_single_sample = {
|
||||
IQ_MISMATCH_CAL,
|
||||
MIN_CAL_SAMPLES,
|
||||
PER_MAX_LOG_COUNT,
|
||||
ath9k_hw_iqcal_collect,
|
||||
ath9k_hw_iqcalibrate
|
||||
};
|
||||
const struct hal_percal_data adc_gain_cal_multi_sample = {
|
||||
const struct ath9k_percal_data adc_gain_cal_multi_sample = {
|
||||
ADC_GAIN_CAL,
|
||||
MAX_CAL_SAMPLES,
|
||||
PER_MIN_LOG_COUNT,
|
||||
ath9k_hw_adc_gaincal_collect,
|
||||
ath9k_hw_adc_gaincal_calibrate
|
||||
};
|
||||
const struct hal_percal_data adc_gain_cal_single_sample = {
|
||||
const struct ath9k_percal_data adc_gain_cal_single_sample = {
|
||||
ADC_GAIN_CAL,
|
||||
MIN_CAL_SAMPLES,
|
||||
PER_MAX_LOG_COUNT,
|
||||
ath9k_hw_adc_gaincal_collect,
|
||||
ath9k_hw_adc_gaincal_calibrate
|
||||
};
|
||||
const struct hal_percal_data adc_dc_cal_multi_sample = {
|
||||
const struct ath9k_percal_data adc_dc_cal_multi_sample = {
|
||||
ADC_DC_CAL,
|
||||
MAX_CAL_SAMPLES,
|
||||
PER_MIN_LOG_COUNT,
|
||||
ath9k_hw_adc_dccal_collect,
|
||||
ath9k_hw_adc_dccal_calibrate
|
||||
};
|
||||
const struct hal_percal_data adc_dc_cal_single_sample = {
|
||||
const struct ath9k_percal_data adc_dc_cal_single_sample = {
|
||||
ADC_DC_CAL,
|
||||
MIN_CAL_SAMPLES,
|
||||
PER_MAX_LOG_COUNT,
|
||||
ath9k_hw_adc_dccal_collect,
|
||||
ath9k_hw_adc_dccal_calibrate
|
||||
};
|
||||
const struct hal_percal_data adc_init_dc_cal = {
|
||||
const struct ath9k_percal_data adc_init_dc_cal = {
|
||||
ADC_DC_INIT_CAL,
|
||||
MIN_CAL_SAMPLES,
|
||||
INIT_LOG_COUNT,
|
|
@ -17,13 +17,13 @@
|
|||
#ifndef CALIB_H
|
||||
#define CALIB_H
|
||||
|
||||
extern const struct hal_percal_data iq_cal_multi_sample;
|
||||
extern const struct hal_percal_data iq_cal_single_sample;
|
||||
extern const struct hal_percal_data adc_gain_cal_multi_sample;
|
||||
extern const struct hal_percal_data adc_gain_cal_single_sample;
|
||||
extern const struct hal_percal_data adc_dc_cal_multi_sample;
|
||||
extern const struct hal_percal_data adc_dc_cal_single_sample;
|
||||
extern const struct hal_percal_data adc_init_dc_cal;
|
||||
extern const struct ath9k_percal_data iq_cal_multi_sample;
|
||||
extern const struct ath9k_percal_data iq_cal_single_sample;
|
||||
extern const struct ath9k_percal_data adc_gain_cal_multi_sample;
|
||||
extern const struct ath9k_percal_data adc_gain_cal_single_sample;
|
||||
extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
|
||||
extern const struct ath9k_percal_data adc_dc_cal_single_sample;
|
||||
extern const struct ath9k_percal_data adc_init_dc_cal;
|
||||
|
||||
#define AR_PHY_CCA_MAX_GOOD_VALUE -85
|
||||
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
|
||||
|
@ -67,14 +67,14 @@ struct ar5416IniArray {
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
enum hal_cal_types {
|
||||
enum ath9k_cal_types {
|
||||
ADC_DC_INIT_CAL = 0x1,
|
||||
ADC_GAIN_CAL = 0x2,
|
||||
ADC_DC_CAL = 0x4,
|
||||
IQ_MISMATCH_CAL = 0x8
|
||||
};
|
||||
|
||||
enum hal_cal_state {
|
||||
enum ath9k_cal_state {
|
||||
CAL_INACTIVE,
|
||||
CAL_WAITING,
|
||||
CAL_RUNNING,
|
||||
|
@ -87,18 +87,18 @@ enum hal_cal_state {
|
|||
#define PER_MIN_LOG_COUNT 2
|
||||
#define PER_MAX_LOG_COUNT 10
|
||||
|
||||
struct hal_percal_data {
|
||||
enum hal_cal_types calType;
|
||||
struct ath9k_percal_data {
|
||||
enum ath9k_cal_types calType;
|
||||
u32 calNumSamples;
|
||||
u32 calCountMax;
|
||||
void (*calCollect) (struct ath_hw *);
|
||||
void (*calPostProc) (struct ath_hw *, u8);
|
||||
};
|
||||
|
||||
struct hal_cal_list {
|
||||
const struct hal_percal_data *calData;
|
||||
enum hal_cal_state calState;
|
||||
struct hal_cal_list *calNext;
|
||||
struct ath9k_cal_list {
|
||||
const struct ath9k_percal_data *calData;
|
||||
enum ath9k_cal_state calState;
|
||||
struct ath9k_cal_list *calNext;
|
||||
};
|
||||
|
||||
struct ath9k_nfcal_hist {
|
||||
|
@ -116,8 +116,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
|
|||
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
u8 rxchainmask, bool longcal,
|
||||
bool *isCalDone);
|
||||
u8 rxchainmask, bool longcal);
|
||||
bool ath9k_hw_init_cal(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
|
|
@ -498,6 +498,9 @@ int ath9k_init_debug(struct ath_softc *sc)
|
|||
{
|
||||
sc->debug.debug_mask = ath9k_debug;
|
||||
|
||||
if (!ath9k_debugfs_root)
|
||||
return -ENOENT;
|
||||
|
||||
sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
|
||||
ath9k_debugfs_root);
|
||||
if (!sc->debug.debugfs_phy)
|
|
@ -19,20 +19,16 @@
|
|||
|
||||
enum ATH_DEBUG {
|
||||
ATH_DBG_RESET = 0x00000001,
|
||||
ATH_DBG_REG_IO = 0x00000002,
|
||||
ATH_DBG_QUEUE = 0x00000004,
|
||||
ATH_DBG_EEPROM = 0x00000008,
|
||||
ATH_DBG_CALIBRATE = 0x00000010,
|
||||
ATH_DBG_CHANNEL = 0x00000020,
|
||||
ATH_DBG_INTERRUPT = 0x00000040,
|
||||
ATH_DBG_REGULATORY = 0x00000080,
|
||||
ATH_DBG_ANI = 0x00000100,
|
||||
ATH_DBG_POWER_MGMT = 0x00000200,
|
||||
ATH_DBG_XMIT = 0x00000400,
|
||||
ATH_DBG_BEACON = 0x00001000,
|
||||
ATH_DBG_CONFIG = 0x00002000,
|
||||
ATH_DBG_KEYCACHE = 0x00004000,
|
||||
ATH_DBG_FATAL = 0x00008000,
|
||||
ATH_DBG_QUEUE = 0x00000002,
|
||||
ATH_DBG_EEPROM = 0x00000004,
|
||||
ATH_DBG_CALIBRATE = 0x00000008,
|
||||
ATH_DBG_INTERRUPT = 0x00000010,
|
||||
ATH_DBG_REGULATORY = 0x00000020,
|
||||
ATH_DBG_ANI = 0x00000040,
|
||||
ATH_DBG_XMIT = 0x00000080,
|
||||
ATH_DBG_BEACON = 0x00000100,
|
||||
ATH_DBG_CONFIG = 0x00000200,
|
||||
ATH_DBG_FATAL = 0x00000400,
|
||||
ATH_DBG_ANY = 0xffffffff
|
||||
};
|
||||
|
|
@ -783,11 +783,11 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
|
|||
((pdadcValues[4 * j + 3] & 0xFF) << 24);
|
||||
REG_WRITE(ah, regOffset, reg32);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"PDADC (%d,%4x): %4.4x %8.8x\n",
|
||||
i, regChainOffset, regOffset,
|
||||
reg32);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"PDADC: Chain %d | "
|
||||
"PDADC %3d Value %3d | "
|
||||
"PDADC %3d Value %3d | "
|
||||
|
@ -910,7 +910,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
|
|||
ah->eep_ops->get_eeprom_rev(ah) <= 2)
|
||||
twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
|
||||
"EXT_ADDITIVE %d\n",
|
||||
ctlMode, numCtlModes, isHt40CtlMode,
|
||||
|
@ -918,7 +918,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
|
|||
|
||||
for (i = 0; (i < AR5416_NUM_CTLS) &&
|
||||
pEepData->ctlIndex[i]; i++) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
|
||||
"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
|
||||
"chan %d\n",
|
||||
|
@ -941,7 +941,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
|
|||
IS_CHAN_2GHZ(chan),
|
||||
AR5416_EEP4K_NUM_BAND_EDGES);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
" MATCH-EE_IDX %d: ch %d is2 %d "
|
||||
"2xMinEdge %d chainmask %d chains %d\n",
|
||||
i, freq, IS_CHAN_2GHZ(chan),
|
||||
|
@ -961,7 +961,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
|
|||
|
||||
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
" SEL-Min ctlMode %d pCtlMode %d "
|
||||
"2xMaxEdge %d sP %d minCtlPwr %d\n",
|
||||
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
|
||||
|
@ -2234,11 +2234,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
|
|||
((pdadcValues[4 * j + 3] & 0xFF) << 24);
|
||||
REG_WRITE(ah, regOffset, reg32);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"PDADC (%d,%4x): %4.4x %8.8x\n",
|
||||
i, regChainOffset, regOffset,
|
||||
reg32);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"PDADC: Chain %d | PDADC %3d "
|
||||
"Value %3d | PDADC %3d Value %3d | "
|
||||
"PDADC %3d Value %3d | PDADC %3d "
|
||||
|
@ -2415,14 +2415,14 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
|
|||
ah->eep_ops->get_eeprom_rev(ah) <= 2)
|
||||
twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
|
||||
"EXT_ADDITIVE %d\n",
|
||||
ctlMode, numCtlModes, isHt40CtlMode,
|
||||
(pCtlMode[ctlMode] & EXT_ADDITIVE));
|
||||
|
||||
for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
|
||||
"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
|
||||
"chan %d\n",
|
||||
|
@ -2441,7 +2441,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
|
|||
rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
|
||||
IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
" MATCH-EE_IDX %d: ch %d is2 %d "
|
||||
"2xMinEdge %d chainmask %d chains %d\n",
|
||||
i, freq, IS_CHAN_2GHZ(chan),
|
||||
|
@ -2460,7 +2460,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
|
|||
|
||||
minCtlPower = min(twiceMaxEdgePower, scaledPower);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
" SEL-Min ctlMode %d pCtlMode %d "
|
||||
"2xMaxEdge %d sP %d minCtlPwr %d\n",
|
||||
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef EEPROM_H
|
||||
#define EEPROM_H
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#define AH_USE_EEPROM 0x1
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
|
@ -97,7 +97,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
|
|||
udelay(AH_TIME_QUANTUM);
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
"timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
|
||||
timeout, reg, REG_READ(ah, reg), mask, val);
|
||||
|
||||
|
@ -181,7 +181,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
|
|||
}
|
||||
break;
|
||||
default:
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Unknown phy %u (rate ix %u)\n",
|
||||
rates->info[rateix].phy, rateix);
|
||||
txTime = 0;
|
||||
|
@ -306,7 +306,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
|
|||
REG_WRITE(ah, addr, wrData);
|
||||
rdData = REG_READ(ah, addr);
|
||||
if (rdData != wrData) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"address test failed "
|
||||
"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
|
||||
addr, wrData, rdData);
|
||||
|
@ -318,7 +318,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
|
|||
REG_WRITE(ah, addr, wrData);
|
||||
rdData = REG_READ(ah, addr);
|
||||
if (wrData != rdData) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"address test failed "
|
||||
"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
|
||||
addr, wrData, rdData);
|
||||
|
@ -363,10 +363,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
|
|||
ah->config.ack_6mb = 0x0;
|
||||
ah->config.cwm_ignore_extcca = 0;
|
||||
ah->config.pcie_powersave_enable = 0;
|
||||
ah->config.pcie_l1skp_enable = 0;
|
||||
ah->config.pcie_clock_req = 0;
|
||||
ah->config.pcie_power_reset = 0x100;
|
||||
ah->config.pcie_restore = 0;
|
||||
ah->config.pcie_waen = 0;
|
||||
ah->config.analog_shiftreg = 1;
|
||||
ah->config.ht_enable = 1;
|
||||
|
@ -375,13 +372,6 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
|
|||
ah->config.cck_trig_high = 200;
|
||||
ah->config.cck_trig_low = 100;
|
||||
ah->config.enable_ani = 1;
|
||||
ah->config.noise_immunity_level = 4;
|
||||
ah->config.ofdm_weaksignal_det = 1;
|
||||
ah->config.cck_weaksignal_thr = 0;
|
||||
ah->config.spur_immunity_level = 2;
|
||||
ah->config.firstep_level = 0;
|
||||
ah->config.rssi_thr_high = 40;
|
||||
ah->config.rssi_thr_low = 7;
|
||||
ah->config.diversity_control = 0;
|
||||
ah->config.antenna_switch_swap = 0;
|
||||
|
||||
|
@ -390,7 +380,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
|
|||
ah->config.spurchans[i][1] = AR_NO_SPUR;
|
||||
}
|
||||
|
||||
ah->config.intr_mitigation = 1;
|
||||
ah->config.intr_mitigation = true;
|
||||
|
||||
/*
|
||||
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
|
||||
|
@ -463,8 +453,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah)
|
|||
|
||||
rfStatus = ath9k_hw_init_rf(ah, &ecode);
|
||||
if (!rfStatus) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
|
||||
"RF setup failed, status %u\n", ecode);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"RF setup failed, status: %u\n", ecode);
|
||||
return ecode;
|
||||
}
|
||||
|
||||
|
@ -488,10 +478,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah)
|
|||
case AR_RAD2122_SREV_MAJOR:
|
||||
break;
|
||||
default:
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
|
||||
"5G Radio Chip Rev 0x%02X is not "
|
||||
"supported by this driver\n",
|
||||
ah->hw_version.analog5GhzRev);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Radio Chip Rev 0x%02X not supported\n",
|
||||
val & AR_RADIO_SREV_MAJOR);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
@ -513,12 +502,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
|
|||
ah->macaddr[2 * i] = eeval >> 8;
|
||||
ah->macaddr[2 * i + 1] = eeval & 0xff;
|
||||
}
|
||||
if (sum == 0 || sum == 0xffff * 3) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"mac address read failed: %pM\n",
|
||||
ah->macaddr);
|
||||
if (sum == 0 || sum == 0xffff * 3)
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -575,11 +560,8 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
|
|||
{
|
||||
int ecode;
|
||||
|
||||
if (!ath9k_hw_chip_test(ah)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
"hardware self-test failed\n");
|
||||
if (!ath9k_hw_chip_test(ah))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ecode = ath9k_hw_rf_claim(ah);
|
||||
if (ecode != 0)
|
||||
|
@ -617,17 +599,14 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
|
|||
|
||||
ath9k_hw_set_defaults(ah);
|
||||
|
||||
if (ah->config.intr_mitigation != 0)
|
||||
ah->intr_mitigation = true;
|
||||
|
||||
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
|
||||
DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n");
|
||||
DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
|
||||
ecode = -EIO;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
|
||||
DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
|
||||
DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
|
||||
ecode = -EIO;
|
||||
goto bad;
|
||||
}
|
||||
|
@ -650,7 +629,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
|
|||
(ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
|
||||
(ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
|
||||
(!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
|
||||
DPRINTF(sc, ATH_DBG_RESET,
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Mac Chip Rev 0x%02x.%x is not supported by "
|
||||
"this driver\n", ah->hw_version.macVersion,
|
||||
ah->hw_version.macRev);
|
||||
|
@ -690,10 +669,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
|
|||
if (AR_SREV_9280_10_OR_LATER(ah))
|
||||
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
|
||||
|
||||
DPRINTF(sc, ATH_DBG_RESET,
|
||||
"This Mac Chip Rev 0x%02x.%x is \n",
|
||||
ah->hw_version.macVersion, ah->hw_version.macRev);
|
||||
|
||||
if (AR_SREV_9285_12_OR_LATER(ah)) {
|
||||
|
||||
INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
|
||||
|
@ -859,11 +834,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
|
|||
if (AR_SREV_9280_20(ah))
|
||||
ath9k_hw_init_txgain_ini(ah);
|
||||
|
||||
if (!ath9k_hw_fill_cap_info(ah)) {
|
||||
DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n");
|
||||
ecode = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
ath9k_hw_fill_cap_info(ah);
|
||||
|
||||
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
|
||||
test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
|
||||
|
@ -885,8 +856,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
|
|||
|
||||
ecode = ath9k_hw_init_macaddr(ah);
|
||||
if (ecode != 0) {
|
||||
DPRINTF(sc, ATH_DBG_RESET,
|
||||
"failed initializing mac address\n");
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Failed to initialize MAC address\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
|
@ -1054,7 +1025,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
|
|||
AR_IMR_RXORN |
|
||||
AR_IMR_BCNMISC;
|
||||
|
||||
if (ah->intr_mitigation)
|
||||
if (ah->config.intr_mitigation)
|
||||
ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
|
||||
else
|
||||
ah->mask_reg |= AR_IMR_RXOK;
|
||||
|
@ -1203,23 +1174,23 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
|
|||
switch (ah->hw_version.devid) {
|
||||
case AR9280_DEVID_PCI:
|
||||
if (reg == 0x7894) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"ini VAL: %x EEPROM: %x\n", value,
|
||||
(pBase->version & 0xff));
|
||||
|
||||
if ((pBase->version & 0xff) > 0x0a) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"PWDCLKIND: %d\n",
|
||||
pBase->pwdclkind);
|
||||
value &= ~AR_AN_TOP2_PWDCLKIND;
|
||||
value |= AR_AN_TOP2_PWDCLKIND &
|
||||
(pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
|
||||
} else {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"PWDCLKIND Earlier Rev\n");
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"final ini VAL: %x\n", value);
|
||||
}
|
||||
break;
|
||||
|
@ -1249,6 +1220,21 @@ static void ath9k_olc_init(struct ath_hw *ah)
|
|||
ah->PDADCdelta = 0;
|
||||
}
|
||||
|
||||
static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band);
|
||||
|
||||
if (IS_CHAN_B(chan))
|
||||
ctl |= CTL_11B;
|
||||
else if (IS_CHAN_G(chan))
|
||||
ctl |= CTL_11G;
|
||||
else
|
||||
ctl |= CTL_11A;
|
||||
|
||||
return ctl;
|
||||
}
|
||||
|
||||
static int ath9k_hw_process_ini(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
enum ath9k_ht_macmode macmode)
|
||||
|
@ -1360,19 +1346,19 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
|
|||
ath9k_olc_init(ah);
|
||||
|
||||
status = ah->eep_ops->set_txpower(ah, chan,
|
||||
ath9k_regd_get_ctl(ah, chan),
|
||||
ath9k_regd_get_ctl(&ah->regulatory, chan),
|
||||
channel->max_antenna_gain * 2,
|
||||
channel->max_power * 2,
|
||||
min((u32) MAX_RATE_POWER,
|
||||
(u32) ah->regulatory.power_limit));
|
||||
if (status != 0) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
"error init'ing transmit power\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Error initializing transmit power\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"ar5416SetRfRegs failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -1678,7 +1664,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
|
|||
REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
|
||||
if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
|
||||
AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Could not kill baseband RX\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -1687,26 +1673,26 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
|
|||
|
||||
if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
|
||||
"failed to set channel\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Failed to set channel\n");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!(ath9k_hw_set_channel(ah, chan))) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
|
||||
"failed to set channel\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Failed to set channel\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ah->eep_ops->set_txpower(ah, chan,
|
||||
ath9k_regd_get_ctl(ah, chan),
|
||||
ath9k_regd_get_ctl(&ah->regulatory, chan),
|
||||
channel->max_antenna_gain * 2,
|
||||
channel->max_power * 2,
|
||||
min((u32) MAX_RATE_POWER,
|
||||
(u32) ah->regulatory.power_limit)) != 0) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
|
||||
"error init'ing transmit power\n");
|
||||
"Error initializing transmit power\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2199,14 +2185,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
ah->txchainmask = sc->tx_chainmask;
|
||||
ah->rxchainmask = sc->rx_chainmask;
|
||||
|
||||
if (AR_SREV_9285(ah)) {
|
||||
ah->txchainmask &= 0x1;
|
||||
ah->rxchainmask &= 0x1;
|
||||
} else if (AR_SREV_9280(ah)) {
|
||||
ah->txchainmask &= 0x3;
|
||||
ah->rxchainmask &= 0x3;
|
||||
}
|
||||
|
||||
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
|
||||
return -EIO;
|
||||
|
||||
|
@ -2242,7 +2220,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
ath9k_hw_mark_phy_inactive(ah);
|
||||
|
||||
if (!ath9k_hw_chip_reset(ah, chan)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2335,8 +2313,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
|
||||
REG_WRITE(ah, AR_OBS, 8);
|
||||
|
||||
if (ah->intr_mitigation) {
|
||||
|
||||
if (ah->config.intr_mitigation) {
|
||||
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
|
||||
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
|
||||
}
|
||||
|
@ -2385,8 +2362,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
|
|||
u32 keyType;
|
||||
|
||||
if (entry >= ah->caps.keycache_size) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
"entry %u out of range\n", entry);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"keychache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2422,8 +2399,8 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
|
|||
u32 macHi, macLo;
|
||||
|
||||
if (entry >= ah->caps.keycache_size) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
"entry %u out of range\n", entry);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"keychache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2454,8 +2431,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
|||
u32 keyType;
|
||||
|
||||
if (entry >= pCap->keycache_size) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
"entry %u out of range\n", entry);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"keycache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2465,7 +2442,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
|||
break;
|
||||
case ATH9K_CIPHER_AES_CCM:
|
||||
if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
"AES-CCM not supported by mac rev 0x%x\n",
|
||||
ah->hw_version.macRev);
|
||||
return false;
|
||||
|
@ -2476,14 +2453,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
|||
keyType = AR_KEYTABLE_TYPE_TKIP;
|
||||
if (ATH9K_IS_MIC_ENABLED(ah)
|
||||
&& entry + 64 >= pCap->keycache_size) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
"entry %u inappropriate for TKIP\n", entry);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ATH9K_CIPHER_WEP:
|
||||
if (k->kv_len < LEN_WEP40) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
"WEP key length %u too small\n", k->kv_len);
|
||||
return false;
|
||||
}
|
||||
|
@ -2498,7 +2475,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
|||
keyType = AR_KEYTABLE_TYPE_CLR;
|
||||
break;
|
||||
default:
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"cipher %u not supported\n", k->kv_type);
|
||||
return false;
|
||||
}
|
||||
|
@ -2716,7 +2693,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
|
|||
AR_RTC_FORCE_WAKE_EN);
|
||||
}
|
||||
if (i == 0) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Failed to wakeup in %uus\n", POWER_UP_TIME / 20);
|
||||
return false;
|
||||
}
|
||||
|
@ -2737,9 +2714,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
|
|||
"UNDEFINED"
|
||||
};
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
|
||||
modes[ah->power_mode], modes[mode],
|
||||
setChip ? "set chip " : "");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
|
||||
modes[ah->power_mode], modes[mode]);
|
||||
|
||||
switch (mode) {
|
||||
case ATH9K_PM_AWAKE:
|
||||
|
@ -2753,7 +2729,7 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
|
|||
ath9k_set_power_network_sleep(ah, setChip);
|
||||
break;
|
||||
default:
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Unknown power mode %u\n", mode);
|
||||
return false;
|
||||
}
|
||||
|
@ -2943,7 +2919,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
|
|||
|
||||
*masked = isr & ATH9K_INT_COMMON;
|
||||
|
||||
if (ah->intr_mitigation) {
|
||||
if (ah->config.intr_mitigation) {
|
||||
if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
|
||||
*masked |= ATH9K_INT_RX;
|
||||
}
|
||||
|
@ -3000,6 +2976,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
|
|||
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
|
||||
"received PCI PERR interrupt\n");
|
||||
}
|
||||
*masked |= ATH9K_INT_FATAL;
|
||||
}
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
|
||||
|
@ -3061,7 +3038,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
|
|||
}
|
||||
if (ints & ATH9K_INT_RX) {
|
||||
mask |= AR_IMR_RXERR;
|
||||
if (ah->intr_mitigation)
|
||||
if (ah->config.intr_mitigation)
|
||||
mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
|
||||
else
|
||||
mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
|
||||
|
@ -3259,7 +3236,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
|
|||
/* HW Capabilities */
|
||||
/*******************/
|
||||
|
||||
bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
||||
void ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
||||
{
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
u16 capField = 0, eeval;
|
||||
|
@ -3343,8 +3320,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
|
||||
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
|
||||
|
||||
if (ah->config.ht_enable)
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_HT;
|
||||
else
|
||||
|
@ -3368,7 +3343,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
pCap->keycache_size = AR_KEYTABLE_SIZE;
|
||||
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
|
||||
pCap->num_mr_retries = 4;
|
||||
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
|
||||
|
||||
if (AR_SREV_9285_10_OR_LATER(ah))
|
||||
|
@ -3378,14 +3352,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
else
|
||||
pCap->num_gpio_pins = AR_NUM_GPIO;
|
||||
|
||||
if (AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_WOW;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
|
||||
} else {
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
|
||||
}
|
||||
|
||||
if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_CST;
|
||||
pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
|
||||
|
@ -3411,7 +3377,8 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
(ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ||
|
||||
(ah->hw_version.macVersion == AR_SREV_VERSION_9160) ||
|
||||
(ah->hw_version.macVersion == AR_SREV_VERSION_9100) ||
|
||||
(ah->hw_version.macVersion == AR_SREV_VERSION_9280))
|
||||
(ah->hw_version.macVersion == AR_SREV_VERSION_9280) ||
|
||||
(ah->hw_version.macVersion == AR_SREV_VERSION_9285))
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
|
||||
else
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
|
||||
|
@ -3445,8 +3412,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
ah->btactive_gpio = 6;
|
||||
ah->wlanactive_gpio = 5;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
|
||||
|
@ -3762,7 +3727,7 @@ bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
|
|||
ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
|
||||
|
||||
if (ah->eep_ops->set_txpower(ah, chan,
|
||||
ath9k_regd_get_ctl(ah, chan),
|
||||
ath9k_regd_get_ctl(&ah->regulatory, chan),
|
||||
channel->max_antenna_gain * 2,
|
||||
channel->max_power * 2,
|
||||
min((u32) MAX_RATE_POWER,
|
|
@ -25,10 +25,11 @@
|
|||
#include "ani.h"
|
||||
#include "eeprom.h"
|
||||
#include "calib.h"
|
||||
#include "regd.h"
|
||||
#include "reg.h"
|
||||
#include "phy.h"
|
||||
|
||||
#include "../regd.h"
|
||||
|
||||
#define ATHEROS_VENDOR_ID 0x168c
|
||||
#define AR5416_DEVID_PCI 0x0023
|
||||
#define AR5416_DEVID_PCIE 0x0024
|
||||
|
@ -124,29 +125,24 @@ enum wireless_mode {
|
|||
};
|
||||
|
||||
enum ath9k_hw_caps {
|
||||
ATH9K_HW_CAP_CHAN_SPREAD = BIT(0),
|
||||
ATH9K_HW_CAP_MIC_AESCCM = BIT(1),
|
||||
ATH9K_HW_CAP_MIC_CKIP = BIT(2),
|
||||
ATH9K_HW_CAP_MIC_TKIP = BIT(3),
|
||||
ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4),
|
||||
ATH9K_HW_CAP_CIPHER_CKIP = BIT(5),
|
||||
ATH9K_HW_CAP_CIPHER_TKIP = BIT(6),
|
||||
ATH9K_HW_CAP_VEOL = BIT(7),
|
||||
ATH9K_HW_CAP_BSSIDMASK = BIT(8),
|
||||
ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9),
|
||||
ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10),
|
||||
ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11),
|
||||
ATH9K_HW_CAP_HT = BIT(12),
|
||||
ATH9K_HW_CAP_GTT = BIT(13),
|
||||
ATH9K_HW_CAP_FASTCC = BIT(14),
|
||||
ATH9K_HW_CAP_RFSILENT = BIT(15),
|
||||
ATH9K_HW_CAP_WOW = BIT(16),
|
||||
ATH9K_HW_CAP_CST = BIT(17),
|
||||
ATH9K_HW_CAP_ENHANCEDPM = BIT(18),
|
||||
ATH9K_HW_CAP_AUTOSLEEP = BIT(19),
|
||||
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20),
|
||||
ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21),
|
||||
ATH9K_HW_CAP_BT_COEX = BIT(22)
|
||||
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
|
||||
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
|
||||
ATH9K_HW_CAP_MIC_TKIP = BIT(2),
|
||||
ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3),
|
||||
ATH9K_HW_CAP_CIPHER_CKIP = BIT(4),
|
||||
ATH9K_HW_CAP_CIPHER_TKIP = BIT(5),
|
||||
ATH9K_HW_CAP_VEOL = BIT(6),
|
||||
ATH9K_HW_CAP_BSSIDMASK = BIT(7),
|
||||
ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8),
|
||||
ATH9K_HW_CAP_HT = BIT(9),
|
||||
ATH9K_HW_CAP_GTT = BIT(10),
|
||||
ATH9K_HW_CAP_FASTCC = BIT(11),
|
||||
ATH9K_HW_CAP_RFSILENT = BIT(12),
|
||||
ATH9K_HW_CAP_CST = BIT(13),
|
||||
ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
|
||||
ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
|
||||
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
|
||||
ATH9K_HW_CAP_BT_COEX = BIT(17)
|
||||
};
|
||||
|
||||
enum ath9k_capability_type {
|
||||
|
@ -166,7 +162,6 @@ struct ath9k_hw_capabilities {
|
|||
u16 keycache_size;
|
||||
u16 low_5ghz_chan, high_5ghz_chan;
|
||||
u16 low_2ghz_chan, high_2ghz_chan;
|
||||
u16 num_mr_retries;
|
||||
u16 rts_aggr_limit;
|
||||
u8 tx_chainmask;
|
||||
u8 rx_chainmask;
|
||||
|
@ -184,11 +179,8 @@ struct ath9k_ops_config {
|
|||
int ack_6mb;
|
||||
int cwm_ignore_extcca;
|
||||
u8 pcie_powersave_enable;
|
||||
u8 pcie_l1skp_enable;
|
||||
u8 pcie_clock_req;
|
||||
u32 pcie_waen;
|
||||
int pcie_power_reset;
|
||||
u8 pcie_restore;
|
||||
u8 analog_shiftreg;
|
||||
u8 ht_enable;
|
||||
u32 ofdm_trig_low;
|
||||
|
@ -196,17 +188,10 @@ struct ath9k_ops_config {
|
|||
u32 cck_trig_high;
|
||||
u32 cck_trig_low;
|
||||
u32 enable_ani;
|
||||
u8 noise_immunity_level;
|
||||
u32 ofdm_weaksignal_det;
|
||||
u32 cck_weaksignal_thr;
|
||||
u8 spur_immunity_level;
|
||||
u8 firstep_level;
|
||||
int8_t rssi_thr_high;
|
||||
int8_t rssi_thr_low;
|
||||
u16 diversity_control;
|
||||
u16 antenna_switch_swap;
|
||||
int serialize_regmode;
|
||||
int intr_mitigation;
|
||||
bool intr_mitigation;
|
||||
#define SPUR_DISABLE 0
|
||||
#define SPUR_ENABLE_IOCTL 1
|
||||
#define SPUR_ENABLE_EEPROM 2
|
||||
|
@ -281,13 +266,6 @@ enum ath9k_int {
|
|||
#define CHANNEL_HT40PLUS 0x20000
|
||||
#define CHANNEL_HT40MINUS 0x40000
|
||||
|
||||
#define CHANNEL_INTERFERENCE 0x01
|
||||
#define CHANNEL_DFS 0x02
|
||||
#define CHANNEL_4MS_LIMIT 0x04
|
||||
#define CHANNEL_DFS_CLEAR 0x08
|
||||
#define CHANNEL_DISALLOW_ADHOC 0x10
|
||||
#define CHANNEL_PER_11D_ADHOC 0x20
|
||||
|
||||
#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM)
|
||||
#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK)
|
||||
#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM)
|
||||
|
@ -318,10 +296,6 @@ struct ath9k_channel {
|
|||
int16_t rawNoiseFloor;
|
||||
};
|
||||
|
||||
#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
|
||||
(((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
|
||||
(((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
|
||||
(((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
|
||||
#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
|
||||
(((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
|
||||
(((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
|
||||
|
@ -329,7 +303,6 @@ struct ath9k_channel {
|
|||
#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
|
||||
#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
|
||||
#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
|
||||
#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
|
||||
#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
|
||||
#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
|
||||
#define IS_CHAN_A_5MHZ_SPACED(_c) \
|
||||
|
@ -420,7 +393,7 @@ struct ath_hw {
|
|||
struct ath9k_hw_version hw_version;
|
||||
struct ath9k_ops_config config;
|
||||
struct ath9k_hw_capabilities caps;
|
||||
struct ath9k_regulatory regulatory;
|
||||
struct ath_regulatory regulatory;
|
||||
struct ath9k_channel channels[38];
|
||||
struct ath9k_channel *curchan;
|
||||
|
||||
|
@ -463,14 +436,14 @@ struct ath_hw {
|
|||
enum ath9k_ant_setting diversity_control;
|
||||
|
||||
/* Calibration */
|
||||
enum hal_cal_types supp_cals;
|
||||
struct hal_cal_list iq_caldata;
|
||||
struct hal_cal_list adcgain_caldata;
|
||||
struct hal_cal_list adcdc_calinitdata;
|
||||
struct hal_cal_list adcdc_caldata;
|
||||
struct hal_cal_list *cal_list;
|
||||
struct hal_cal_list *cal_list_last;
|
||||
struct hal_cal_list *cal_list_curr;
|
||||
enum ath9k_cal_types supp_cals;
|
||||
struct ath9k_cal_list iq_caldata;
|
||||
struct ath9k_cal_list adcgain_caldata;
|
||||
struct ath9k_cal_list adcdc_calinitdata;
|
||||
struct ath9k_cal_list adcdc_caldata;
|
||||
struct ath9k_cal_list *cal_list;
|
||||
struct ath9k_cal_list *cal_list_last;
|
||||
struct ath9k_cal_list *cal_list_curr;
|
||||
#define totalPowerMeasI meas0.unsign
|
||||
#define totalPowerMeasQ meas1.unsign
|
||||
#define totalIqCorrMeas meas2.sign
|
||||
|
@ -540,7 +513,6 @@ struct ath_hw {
|
|||
enum ath9k_ani_cmd ani_function;
|
||||
|
||||
u32 intr_txqs;
|
||||
bool intr_mitigation;
|
||||
enum ath9k_ht_extprotspacing extprotspacing;
|
||||
u8 txchainmask;
|
||||
u8 rxchainmask;
|
||||
|
@ -573,7 +545,7 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error);
|
|||
void ath9k_hw_rfdetach(struct ath_hw *ah);
|
||||
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
bool bChannelChange);
|
||||
bool ath9k_hw_fill_cap_info(struct ath_hw *ah);
|
||||
void ath9k_hw_fill_cap_info(struct ath_hw *ah);
|
||||
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
|
||||
u32 capability, u32 *result);
|
||||
bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
|
|
@ -49,7 +49,7 @@ bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
|
|||
|
||||
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
|
||||
|
||||
REG_WRITE(ah, AR_Q_TXE, 1 << q);
|
||||
|
||||
|
@ -110,13 +110,15 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
|
|||
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
|
||||
"invalid queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
|
||||
"inactive queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -146,7 +148,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
|
|||
break;
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
|
||||
"TSF have moved while trying to set "
|
||||
"TSF has moved while trying to set "
|
||||
"quiet time TSF: 0x%08x\n", tsfLow);
|
||||
}
|
||||
|
||||
|
@ -158,8 +160,8 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
|
|||
wait = wait_time;
|
||||
while (ath9k_hw_numtxpending(ah, q)) {
|
||||
if ((--wait) == 0) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
|
||||
"Failed to stop Tx DMA in 100 "
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
|
||||
"Failed to stop TX DMA in 100 "
|
||||
"msec after killing last frame\n");
|
||||
break;
|
||||
}
|
||||
|
@ -454,17 +456,19 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
|
|||
struct ath9k_tx_queue_info *qi;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
|
||||
"invalid queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
|
||||
"inactive queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
|
||||
|
||||
qi->tqi_ver = qinfo->tqi_ver;
|
||||
qi->tqi_subtype = qinfo->tqi_subtype;
|
||||
|
@ -521,13 +525,15 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
|
|||
struct ath9k_tx_queue_info *qi;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
|
||||
"invalid queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
|
||||
"inactive queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -575,22 +581,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
|
|||
ATH9K_TX_QUEUE_INACTIVE)
|
||||
break;
|
||||
if (q == pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
|
||||
"no available tx queue\n");
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"No available TX queue\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n",
|
||||
type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
|
||||
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
|
||||
"tx queue %u already active\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"TX queue: %u already active\n", q);
|
||||
return -1;
|
||||
}
|
||||
memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
|
||||
|
@ -620,16 +627,18 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
|
|||
struct ath9k_tx_queue_info *qi;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
|
||||
"invalid queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
|
||||
"inactive queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
|
||||
|
||||
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
|
||||
ah->txok_interrupt_mask &= ~(1 << q);
|
||||
|
@ -650,17 +659,19 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
|
|||
u32 cwMin, chanCwMin, value;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
|
||||
"invalid queue: %u\n", q);
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
|
||||
"inactive queue: %u\n", q);
|
||||
return true;
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
|
||||
|
||||
if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
|
||||
if (chan && IS_CHAN_B(chan))
|
||||
|
@ -894,7 +905,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
|
|||
|
||||
reg = REG_READ(ah, AR_OBS_BUS_1);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"rx failed to go idle in 10 ms RXSM=0x%x\n", reg);
|
||||
"RX failed to go idle in 10 ms RXSM=0x%x\n", reg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -949,8 +960,8 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
|
|||
}
|
||||
|
||||
if (i == 0) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
|
||||
"dma failed to stop in %d ms "
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"DMA failed to stop in %d ms "
|
||||
"AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
|
||||
AH_RX_STOP_DMA_TIMEOUT / 1000,
|
||||
REG_READ(ah, AR_CR),
|
|
@ -287,7 +287,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
}
|
||||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
|
||||
sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
|
||||
sc->sc_flags &= ~SC_OP_FULL_RESET;
|
||||
|
||||
if (ath_startrecv(sc) != 0) {
|
||||
|
@ -368,28 +367,16 @@ static void ath_ani_calibrate(unsigned long data)
|
|||
|
||||
/* Perform calibration if necessary */
|
||||
if (longcal || shortcal) {
|
||||
bool iscaldone = false;
|
||||
sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan,
|
||||
sc->rx_chainmask, longcal);
|
||||
|
||||
if (ath9k_hw_calibrate(ah, ah->curchan,
|
||||
sc->rx_chainmask, longcal,
|
||||
&iscaldone)) {
|
||||
if (longcal)
|
||||
sc->ani.noise_floor =
|
||||
ath9k_hw_getchan_noise(ah,
|
||||
ah->curchan);
|
||||
if (longcal)
|
||||
sc->ani.noise_floor = ath9k_hw_getchan_noise(ah,
|
||||
ah->curchan);
|
||||
|
||||
DPRINTF(sc, ATH_DBG_ANI,
|
||||
"calibrate chan %u/%x nf: %d\n",
|
||||
ah->curchan->channel,
|
||||
ah->curchan->channelFlags,
|
||||
sc->ani.noise_floor);
|
||||
} else {
|
||||
DPRINTF(sc, ATH_DBG_ANY,
|
||||
"calibrate chan %u/%x failed\n",
|
||||
ah->curchan->channel,
|
||||
ah->curchan->channelFlags);
|
||||
}
|
||||
sc->ani.caldone = iscaldone;
|
||||
DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n",
|
||||
ah->curchan->channel, ah->curchan->channelFlags,
|
||||
sc->ani.noise_floor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,6 +395,18 @@ static void ath_ani_calibrate(unsigned long data)
|
|||
mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
|
||||
}
|
||||
|
||||
static void ath_start_ani(struct ath_softc *sc)
|
||||
{
|
||||
unsigned long timestamp = jiffies_to_msecs(jiffies);
|
||||
|
||||
sc->ani.longcal_timer = timestamp;
|
||||
sc->ani.shortcal_timer = timestamp;
|
||||
sc->ani.checkani_timer = timestamp;
|
||||
|
||||
mod_timer(&sc->ani.timer,
|
||||
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Update tx/rx chainmask. For legacy association,
|
||||
* hard code chainmask to 1x1, for 11n association, use
|
||||
|
@ -416,7 +415,6 @@ static void ath_ani_calibrate(unsigned long data)
|
|||
*/
|
||||
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
|
||||
{
|
||||
sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
|
||||
if (is_ht ||
|
||||
(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
|
||||
sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
|
||||
|
@ -436,12 +434,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
|
|||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
if (sc->sc_flags & SC_OP_TXAGGR)
|
||||
if (sc->sc_flags & SC_OP_TXAGGR) {
|
||||
ath_tx_node_init(sc, an);
|
||||
|
||||
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
|
||||
sta->ht_cap.ampdu_factor);
|
||||
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
|
||||
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
|
||||
sta->ht_cap.ampdu_factor);
|
||||
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
|
||||
|
@ -458,133 +456,124 @@ static void ath9k_tasklet(unsigned long data)
|
|||
u32 status = sc->intrstatus;
|
||||
|
||||
if (status & ATH9K_INT_FATAL) {
|
||||
/* need a chip reset */
|
||||
ath_reset(sc, false);
|
||||
return;
|
||||
} else {
|
||||
|
||||
if (status &
|
||||
(ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
|
||||
spin_lock_bh(&sc->rx.rxflushlock);
|
||||
ath_rx_tasklet(sc, 0);
|
||||
spin_unlock_bh(&sc->rx.rxflushlock);
|
||||
}
|
||||
/* XXX: optimize this */
|
||||
if (status & ATH9K_INT_TX)
|
||||
ath_tx_tasklet(sc);
|
||||
}
|
||||
|
||||
if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
|
||||
spin_lock_bh(&sc->rx.rxflushlock);
|
||||
ath_rx_tasklet(sc, 0);
|
||||
spin_unlock_bh(&sc->rx.rxflushlock);
|
||||
}
|
||||
|
||||
if (status & ATH9K_INT_TX)
|
||||
ath_tx_tasklet(sc);
|
||||
|
||||
/* re-enable hardware interrupt */
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||
}
|
||||
|
||||
irqreturn_t ath_isr(int irq, void *dev)
|
||||
{
|
||||
#define SCHED_INTR ( \
|
||||
ATH9K_INT_FATAL | \
|
||||
ATH9K_INT_RXORN | \
|
||||
ATH9K_INT_RXEOL | \
|
||||
ATH9K_INT_RX | \
|
||||
ATH9K_INT_TX | \
|
||||
ATH9K_INT_BMISS | \
|
||||
ATH9K_INT_CST | \
|
||||
ATH9K_INT_TSFOOR)
|
||||
|
||||
struct ath_softc *sc = dev;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
enum ath9k_int status;
|
||||
bool sched = false;
|
||||
|
||||
do {
|
||||
if (sc->sc_flags & SC_OP_INVALID) {
|
||||
/*
|
||||
* The hardware is not ready/present, don't
|
||||
* touch anything. Note this can happen early
|
||||
* on if the IRQ is shared.
|
||||
*/
|
||||
return IRQ_NONE;
|
||||
}
|
||||
if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
/*
|
||||
* The hardware is not ready/present, don't
|
||||
* touch anything. Note this can happen early
|
||||
* on if the IRQ is shared.
|
||||
*/
|
||||
if (sc->sc_flags & SC_OP_INVALID)
|
||||
return IRQ_NONE;
|
||||
|
||||
/*
|
||||
* Figure out the reason(s) for the interrupt. Note
|
||||
* that the hal returns a pseudo-ISR that may include
|
||||
* bits we haven't explicitly enabled so we mask the
|
||||
* value to insure we only process bits we requested.
|
||||
*/
|
||||
ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
status &= sc->imask; /* discard unasked-for bits */
|
||||
/* shared irq, not for us */
|
||||
|
||||
/*
|
||||
* If there are no status bits set, then this interrupt was not
|
||||
* for me (should have been caught above).
|
||||
*/
|
||||
if (!status)
|
||||
return IRQ_NONE;
|
||||
|
||||
sc->intrstatus = status;
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
if (status & ATH9K_INT_FATAL) {
|
||||
/* need a chip reset */
|
||||
sched = true;
|
||||
} else if (status & ATH9K_INT_RXORN) {
|
||||
/* need a chip reset */
|
||||
sched = true;
|
||||
} else {
|
||||
if (status & ATH9K_INT_SWBA) {
|
||||
/* schedule a tasklet for beacon handling */
|
||||
tasklet_schedule(&sc->bcon_tasklet);
|
||||
}
|
||||
if (status & ATH9K_INT_RXEOL) {
|
||||
/*
|
||||
* NB: the hardware should re-read the link when
|
||||
* RXE bit is written, but it doesn't work
|
||||
* at least on older hardware revs.
|
||||
*/
|
||||
sched = true;
|
||||
}
|
||||
|
||||
if (status & ATH9K_INT_TXURN)
|
||||
/* bump tx trigger level */
|
||||
ath9k_hw_updatetxtriglevel(ah, true);
|
||||
/* XXX: optimize this */
|
||||
if (status & ATH9K_INT_RX)
|
||||
sched = true;
|
||||
if (status & ATH9K_INT_TX)
|
||||
sched = true;
|
||||
if (status & ATH9K_INT_BMISS)
|
||||
sched = true;
|
||||
/* carrier sense timeout */
|
||||
if (status & ATH9K_INT_CST)
|
||||
sched = true;
|
||||
if (status & ATH9K_INT_MIB) {
|
||||
/*
|
||||
* Disable interrupts until we service the MIB
|
||||
* interrupt; otherwise it will continue to
|
||||
* fire.
|
||||
*/
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
/*
|
||||
* Let the hal handle the event. We assume
|
||||
* it will clear whatever condition caused
|
||||
* the interrupt.
|
||||
*/
|
||||
ath9k_hw_procmibevent(ah, &sc->nodestats);
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
}
|
||||
if (status & ATH9K_INT_TIM_TIMER) {
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
/* Clear RxAbort bit so that we can
|
||||
* receive frames */
|
||||
ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
|
||||
ath9k_hw_setrxabort(ah, 0);
|
||||
sched = true;
|
||||
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
|
||||
}
|
||||
}
|
||||
if (status & ATH9K_INT_TSFOOR) {
|
||||
/* FIXME: Handle this interrupt for power save */
|
||||
sched = true;
|
||||
}
|
||||
}
|
||||
if (!ath9k_hw_intrpend(ah)) {
|
||||
ath9k_ps_restore(sc);
|
||||
} while (0);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out the reason(s) for the interrupt. Note
|
||||
* that the hal returns a pseudo-ISR that may include
|
||||
* bits we haven't explicitly enabled so we mask the
|
||||
* value to insure we only process bits we requested.
|
||||
*/
|
||||
ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
|
||||
status &= sc->imask; /* discard unasked-for bits */
|
||||
|
||||
/*
|
||||
* If there are no status bits set, then this interrupt was not
|
||||
* for me (should have been caught above).
|
||||
*/
|
||||
if (!status) {
|
||||
ath9k_ps_restore(sc);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Cache the status */
|
||||
sc->intrstatus = status;
|
||||
|
||||
if (status & SCHED_INTR)
|
||||
sched = true;
|
||||
|
||||
/*
|
||||
* If a FATAL or RXORN interrupt is received, we have to reset the
|
||||
* chip immediately.
|
||||
*/
|
||||
if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN))
|
||||
goto chip_reset;
|
||||
|
||||
if (status & ATH9K_INT_SWBA)
|
||||
tasklet_schedule(&sc->bcon_tasklet);
|
||||
|
||||
if (status & ATH9K_INT_TXURN)
|
||||
ath9k_hw_updatetxtriglevel(ah, true);
|
||||
|
||||
if (status & ATH9K_INT_MIB) {
|
||||
/*
|
||||
* Disable interrupts until we service the MIB
|
||||
* interrupt; otherwise it will continue to
|
||||
* fire.
|
||||
*/
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
/*
|
||||
* Let the hal handle the event. We assume
|
||||
* it will clear whatever condition caused
|
||||
* the interrupt.
|
||||
*/
|
||||
ath9k_hw_procmibevent(ah, &sc->nodestats);
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
}
|
||||
|
||||
if (status & ATH9K_INT_TIM_TIMER) {
|
||||
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
/* Clear RxAbort bit so that we can
|
||||
* receive frames */
|
||||
ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
|
||||
ath9k_hw_setrxabort(ah, 0);
|
||||
sched = true;
|
||||
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
|
||||
}
|
||||
}
|
||||
|
||||
chip_reset:
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
ath_debug_stat_interrupt(sc, status);
|
||||
|
||||
if (sched) {
|
||||
|
@ -594,6 +583,8 @@ irqreturn_t ath_isr(int irq, void *dev)
|
|||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
#undef SCHED_INTR
|
||||
}
|
||||
|
||||
static u32 ath_get_extchanmode(struct ath_softc *sc,
|
||||
|
@ -676,7 +667,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
|
|||
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
|
||||
if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
|
||||
/* TX MIC entry failed. No need to proceed further */
|
||||
DPRINTF(sc, ATH_DBG_KEYCACHE,
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Setting TX MIC Key Failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -920,11 +911,9 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
|
|||
sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
|
||||
|
||||
/* Start ANI */
|
||||
mod_timer(&sc->ani.timer,
|
||||
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
||||
ath_start_ani(sc);
|
||||
} else {
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
|
||||
sc->curaid = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1098,10 +1087,10 @@ void ath_radio_enable(struct ath_softc *sc)
|
|||
int r;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_hw_configpcipowersave(ah, 0);
|
||||
|
||||
spin_lock_bh(&sc->sc_resetlock);
|
||||
|
||||
r = ath9k_hw_reset(ah, ah->curchan, false);
|
||||
|
||||
if (r) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Unable to reset channel %u (%uMhz) ",
|
||||
|
@ -1163,6 +1152,7 @@ void ath_radio_disable(struct ath_softc *sc)
|
|||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
|
||||
ath9k_hw_phy_disable(ah);
|
||||
ath9k_hw_configpcipowersave(ah, 1);
|
||||
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
@ -1267,7 +1257,6 @@ static int ath_init_sw_rfkill(struct ath_softc *sc)
|
|||
sc->rf_kill.rfkill->data = sc;
|
||||
sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
|
||||
sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
sc->rf_kill.rfkill->user_claim_unsupported = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1362,6 +1351,17 @@ void ath_detach(struct ath_softc *sc)
|
|||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
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 = &sc->sc_ah->regulatory;
|
||||
|
||||
return ath_reg_notifier_apply(wiphy, request, reg);
|
||||
}
|
||||
|
||||
static int ath_init(u16 devid, struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = NULL;
|
||||
|
@ -1403,7 +1403,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
|
|||
/* Get the hardware key cache size. */
|
||||
sc->keymax = ah->caps.keycache_size;
|
||||
if (sc->keymax > ATH_KEYMAX) {
|
||||
DPRINTF(sc, ATH_DBG_KEYCACHE,
|
||||
DPRINTF(sc, ATH_DBG_ANY,
|
||||
"Warning, using only %u entries in %u key cache\n",
|
||||
ATH_KEYMAX, sc->keymax);
|
||||
sc->keymax = ATH_KEYMAX;
|
||||
|
@ -1416,7 +1416,9 @@ static int ath_init(u16 devid, struct ath_softc *sc)
|
|||
for (i = 0; i < sc->keymax; i++)
|
||||
ath9k_hw_keyreset(ah, (u16) i);
|
||||
|
||||
if (ath9k_regd_init(sc->sc_ah))
|
||||
error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
|
||||
ath9k_reg_notifier);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/* default to MONITOR mode */
|
||||
|
@ -1545,9 +1547,6 @@ static int ath_init(u16 devid, struct ath_softc *sc)
|
|||
sc->beacon.bslot_aphy[i] = NULL;
|
||||
}
|
||||
|
||||
/* save MISC configurations */
|
||||
sc->config.swBeaconProcess = 1;
|
||||
|
||||
/* setup channels and rates */
|
||||
|
||||
sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
|
||||
|
@ -1602,9 +1601,6 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->wiphy->reg_notifier = ath9k_reg_notifier;
|
||||
hw->wiphy->strict_regulatory = true;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
hw->channel_change_time = 5000;
|
||||
|
@ -1625,8 +1621,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
int ath_attach(u16 devid, struct ath_softc *sc)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
const struct ieee80211_regdomain *regd;
|
||||
int error = 0, i;
|
||||
struct ath_regulatory *reg;
|
||||
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
|
||||
|
||||
|
@ -1634,6 +1630,8 @@ int ath_attach(u16 devid, struct ath_softc *sc)
|
|||
if (error != 0)
|
||||
return error;
|
||||
|
||||
reg = &sc->sc_ah->regulatory;
|
||||
|
||||
/* get mac address from hardware and set in mac80211 */
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
|
||||
|
@ -1666,31 +1664,14 @@ int ath_attach(u16 devid, struct ath_softc *sc)
|
|||
goto error_attach;
|
||||
#endif
|
||||
|
||||
if (ath9k_is_world_regd(sc->sc_ah)) {
|
||||
/* Anything applied here (prior to wiphy registration) gets
|
||||
* saved on the wiphy orig_* parameters */
|
||||
regd = ath9k_world_regdomain(sc->sc_ah);
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->strict_regulatory = false;
|
||||
} else {
|
||||
/* This gets applied in the case of the absense of CRDA,
|
||||
* it's our own custom world regulatory domain, similar to
|
||||
* cfg80211's but we enable passive scanning */
|
||||
regd = ath9k_default_world_regdomain();
|
||||
}
|
||||
wiphy_apply_custom_regulatory(hw->wiphy, regd);
|
||||
ath9k_reg_apply_radar_flags(hw->wiphy);
|
||||
ath9k_reg_apply_world_flags(hw->wiphy, NL80211_REGDOM_SET_BY_DRIVER);
|
||||
|
||||
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);
|
||||
|
||||
error = ieee80211_register_hw(hw);
|
||||
|
||||
if (!ath9k_is_world_regd(sc->sc_ah)) {
|
||||
error = regulatory_hint(hw->wiphy,
|
||||
sc->sc_ah->regulatory.alpha2);
|
||||
if (!ath_is_world_regd(reg)) {
|
||||
error = regulatory_hint(hw->wiphy, reg->alpha2);
|
||||
if (error)
|
||||
goto error_attach;
|
||||
}
|
||||
|
@ -1792,7 +1773,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
dd->dd_name = name;
|
||||
dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
|
||||
|
||||
/*
|
||||
|
@ -1822,7 +1802,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
}
|
||||
ds = dd->dd_desc;
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
|
||||
dd->dd_name, ds, (u32) dd->dd_desc_len,
|
||||
name, ds, (u32) dd->dd_desc_len,
|
||||
ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
|
||||
|
||||
/* allocate buffers */
|
||||
|
@ -2043,8 +2023,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
|||
* here except setup the interrupt mask.
|
||||
*/
|
||||
if (ath_startrecv(sc) != 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Unable to start recv logic\n");
|
||||
DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
|
||||
r = -EIO;
|
||||
goto mutex_unlock;
|
||||
}
|
||||
|
@ -2257,25 +2236,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||
sc->imask |= ATH9K_INT_TSFOOR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some hardware processes the TIM IE and fires an
|
||||
* interrupt when the TIM bit is set. For hardware
|
||||
* that does, if not overridden by configuration,
|
||||
* enable the TIM interrupt when operating as station.
|
||||
*/
|
||||
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
|
||||
(conf->type == NL80211_IFTYPE_STATION) &&
|
||||
!sc->config.swBeaconProcess)
|
||||
sc->imask |= ATH9K_INT_TIM;
|
||||
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||
|
||||
if (conf->type == NL80211_IFTYPE_AP) {
|
||||
/* TODO: is this a suitable place to start ANI for AP mode? */
|
||||
/* Start ANI */
|
||||
mod_timer(&sc->ani.timer,
|
||||
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
||||
}
|
||||
if (conf->type == NL80211_IFTYPE_AP)
|
||||
ath_start_ani(sc);
|
||||
|
||||
out:
|
||||
mutex_unlock(&sc->mutex);
|
||||
|
@ -2326,26 +2290,33 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_PS) {
|
||||
if (conf->flags & IEEE80211_CONF_PS) {
|
||||
if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
|
||||
sc->imask |= ATH9K_INT_TIM_TIMER;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah,
|
||||
sc->imask);
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
|
||||
sc->imask |= ATH9K_INT_TIM_TIMER;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah,
|
||||
sc->imask);
|
||||
}
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 1);
|
||||
}
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 1);
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
|
||||
} else {
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 0);
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
|
||||
if (sc->imask & ATH9K_INT_TIM_TIMER) {
|
||||
sc->imask &= ~ATH9K_INT_TIM_TIMER;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah,
|
||||
sc->imask);
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 0);
|
||||
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
|
||||
if (sc->imask & ATH9K_INT_TIM_TIMER) {
|
||||
sc->imask &= ~ATH9K_INT_TIM_TIMER;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah,
|
||||
sc->imask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2562,6 +2533,8 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
|||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
|
||||
|
||||
qi.tqi_aifs = params->aifs;
|
||||
qi.tqi_cwmin = params->cw_min;
|
||||
qi.tqi_cwmax = params->cw_max;
|
||||
|
@ -2598,7 +2571,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&sc->mutex);
|
||||
ath9k_ps_wakeup(sc);
|
||||
DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n");
|
||||
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
|
@ -2771,6 +2744,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
|
|||
mutex_lock(&sc->mutex);
|
||||
aphy->state = ATH_WIPHY_ACTIVE;
|
||||
sc->sc_flags &= ~SC_OP_SCANNING;
|
||||
sc->sc_flags |= SC_OP_FULL_RESET;
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
channelSel = ((freq - 704) * 2 - 3040) / 10;
|
||||
bModeSynth = 1;
|
||||
} else {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Invalid channel %u MHz\n", freq);
|
||||
return false;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
|
||||
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
|
||||
} else {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Invalid channel %u MHz\n", freq);
|
||||
return false;
|
||||
}
|
|
@ -556,9 +556,6 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
|
|||
int r; \
|
||||
for (r = 0; r < ((iniarray)->ia_rows); r++) { \
|
||||
REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, \
|
||||
"RF 0x%x V 0x%x\n", \
|
||||
INI_RA((iniarray), r, 0), (regData)[r]); \
|
||||
DO_DELAY(regWr); \
|
||||
} \
|
||||
} while (0)
|
|
@ -524,7 +524,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
|
|||
u32 valid;
|
||||
|
||||
for (i = 0; i < rate_table->rate_cnt; i++) {
|
||||
valid = (ath_rc_priv->single_stream ?
|
||||
valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
|
||||
rate_table->info[i].valid_single_stream :
|
||||
rate_table->info[i].valid);
|
||||
if (valid == 1) {
|
||||
|
@ -557,9 +557,9 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
|
|||
for (i = 0; i < rateset->rs_nrates; i++) {
|
||||
for (j = 0; j < rate_table->rate_cnt; j++) {
|
||||
u32 phy = rate_table->info[j].phy;
|
||||
u32 valid = (ath_rc_priv->single_stream ?
|
||||
rate_table->info[j].valid_single_stream :
|
||||
rate_table->info[j].valid);
|
||||
u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
|
||||
rate_table->info[j].valid_single_stream :
|
||||
rate_table->info[j].valid);
|
||||
u8 rate = rateset->rs_rates[i];
|
||||
u8 dot11rate = rate_table->info[j].dot11rate;
|
||||
|
||||
|
@ -603,7 +603,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
|
|||
for (i = 0; i < rateset->rs_nrates; i++) {
|
||||
for (j = 0; j < rate_table->rate_cnt; j++) {
|
||||
u32 phy = rate_table->info[j].phy;
|
||||
u32 valid = (ath_rc_priv->single_stream ?
|
||||
u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
|
||||
rate_table->info[j].valid_single_stream :
|
||||
rate_table->info[j].valid);
|
||||
u8 rate = rateset->rs_rates[i];
|
||||
|
@ -740,9 +740,10 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
|
|||
if (rate > (ath_rc_priv->rate_table_size - 1))
|
||||
rate = ath_rc_priv->rate_table_size - 1;
|
||||
|
||||
ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
|
||||
ASSERT((rate_table->info[rate].valid &&
|
||||
(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
|
||||
(rate_table->info[rate].valid_single_stream &&
|
||||
ath_rc_priv->single_stream));
|
||||
!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
@ -811,7 +812,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
|
|||
u16 min_rate)
|
||||
{
|
||||
u32 j;
|
||||
u8 nextindex;
|
||||
u8 nextindex = 0;
|
||||
|
||||
if (min_rate) {
|
||||
for (j = RATE_TABLE_SIZE; j > 0; j--) {
|
||||
|
@ -1320,7 +1321,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
|||
* 40 to 20 => don't update */
|
||||
|
||||
if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
|
||||
(ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG))
|
||||
!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
|
||||
return;
|
||||
|
||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||
|
@ -1345,9 +1346,8 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
|||
|
||||
/* If HT40 and we have switched mode from 40 to 20 => don't update */
|
||||
if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
|
||||
(ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) {
|
||||
!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
|
||||
return;
|
||||
}
|
||||
|
||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
|
||||
|
@ -1420,10 +1420,6 @@ static void ath_rc_init(struct ath_softc *sc,
|
|||
ath_rc_priv->valid_phy_rateidx[i][j] = 0;
|
||||
ath_rc_priv->valid_phy_ratecnt[i] = 0;
|
||||
}
|
||||
ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG;
|
||||
|
||||
/* Set stream capability */
|
||||
ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1;
|
||||
|
||||
if (!rateset->rs_nrates) {
|
||||
/* No working rate, just initialize valid rates */
|
|
@ -24,7 +24,6 @@ struct ath_softc;
|
|||
#define ATH_RATE_MAX 30
|
||||
#define RATE_TABLE_SIZE 64
|
||||
#define MAX_TX_RATE_PHY 48
|
||||
#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
|
||||
|
||||
/* VALID_ALL - valid for 20/40/Legacy,
|
||||
* VALID - Legacy only,
|
||||
|
@ -158,7 +157,6 @@ struct ath_rateset {
|
|||
* @probe_interval: interval for ratectrl to probe for other rates
|
||||
* @prev_data_rix: rate idx of last data frame
|
||||
* @ht_cap: HT capabilities
|
||||
* @single_stream: When TRUE, only single TX stream possible
|
||||
* @neg_rates: Negotatied rates
|
||||
* @neg_ht_rates: Negotiated HT rates
|
||||
*/
|
||||
|
@ -176,10 +174,8 @@ struct ath_rate_priv {
|
|||
u8 max_valid_rate;
|
||||
u8 valid_rate_index[RATE_TABLE_SIZE];
|
||||
u8 ht_cap;
|
||||
u8 single_stream;
|
||||
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
|
||||
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
|
||||
u8 rc_phy_mode;
|
||||
u8 rate_max_phy;
|
||||
u32 rssi_time;
|
||||
u32 rssi_down_time;
|
|
@ -283,54 +283,51 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
|
|||
struct ath_buf *bf;
|
||||
int error = 0;
|
||||
|
||||
do {
|
||||
spin_lock_init(&sc->rx.rxflushlock);
|
||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
||||
spin_lock_init(&sc->rx.rxbuflock);
|
||||
spin_lock_init(&sc->rx.rxflushlock);
|
||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
||||
spin_lock_init(&sc->rx.rxbuflock);
|
||||
|
||||
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
|
||||
min(sc->cachelsz,
|
||||
(u16)64));
|
||||
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
|
||||
min(sc->cachelsz, (u16)64));
|
||||
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
|
||||
sc->cachelsz, sc->rx.bufsize);
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
|
||||
sc->cachelsz, sc->rx.bufsize);
|
||||
|
||||
/* Initialize rx descriptors */
|
||||
/* Initialize rx descriptors */
|
||||
|
||||
error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
|
||||
"rx", nbufs, 1);
|
||||
if (error != 0) {
|
||||
error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
|
||||
"rx", nbufs, 1);
|
||||
if (error != 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"failed to allocate rx descriptors: %d\n", error);
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
|
||||
skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
|
||||
if (skb == NULL) {
|
||||
error = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
bf->bf_mpdu = skb;
|
||||
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
|
||||
sc->rx.bufsize,
|
||||
DMA_FROM_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sc->dev,
|
||||
bf->bf_buf_addr))) {
|
||||
dev_kfree_skb_any(skb);
|
||||
bf->bf_mpdu = NULL;
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"failed to allocate rx descriptors: %d\n", error);
|
||||
break;
|
||||
"dma_mapping_error() on RX init\n");
|
||||
error = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
bf->bf_dmacontext = bf->bf_buf_addr;
|
||||
}
|
||||
sc->rx.rxlink = NULL;
|
||||
|
||||
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
|
||||
skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
|
||||
if (skb == NULL) {
|
||||
error = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
bf->bf_mpdu = skb;
|
||||
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
|
||||
sc->rx.bufsize,
|
||||
DMA_FROM_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sc->dev,
|
||||
bf->bf_buf_addr))) {
|
||||
dev_kfree_skb_any(skb);
|
||||
bf->bf_mpdu = NULL;
|
||||
DPRINTF(sc, ATH_DBG_CONFIG,
|
||||
"dma_mapping_error() on RX init\n");
|
||||
error = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
bf->bf_dmacontext = bf->bf_buf_addr;
|
||||
}
|
||||
sc->rx.rxlink = NULL;
|
||||
|
||||
} while (0);
|
||||
|
||||
err:
|
||||
if (error)
|
||||
ath_rx_cleanup(sc);
|
||||
|
||||
|
@ -345,10 +342,8 @@ void ath_rx_cleanup(struct ath_softc *sc)
|
|||
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
|
||||
skb = bf->bf_mpdu;
|
||||
if (skb) {
|
||||
dma_unmap_single(sc->dev,
|
||||
bf->bf_buf_addr,
|
||||
sc->rx.bufsize,
|
||||
DMA_FROM_DEVICE);
|
||||
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
||||
sc->rx.bufsize, DMA_FROM_DEVICE);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
@ -675,7 +670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
|||
bf->bf_buf_addr))) {
|
||||
dev_kfree_skb_any(requeue_skb);
|
||||
bf->bf_mpdu = NULL;
|
||||
DPRINTF(sc, ATH_DBG_CONFIG,
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"dma_mapping_error() on RX\n");
|
||||
break;
|
||||
}
|
|
@ -283,7 +283,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
|
||||
bool rc_update = true;
|
||||
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
skb = bf->bf_mpdu;
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -380,8 +380,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
|
||||
} else {
|
||||
/* retry the un-acked ones */
|
||||
if (bf->bf_next == NULL &&
|
||||
bf_last->bf_status & ATH_BUFSTATUS_STALE) {
|
||||
if (bf->bf_next == NULL && bf_last->bf_stale) {
|
||||
struct ath_buf *tbf;
|
||||
|
||||
tbf = ath_clone_txbuf(sc, bf_last);
|
||||
|
@ -444,7 +443,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
|||
u16 aggr_limit, legacy = 0, maxampdu;
|
||||
int i;
|
||||
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
skb = bf->bf_mpdu;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
rates = tx_info->control.rates;
|
||||
tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
|
||||
|
@ -1004,7 +1003,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
|
|||
|
||||
bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
|
||||
|
||||
if (bf->bf_status & ATH_BUFSTATUS_STALE) {
|
||||
if (bf->bf_stale) {
|
||||
list_del(&bf->list);
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
|
||||
|
@ -1452,7 +1451,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
|
|||
|
||||
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
|
||||
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
skb = bf->bf_mpdu;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
rates = tx_info->control.rates;
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
@ -1573,8 +1572,9 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
|||
skb->len, DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
|
||||
bf->bf_mpdu = NULL;
|
||||
DPRINTF(sc, ATH_DBG_CONFIG,
|
||||
"dma_mapping_error() on TX\n");
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -1586,7 +1586,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
|||
static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct ath_tx_control *txctl)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ath_node *an = NULL;
|
||||
|
@ -1860,7 +1860,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
|
|||
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
|
||||
int nbad, int txok, bool update_rc)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
|
@ -1941,7 +1941,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
* it with the STALE flag.
|
||||
*/
|
||||
bf_held = NULL;
|
||||
if (bf->bf_status & ATH_BUFSTATUS_STALE) {
|
||||
if (bf->bf_stale) {
|
||||
bf_held = bf;
|
||||
if (list_is_last(&bf_held->list, &txq->axq_q)) {
|
||||
txq->axq_link = NULL;
|
||||
|
@ -1982,7 +1982,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
* however leave the last descriptor back as the holding
|
||||
* descriptor for hw.
|
||||
*/
|
||||
lastbf->bf_status |= ATH_BUFSTATUS_STALE;
|
||||
lastbf->bf_stale = true;
|
||||
INIT_LIST_HEAD(&bf_head);
|
||||
if (!list_is_singular(&lastbf->list))
|
||||
list_cut_position(&bf_head,
|
||||
|
@ -2048,44 +2048,38 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
|
|||
{
|
||||
int error = 0;
|
||||
|
||||
do {
|
||||
spin_lock_init(&sc->tx.txbuflock);
|
||||
spin_lock_init(&sc->tx.txbuflock);
|
||||
|
||||
error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
|
||||
"tx", nbufs, 1);
|
||||
if (error != 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Failed to allocate tx descriptors: %d\n",
|
||||
error);
|
||||
break;
|
||||
}
|
||||
error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
|
||||
"tx", nbufs, 1);
|
||||
if (error != 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Failed to allocate tx descriptors: %d\n", error);
|
||||
goto err;
|
||||
}
|
||||
|
||||
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
|
||||
"beacon", ATH_BCBUF, 1);
|
||||
if (error != 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Failed to allocate beacon descriptors: %d\n",
|
||||
error);
|
||||
break;
|
||||
}
|
||||
|
||||
} while (0);
|
||||
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
|
||||
"beacon", ATH_BCBUF, 1);
|
||||
if (error != 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Failed to allocate beacon descriptors: %d\n", error);
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
if (error != 0)
|
||||
ath_tx_cleanup(sc);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int ath_tx_cleanup(struct ath_softc *sc)
|
||||
void ath_tx_cleanup(struct ath_softc *sc)
|
||||
{
|
||||
if (sc->beacon.bdma.dd_desc_len != 0)
|
||||
ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
|
||||
|
||||
if (sc->tx.txdma.dd_desc_len != 0)
|
||||
ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 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 <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
MODULE_AUTHOR("Atheros Communications");
|
||||
MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards.");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "ath9k.h"
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "regd.h"
|
||||
#include "regd_common.h"
|
||||
|
||||
/*
|
||||
|
@ -55,7 +57,7 @@
|
|||
|
||||
/* Can be used for:
|
||||
* 0x60, 0x61, 0x62 */
|
||||
static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = {
|
||||
static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
|
||||
.n_reg_rules = 5,
|
||||
.alpha2 = "99",
|
||||
.reg_rules = {
|
||||
|
@ -65,7 +67,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = {
|
|||
};
|
||||
|
||||
/* Can be used by 0x63 and 0x65 */
|
||||
static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = {
|
||||
static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
|
||||
.n_reg_rules = 4,
|
||||
.alpha2 = "99",
|
||||
.reg_rules = {
|
||||
|
@ -76,7 +78,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = {
|
|||
};
|
||||
|
||||
/* Can be used by 0x64 only */
|
||||
static const struct ieee80211_regdomain ath9k_world_regdom_64 = {
|
||||
static const struct ieee80211_regdomain ath_world_regdom_64 = {
|
||||
.n_reg_rules = 3,
|
||||
.alpha2 = "99",
|
||||
.reg_rules = {
|
||||
|
@ -86,7 +88,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_64 = {
|
|||
};
|
||||
|
||||
/* Can be used by 0x66 and 0x69 */
|
||||
static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = {
|
||||
static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
|
||||
.n_reg_rules = 3,
|
||||
.alpha2 = "99",
|
||||
.reg_rules = {
|
||||
|
@ -96,7 +98,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = {
|
|||
};
|
||||
|
||||
/* Can be used by 0x67, 0x6A and 0x68 */
|
||||
static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
|
||||
static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = {
|
||||
.n_reg_rules = 4,
|
||||
.alpha2 = "99",
|
||||
.reg_rules = {
|
||||
|
@ -112,49 +114,51 @@ static inline bool is_wwr_sku(u16 regd)
|
|||
(regd == WORLD);
|
||||
}
|
||||
|
||||
static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
|
||||
static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
|
||||
{
|
||||
return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
|
||||
return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
|
||||
}
|
||||
|
||||
bool ath9k_is_world_regd(struct ath_hw *ah)
|
||||
bool ath_is_world_regd(struct ath_regulatory *reg)
|
||||
{
|
||||
return is_wwr_sku(ath9k_regd_get_eepromRD(ah));
|
||||
return is_wwr_sku(ath_regd_get_eepromRD(reg));
|
||||
}
|
||||
EXPORT_SYMBOL(ath_is_world_regd);
|
||||
|
||||
const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
|
||||
static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
|
||||
{
|
||||
/* this is the most restrictive */
|
||||
return &ath9k_world_regdom_64;
|
||||
return &ath_world_regdom_64;
|
||||
}
|
||||
|
||||
const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah)
|
||||
static const struct
|
||||
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
|
||||
{
|
||||
switch (ah->regulatory.regpair->regDmnEnum) {
|
||||
switch (reg->regpair->regDmnEnum) {
|
||||
case 0x60:
|
||||
case 0x61:
|
||||
case 0x62:
|
||||
return &ath9k_world_regdom_60_61_62;
|
||||
return &ath_world_regdom_60_61_62;
|
||||
case 0x63:
|
||||
case 0x65:
|
||||
return &ath9k_world_regdom_63_65;
|
||||
return &ath_world_regdom_63_65;
|
||||
case 0x64:
|
||||
return &ath9k_world_regdom_64;
|
||||
return &ath_world_regdom_64;
|
||||
case 0x66:
|
||||
case 0x69:
|
||||
return &ath9k_world_regdom_66_69;
|
||||
return &ath_world_regdom_66_69;
|
||||
case 0x67:
|
||||
case 0x68:
|
||||
case 0x6A:
|
||||
return &ath9k_world_regdom_67_68_6A;
|
||||
return &ath_world_regdom_67_68_6A;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return ath9k_default_world_regdomain();
|
||||
return ath_default_world_regdomain();
|
||||
}
|
||||
}
|
||||
|
||||
/* Frequency is one where radar detection is required */
|
||||
static bool ath9k_is_radar_freq(u16 center_freq)
|
||||
static bool ath_is_radar_freq(u16 center_freq)
|
||||
{
|
||||
return (center_freq >= 5260 && center_freq <= 5700);
|
||||
}
|
||||
|
@ -168,9 +172,9 @@ static bool ath9k_is_radar_freq(u16 center_freq)
|
|||
* received a beacon on a channel we can enable active scan and
|
||||
* adhoc (or beaconing).
|
||||
*/
|
||||
static void ath9k_reg_apply_beaconing_flags(
|
||||
struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
static void
|
||||
ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
@ -191,7 +195,7 @@ static void ath9k_reg_apply_beaconing_flags(
|
|||
|
||||
ch = &sband->channels[i];
|
||||
|
||||
if (ath9k_is_radar_freq(ch->center_freq) ||
|
||||
if (ath_is_radar_freq(ch->center_freq) ||
|
||||
(ch->flags & IEEE80211_CHAN_RADAR))
|
||||
continue;
|
||||
|
||||
|
@ -227,9 +231,9 @@ static void ath9k_reg_apply_beaconing_flags(
|
|||
}
|
||||
|
||||
/* Allows active scan scan on Ch 12 and 13 */
|
||||
static void ath9k_reg_apply_active_scan_flags(
|
||||
struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
static void
|
||||
ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *ch;
|
||||
|
@ -278,7 +282,7 @@ static void ath9k_reg_apply_active_scan_flags(
|
|||
}
|
||||
|
||||
/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
|
||||
void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
|
||||
static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *ch;
|
||||
|
@ -291,7 +295,7 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
|
|||
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
ch = &sband->channels[i];
|
||||
if (!ath9k_is_radar_freq(ch->center_freq))
|
||||
if (!ath_is_radar_freq(ch->center_freq))
|
||||
continue;
|
||||
/* We always enable radar detection/DFS on this
|
||||
* frequency range. Additionally we also apply on
|
||||
|
@ -310,37 +314,31 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
|
|||
}
|
||||
}
|
||||
|
||||
void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
static void ath_reg_apply_world_flags(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator,
|
||||
struct ath_regulatory *reg)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
switch (ah->regulatory.regpair->regDmnEnum) {
|
||||
switch (reg->regpair->regDmnEnum) {
|
||||
case 0x60:
|
||||
case 0x63:
|
||||
case 0x66:
|
||||
case 0x67:
|
||||
ath9k_reg_apply_beaconing_flags(wiphy, initiator);
|
||||
ath_reg_apply_beaconing_flags(wiphy, initiator);
|
||||
break;
|
||||
case 0x68:
|
||||
ath9k_reg_apply_beaconing_flags(wiphy, initiator);
|
||||
ath9k_reg_apply_active_scan_flags(wiphy, initiator);
|
||||
ath_reg_apply_beaconing_flags(wiphy, initiator);
|
||||
ath_reg_apply_active_scan_flags(wiphy, initiator);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
|
||||
int ath_reg_notifier_apply(struct wiphy *wiphy,
|
||||
struct regulatory_request *request,
|
||||
struct ath_regulatory *reg)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
||||
/* We always apply this */
|
||||
ath9k_reg_apply_radar_flags(wiphy);
|
||||
ath_reg_apply_radar_flags(wiphy);
|
||||
|
||||
switch (request->initiator) {
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
|
@ -348,17 +346,19 @@ int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
|
|||
case NL80211_REGDOM_SET_BY_USER:
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
|
||||
if (ath9k_is_world_regd(sc->sc_ah))
|
||||
ath9k_reg_apply_world_flags(wiphy, request->initiator);
|
||||
if (ath_is_world_regd(reg))
|
||||
ath_reg_apply_world_flags(wiphy, request->initiator,
|
||||
reg);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_reg_notifier_apply);
|
||||
|
||||
bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
|
||||
static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
|
||||
{
|
||||
u16 rd = ath9k_regd_get_eepromRD(ah);
|
||||
u16 rd = ath_regd_get_eepromRD(reg);
|
||||
int i;
|
||||
|
||||
if (rd & COUNTRY_ERD_FLAG) {
|
||||
|
@ -373,14 +373,14 @@ bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
|
|||
if (regDomainPairs[i].regDmnEnum == rd)
|
||||
return true;
|
||||
}
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
|
||||
"invalid regulatory domain/country code 0x%x\n", rd);
|
||||
printk(KERN_DEBUG
|
||||
"ath: invalid regulatory domain/country code 0x%x\n", rd);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* EEPROM country code to regpair mapping */
|
||||
static struct country_code_to_enum_rd*
|
||||
ath9k_regd_find_country(u16 countryCode)
|
||||
ath_regd_find_country(u16 countryCode)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -393,7 +393,7 @@ ath9k_regd_find_country(u16 countryCode)
|
|||
|
||||
/* EEPROM rd code to regpair mapping */
|
||||
static struct country_code_to_enum_rd*
|
||||
ath9k_regd_find_country_by_rd(int regdmn)
|
||||
ath_regd_find_country_by_rd(int regdmn)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -405,13 +405,13 @@ ath9k_regd_find_country_by_rd(int regdmn)
|
|||
}
|
||||
|
||||
/* Returns the map of the EEPROM set RD to a country code */
|
||||
static u16 ath9k_regd_get_default_country(u16 rd)
|
||||
static u16 ath_regd_get_default_country(u16 rd)
|
||||
{
|
||||
if (rd & COUNTRY_ERD_FLAG) {
|
||||
struct country_code_to_enum_rd *country = NULL;
|
||||
u16 cc = rd & ~COUNTRY_ERD_FLAG;
|
||||
|
||||
country = ath9k_regd_find_country(cc);
|
||||
country = ath_regd_find_country(cc);
|
||||
if (country != NULL)
|
||||
return cc;
|
||||
}
|
||||
|
@ -420,7 +420,7 @@ static u16 ath9k_regd_get_default_country(u16 rd)
|
|||
}
|
||||
|
||||
static struct reg_dmn_pair_mapping*
|
||||
ath9k_get_regpair(int regdmn)
|
||||
ath_get_regpair(int regdmn)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -433,87 +433,120 @@ ath9k_get_regpair(int regdmn)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int ath9k_regd_init(struct ath_hw *ah)
|
||||
static int
|
||||
ath_regd_init_wiphy(struct ath_regulatory *reg,
|
||||
struct wiphy *wiphy,
|
||||
int (*reg_notifier)(struct wiphy *wiphy,
|
||||
struct regulatory_request *request))
|
||||
{
|
||||
const struct ieee80211_regdomain *regd;
|
||||
|
||||
wiphy->reg_notifier = reg_notifier;
|
||||
wiphy->strict_regulatory = true;
|
||||
|
||||
if (ath_is_world_regd(reg)) {
|
||||
/*
|
||||
* Anything applied here (prior to wiphy registration) gets
|
||||
* saved on the wiphy orig_* parameters
|
||||
*/
|
||||
regd = ath_world_regdomain(reg);
|
||||
wiphy->custom_regulatory = true;
|
||||
wiphy->strict_regulatory = false;
|
||||
} else {
|
||||
/*
|
||||
* This gets applied in the case of the absense of CRDA,
|
||||
* it's our own custom world regulatory domain, similar to
|
||||
* cfg80211's but we enable passive scanning.
|
||||
*/
|
||||
regd = ath_default_world_regdomain();
|
||||
}
|
||||
wiphy_apply_custom_regulatory(wiphy, regd);
|
||||
ath_reg_apply_radar_flags(wiphy);
|
||||
ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ath_regd_init(struct ath_regulatory *reg,
|
||||
struct wiphy *wiphy,
|
||||
int (*reg_notifier)(struct wiphy *wiphy,
|
||||
struct regulatory_request *request))
|
||||
{
|
||||
struct country_code_to_enum_rd *country = NULL;
|
||||
u16 regdmn;
|
||||
|
||||
if (!ath9k_regd_is_eeprom_valid(ah)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
|
||||
"Invalid EEPROM contents\n");
|
||||
if (!ath_regd_is_eeprom_valid(reg)) {
|
||||
printk(KERN_ERR "ath: Invalid EEPROM contents\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regdmn = ath9k_regd_get_eepromRD(ah);
|
||||
ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn);
|
||||
regdmn = ath_regd_get_eepromRD(reg);
|
||||
reg->country_code = ath_regd_get_default_country(regdmn);
|
||||
|
||||
if (ah->regulatory.country_code == CTRY_DEFAULT &&
|
||||
if (reg->country_code == CTRY_DEFAULT &&
|
||||
regdmn == CTRY_DEFAULT)
|
||||
ah->regulatory.country_code = CTRY_UNITED_STATES;
|
||||
reg->country_code = CTRY_UNITED_STATES;
|
||||
|
||||
if (ah->regulatory.country_code == CTRY_DEFAULT) {
|
||||
if (reg->country_code == CTRY_DEFAULT) {
|
||||
country = NULL;
|
||||
} else {
|
||||
country = ath9k_regd_find_country(ah->regulatory.country_code);
|
||||
country = ath_regd_find_country(reg->country_code);
|
||||
if (country == NULL) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
|
||||
"Country is NULL!!!!, cc= %d\n",
|
||||
ah->regulatory.country_code);
|
||||
printk(KERN_DEBUG
|
||||
"ath: Country is NULL!!!!, cc= %d\n",
|
||||
reg->country_code);
|
||||
return -EINVAL;
|
||||
} else
|
||||
regdmn = country->regDmnEnum;
|
||||
}
|
||||
|
||||
ah->regulatory.regpair = ath9k_get_regpair(regdmn);
|
||||
reg->regpair = ath_get_regpair(regdmn);
|
||||
|
||||
if (!ah->regulatory.regpair) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
if (!reg->regpair) {
|
||||
printk(KERN_DEBUG "ath: "
|
||||
"No regulatory domain pair found, cannot continue\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!country)
|
||||
country = ath9k_regd_find_country_by_rd(regdmn);
|
||||
country = ath_regd_find_country_by_rd(regdmn);
|
||||
|
||||
if (country) {
|
||||
ah->regulatory.alpha2[0] = country->isoName[0];
|
||||
ah->regulatory.alpha2[1] = country->isoName[1];
|
||||
reg->alpha2[0] = country->isoName[0];
|
||||
reg->alpha2[1] = country->isoName[1];
|
||||
} else {
|
||||
ah->regulatory.alpha2[0] = '0';
|
||||
ah->regulatory.alpha2[1] = '0';
|
||||
reg->alpha2[0] = '0';
|
||||
reg->alpha2[1] = '0';
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
|
||||
"Country alpha2 being used: %c%c\n"
|
||||
"Regulatory.Regpair detected: 0x%0x\n",
|
||||
ah->regulatory.alpha2[0], ah->regulatory.alpha2[1],
|
||||
ah->regulatory.regpair->regDmnEnum);
|
||||
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
|
||||
reg->alpha2[0], reg->alpha2[1]);
|
||||
printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n",
|
||||
reg->regpair->regDmnEnum);
|
||||
|
||||
ath_regd_init_wiphy(reg, wiphy, reg_notifier);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_regd_init);
|
||||
|
||||
u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
u32 ctl = NO_CTL;
|
||||
|
||||
if (!ah->regulatory.regpair ||
|
||||
(ah->regulatory.country_code == CTRY_DEFAULT &&
|
||||
is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) {
|
||||
if (IS_CHAN_B(chan))
|
||||
ctl = SD_NO_CTL | CTL_11B;
|
||||
else if (IS_CHAN_G(chan))
|
||||
ctl = SD_NO_CTL | CTL_11G;
|
||||
else
|
||||
ctl = SD_NO_CTL | CTL_11A;
|
||||
return ctl;
|
||||
if (!reg->regpair ||
|
||||
(reg->country_code == CTRY_DEFAULT &&
|
||||
is_wwr_sku(ath_regd_get_eepromRD(reg)))) {
|
||||
return SD_NO_CTL;
|
||||
}
|
||||
|
||||
if (IS_CHAN_B(chan))
|
||||
ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
|
||||
else if (IS_CHAN_G(chan))
|
||||
ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G;
|
||||
else
|
||||
ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
return reg->regpair->reg_2ghz_ctl;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
return reg->regpair->reg_5ghz_ctl;
|
||||
default:
|
||||
return NO_CTL;
|
||||
}
|
||||
|
||||
return ctl;
|
||||
return NO_CTL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_regd_get_band_ctl);
|
|
@ -17,6 +17,25 @@
|
|||
#ifndef REGD_H
|
||||
#define REGD_H
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#define NO_CTL 0xff
|
||||
#define SD_NO_CTL 0xE0
|
||||
#define NO_CTL 0xff
|
||||
#define CTL_MODE_M 7
|
||||
#define CTL_11A 0
|
||||
#define CTL_11B 1
|
||||
#define CTL_11G 2
|
||||
#define CTL_2GHT20 5
|
||||
#define CTL_5GHT20 6
|
||||
#define CTL_2GHT40 7
|
||||
#define CTL_5GHT40 8
|
||||
|
||||
#define CTRY_DEBUG 0x1ff
|
||||
#define CTRY_DEFAULT 0
|
||||
|
||||
#define COUNTRY_ERD_FLAG 0x8000
|
||||
#define WORLDWIDE_ROAMING_FLAG 0x4000
|
||||
|
||||
|
@ -40,7 +59,7 @@ struct country_code_to_enum_rd {
|
|||
const char *isoName;
|
||||
};
|
||||
|
||||
struct ath9k_regulatory {
|
||||
struct ath_regulatory {
|
||||
char alpha2[2];
|
||||
u16 country_code;
|
||||
u16 max_power_level;
|
||||
|
@ -233,15 +252,14 @@ enum CountryCode {
|
|||
CTRY_BELGIUM2 = 5002
|
||||
};
|
||||
|
||||
bool ath9k_is_world_regd(struct ath_hw *ah);
|
||||
const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah);
|
||||
const struct ieee80211_regdomain *ath9k_default_world_regdomain(void);
|
||||
void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator);
|
||||
void ath9k_reg_apply_radar_flags(struct wiphy *wiphy);
|
||||
int ath9k_regd_init(struct ath_hw *ah);
|
||||
bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah);
|
||||
u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
|
||||
bool ath_is_world_regd(struct ath_regulatory *reg);
|
||||
int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
|
||||
int (*reg_notifier)(struct wiphy *wiphy,
|
||||
struct regulatory_request *request));
|
||||
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
|
||||
enum ieee80211_band band);
|
||||
int ath_reg_notifier_apply(struct wiphy *wiphy,
|
||||
struct regulatory_request *request,
|
||||
struct ath_regulatory *reg);
|
||||
|
||||
#endif
|
|
@ -3,7 +3,6 @@ config B43
|
|||
depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA
|
||||
select SSB
|
||||
select FW_LOADER
|
||||
select HW_RANDOM
|
||||
---help---
|
||||
b43 is a driver for the Broadcom 43xx series wireless devices.
|
||||
|
||||
|
@ -106,6 +105,13 @@ config B43_RFKILL
|
|||
depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
|
||||
default y
|
||||
|
||||
# This config option automatically enables b43 HW-RNG support,
|
||||
# if the HW-RNG core is enabled.
|
||||
config B43_HWRNG
|
||||
bool
|
||||
depends on B43 && (HW_RANDOM = y || HW_RANDOM = B43)
|
||||
default y
|
||||
|
||||
config B43_DEBUG
|
||||
bool "Broadcom 43xx debugging"
|
||||
depends on B43
|
||||
|
|
|
@ -625,9 +625,11 @@ struct b43_wl {
|
|||
/* Stats about the wireless interface */
|
||||
struct ieee80211_low_level_stats ieee_stats;
|
||||
|
||||
#ifdef CONFIG_B43_HWRNG
|
||||
struct hwrng rng;
|
||||
u8 rng_initialized;
|
||||
bool rng_initialized;
|
||||
char rng_name[30 + 1];
|
||||
#endif /* CONFIG_B43_HWRNG */
|
||||
|
||||
/* The RF-kill button */
|
||||
struct b43_rfkill rfkill;
|
||||
|
@ -776,8 +778,8 @@ struct b43_wldev {
|
|||
/* Reason code of the last interrupt. */
|
||||
u32 irq_reason;
|
||||
u32 dma_reason[6];
|
||||
/* saved irq enable/disable state bitfield. */
|
||||
u32 irq_savedstate;
|
||||
/* The currently active generic-interrupt mask. */
|
||||
u32 irq_mask;
|
||||
/* Link Quality calculation context. */
|
||||
struct b43_noise_calculation noisecalc;
|
||||
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
|
||||
|
|
|
@ -673,32 +673,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev)
|
|||
b43_set_slot_time(dev, 20);
|
||||
}
|
||||
|
||||
/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
|
||||
* Returns the _previously_ enabled IRQ mask.
|
||||
*/
|
||||
static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
|
||||
{
|
||||
u32 old_mask;
|
||||
|
||||
old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
|
||||
|
||||
return old_mask;
|
||||
}
|
||||
|
||||
/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
|
||||
* Returns the _previously_ enabled IRQ mask.
|
||||
*/
|
||||
static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
|
||||
{
|
||||
u32 old_mask;
|
||||
|
||||
old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
|
||||
|
||||
return old_mask;
|
||||
}
|
||||
|
||||
/* Synchronize IRQ top- and bottom-half.
|
||||
* IRQs must be masked before calling this.
|
||||
* This must not be called with the irq_lock held.
|
||||
|
@ -1593,7 +1567,7 @@ static void handle_irq_beacon(struct b43_wldev *dev)
|
|||
/* This is the bottom half of the asynchronous beacon update. */
|
||||
|
||||
/* Ignore interrupt in the future. */
|
||||
dev->irq_savedstate &= ~B43_IRQ_BEACON;
|
||||
dev->irq_mask &= ~B43_IRQ_BEACON;
|
||||
|
||||
cmd = b43_read32(dev, B43_MMIO_MACCMD);
|
||||
beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
|
||||
|
@ -1602,7 +1576,7 @@ static void handle_irq_beacon(struct b43_wldev *dev)
|
|||
/* Schedule interrupt manually, if busy. */
|
||||
if (beacon0_valid && beacon1_valid) {
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
|
||||
dev->irq_savedstate |= B43_IRQ_BEACON;
|
||||
dev->irq_mask |= B43_IRQ_BEACON;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1641,11 +1615,9 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
|
|||
if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
|
||||
spin_lock_irq(&wl->irq_lock);
|
||||
/* update beacon right away or defer to irq */
|
||||
dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
|
||||
handle_irq_beacon(dev);
|
||||
/* The handler might have updated the IRQ mask. */
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK,
|
||||
dev->irq_savedstate);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
|
||||
mmiowb();
|
||||
spin_unlock_irq(&wl->irq_lock);
|
||||
}
|
||||
|
@ -1879,7 +1851,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
|
|||
if (reason & B43_IRQ_TX_OK)
|
||||
handle_irq_transmit_status(dev);
|
||||
|
||||
b43_interrupt_enable(dev, dev->irq_savedstate);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
|
||||
mmiowb();
|
||||
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
|
||||
}
|
||||
|
@ -1893,7 +1865,9 @@ static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
|
|||
b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
|
||||
b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
|
||||
b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
|
||||
/* Unused ring
|
||||
b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
|
||||
*/
|
||||
}
|
||||
|
||||
/* Interrupt handler top-half */
|
||||
|
@ -1903,18 +1877,19 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
|
|||
struct b43_wldev *dev = dev_id;
|
||||
u32 reason;
|
||||
|
||||
if (!dev)
|
||||
return IRQ_NONE;
|
||||
B43_WARN_ON(!dev);
|
||||
|
||||
spin_lock(&dev->wl->irq_lock);
|
||||
|
||||
if (b43_status(dev) < B43_STAT_STARTED)
|
||||
if (unlikely(b43_status(dev) < B43_STAT_STARTED)) {
|
||||
/* This can only happen on shared IRQ lines. */
|
||||
goto out;
|
||||
}
|
||||
reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
|
||||
if (reason == 0xffffffff) /* shared IRQ */
|
||||
goto out;
|
||||
ret = IRQ_HANDLED;
|
||||
reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
|
||||
reason &= dev->irq_mask;
|
||||
if (!reason)
|
||||
goto out;
|
||||
|
||||
|
@ -1928,16 +1903,18 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
|
|||
& 0x0001DC00;
|
||||
dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
|
||||
& 0x0000DC00;
|
||||
/* Unused ring
|
||||
dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
|
||||
& 0x0000DC00;
|
||||
*/
|
||||
|
||||
b43_interrupt_ack(dev, reason);
|
||||
/* disable all IRQs. They are enabled again in the bottom half. */
|
||||
dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
|
||||
/* save the reason code and call our bottom half. */
|
||||
dev->irq_reason = reason;
|
||||
tasklet_schedule(&dev->isr_tasklet);
|
||||
out:
|
||||
out:
|
||||
mmiowb();
|
||||
spin_unlock(&dev->wl->irq_lock);
|
||||
|
||||
|
@ -2980,6 +2957,7 @@ static void b43_security_init(struct b43_wldev *dev)
|
|||
b43_clear_keys(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_B43_HWRNG
|
||||
static int b43_rng_read(struct hwrng *rng, u32 *data)
|
||||
{
|
||||
struct b43_wl *wl = (struct b43_wl *)rng->priv;
|
||||
|
@ -2995,17 +2973,21 @@ static int b43_rng_read(struct hwrng *rng, u32 *data)
|
|||
|
||||
return (sizeof(u16));
|
||||
}
|
||||
#endif /* CONFIG_B43_HWRNG */
|
||||
|
||||
static void b43_rng_exit(struct b43_wl *wl)
|
||||
{
|
||||
#ifdef CONFIG_B43_HWRNG
|
||||
if (wl->rng_initialized)
|
||||
hwrng_unregister(&wl->rng);
|
||||
#endif /* CONFIG_B43_HWRNG */
|
||||
}
|
||||
|
||||
static int b43_rng_init(struct b43_wl *wl)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
#ifdef CONFIG_B43_HWRNG
|
||||
snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
|
||||
"%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
|
||||
wl->rng.name = wl->rng_name;
|
||||
|
@ -3018,6 +3000,7 @@ static int b43_rng_init(struct b43_wl *wl)
|
|||
b43err(wl, "Failed to register the random "
|
||||
"number generator (%d)\n", err);
|
||||
}
|
||||
#endif /* CONFIG_B43_HWRNG */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -3793,7 +3776,7 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
|
|||
* setting the status to INITIALIZED, as the interrupt handler
|
||||
* won't care about IRQs then. */
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
|
||||
b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
b43_synchronize_irq(dev);
|
||||
|
@ -3834,7 +3817,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
|
|||
|
||||
/* Start data flow (TX/RX). */
|
||||
b43_mac_enable(dev);
|
||||
b43_interrupt_enable(dev, dev->irq_savedstate);
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
|
||||
|
||||
/* Start maintainance work */
|
||||
b43_periodic_tasks_setup(dev);
|
||||
|
@ -3997,9 +3980,9 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
|
|||
/* IRQ related flags */
|
||||
dev->irq_reason = 0;
|
||||
memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
|
||||
dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
|
||||
dev->irq_mask = B43_IRQ_MASKTEMPLATE;
|
||||
if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
|
||||
dev->irq_savedstate &= ~B43_IRQ_PHY_TXERR;
|
||||
dev->irq_mask &= ~B43_IRQ_PHY_TXERR;
|
||||
|
||||
dev->mac_suspended = 1;
|
||||
|
||||
|
|
|
@ -139,7 +139,6 @@ void b43_rfkill_init(struct b43_wldev *dev)
|
|||
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
rfk->rfkill->data = dev;
|
||||
rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
|
||||
rfk->rfkill->user_claim_unsupported = 1;
|
||||
|
||||
rfk->poll_dev = input_allocate_polled_device();
|
||||
if (!rfk->poll_dev) {
|
||||
|
|
|
@ -3,7 +3,6 @@ config B43LEGACY
|
|||
depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA
|
||||
select SSB
|
||||
select FW_LOADER
|
||||
select HW_RANDOM
|
||||
---help---
|
||||
b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
|
||||
BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the
|
||||
|
@ -51,6 +50,13 @@ config B43LEGACY_RFKILL
|
|||
depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY)
|
||||
default y
|
||||
|
||||
# This config option automatically enables b43 HW-RNG support,
|
||||
# if the HW-RNG core is enabled.
|
||||
config B43LEGACY_HWRNG
|
||||
bool
|
||||
depends on B43LEGACY && (HW_RANDOM = y || HW_RANDOM = B43LEGACY)
|
||||
default y
|
||||
|
||||
config B43LEGACY_DEBUG
|
||||
bool "Broadcom 43xx-legacy debugging"
|
||||
depends on B43LEGACY
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
#define B43legacy_MMIO_XMITSTAT_1 0x174
|
||||
#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
|
||||
#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
|
||||
|
||||
#define B43legacy_MMIO_TSF_CFP_REP 0x188
|
||||
#define B43legacy_MMIO_TSF_CFP_START 0x18C
|
||||
/* 32-bit DMA */
|
||||
#define B43legacy_MMIO_DMA32_BASE0 0x200
|
||||
#define B43legacy_MMIO_DMA32_BASE1 0x220
|
||||
|
@ -258,7 +259,6 @@
|
|||
|
||||
#define B43legacy_IRQ_ALL 0xFFFFFFFF
|
||||
#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \
|
||||
B43legacy_IRQ_BEACON | \
|
||||
B43legacy_IRQ_TBTT_INDI | \
|
||||
B43legacy_IRQ_ATIM_END | \
|
||||
B43legacy_IRQ_PMQ | \
|
||||
|
@ -596,9 +596,11 @@ struct b43legacy_wl {
|
|||
/* Stats about the wireless interface */
|
||||
struct ieee80211_low_level_stats ieee_stats;
|
||||
|
||||
#ifdef CONFIG_B43LEGACY_HWRNG
|
||||
struct hwrng rng;
|
||||
u8 rng_initialized;
|
||||
char rng_name[30 + 1];
|
||||
#endif
|
||||
|
||||
/* The RF-kill button */
|
||||
struct b43legacy_rfkill rfkill;
|
||||
|
@ -614,6 +616,8 @@ struct b43legacy_wl {
|
|||
struct sk_buff *current_beacon;
|
||||
bool beacon0_uploaded;
|
||||
bool beacon1_uploaded;
|
||||
bool beacon_templates_virgin; /* Never wrote the templates? */
|
||||
struct work_struct beacon_update_trigger;
|
||||
};
|
||||
|
||||
/* Pointers to the firmware data and meta information about it. */
|
||||
|
|
|
@ -955,23 +955,54 @@ static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
|
|||
size + sizeof(struct b43legacy_plcp_hdr6));
|
||||
}
|
||||
|
||||
/* Convert a b43legacy antenna number value to the PHY TX control value. */
|
||||
static u16 b43legacy_antenna_to_phyctl(int antenna)
|
||||
{
|
||||
switch (antenna) {
|
||||
case B43legacy_ANTENNA0:
|
||||
return B43legacy_TX4_PHY_ANT0;
|
||||
case B43legacy_ANTENNA1:
|
||||
return B43legacy_TX4_PHY_ANT1;
|
||||
}
|
||||
return B43legacy_TX4_PHY_ANTLAST;
|
||||
}
|
||||
|
||||
static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
|
||||
u16 ram_offset,
|
||||
u16 shm_size_offset, u8 rate)
|
||||
u16 shm_size_offset)
|
||||
{
|
||||
|
||||
unsigned int i, len, variable_len;
|
||||
const struct ieee80211_mgmt *bcn;
|
||||
const u8 *ie;
|
||||
bool tim_found = 0;
|
||||
unsigned int rate;
|
||||
u16 ctl;
|
||||
int antenna;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
|
||||
|
||||
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
|
||||
len = min((size_t)dev->wl->current_beacon->len,
|
||||
0x200 - sizeof(struct b43legacy_plcp_hdr6));
|
||||
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
|
||||
|
||||
b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset,
|
||||
shm_size_offset, rate);
|
||||
|
||||
/* Write the PHY TX control parameters. */
|
||||
antenna = B43legacy_ANTENNA_DEFAULT;
|
||||
antenna = b43legacy_antenna_to_phyctl(antenna);
|
||||
ctl = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
|
||||
B43legacy_SHM_SH_BEACPHYCTL);
|
||||
/* We can't send beacons with short preamble. Would get PHY errors. */
|
||||
ctl &= ~B43legacy_TX4_PHY_SHORTPRMBL;
|
||||
ctl &= ~B43legacy_TX4_PHY_ANT;
|
||||
ctl &= ~B43legacy_TX4_PHY_ENC;
|
||||
ctl |= antenna;
|
||||
ctl |= B43legacy_TX4_PHY_ENC_CCK;
|
||||
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
|
||||
B43legacy_SHM_SH_BEACPHYCTL, ctl);
|
||||
|
||||
/* Find the position of the TIM and the DTIM_period value
|
||||
* and write them to SHM. */
|
||||
ie = bcn->u.beacon.variable;
|
||||
|
@ -1013,7 +1044,8 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
|
|||
b43legacywarn(dev->wl, "Did not find a valid TIM IE in the "
|
||||
"beacon template packet. AP or IBSS operation "
|
||||
"may be broken.\n");
|
||||
}
|
||||
} else
|
||||
b43legacydbg(dev->wl, "Updated beacon template\n");
|
||||
}
|
||||
|
||||
static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
|
||||
|
@ -1025,7 +1057,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
|
|||
__le16 dur;
|
||||
|
||||
plcp.data = 0;
|
||||
b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate);
|
||||
b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
|
||||
dur = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
dev->wl->vif,
|
||||
size,
|
||||
|
@ -1129,10 +1161,104 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
|
|||
0x200 - sizeof(struct b43legacy_plcp_hdr6));
|
||||
b43legacy_write_template_common(dev, probe_resp_data,
|
||||
size, ram_offset,
|
||||
shm_size_offset, rate->bitrate);
|
||||
shm_size_offset, rate->hw_value);
|
||||
kfree(probe_resp_data);
|
||||
}
|
||||
|
||||
static void b43legacy_upload_beacon0(struct b43legacy_wldev *dev)
|
||||
{
|
||||
struct b43legacy_wl *wl = dev->wl;
|
||||
|
||||
if (wl->beacon0_uploaded)
|
||||
return;
|
||||
b43legacy_write_beacon_template(dev, 0x68, 0x18);
|
||||
/* FIXME: Probe resp upload doesn't really belong here,
|
||||
* but we don't use that feature anyway. */
|
||||
b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
|
||||
&__b43legacy_ratetable[3]);
|
||||
wl->beacon0_uploaded = 1;
|
||||
}
|
||||
|
||||
static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev)
|
||||
{
|
||||
struct b43legacy_wl *wl = dev->wl;
|
||||
|
||||
if (wl->beacon1_uploaded)
|
||||
return;
|
||||
b43legacy_write_beacon_template(dev, 0x468, 0x1A);
|
||||
wl->beacon1_uploaded = 1;
|
||||
}
|
||||
|
||||
static void handle_irq_beacon(struct b43legacy_wldev *dev)
|
||||
{
|
||||
struct b43legacy_wl *wl = dev->wl;
|
||||
u32 cmd, beacon0_valid, beacon1_valid;
|
||||
|
||||
if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
|
||||
return;
|
||||
|
||||
/* This is the bottom half of the asynchronous beacon update. */
|
||||
|
||||
/* Ignore interrupt in the future. */
|
||||
dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
|
||||
|
||||
cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
|
||||
beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID);
|
||||
beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID);
|
||||
|
||||
/* Schedule interrupt manually, if busy. */
|
||||
if (beacon0_valid && beacon1_valid) {
|
||||
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON);
|
||||
dev->irq_savedstate |= B43legacy_IRQ_BEACON;
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(wl->beacon_templates_virgin)) {
|
||||
/* We never uploaded a beacon before.
|
||||
* Upload both templates now, but only mark one valid. */
|
||||
wl->beacon_templates_virgin = 0;
|
||||
b43legacy_upload_beacon0(dev);
|
||||
b43legacy_upload_beacon1(dev);
|
||||
cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
|
||||
cmd |= B43legacy_MACCMD_BEACON0_VALID;
|
||||
b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
|
||||
} else {
|
||||
if (!beacon0_valid) {
|
||||
b43legacy_upload_beacon0(dev);
|
||||
cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
|
||||
cmd |= B43legacy_MACCMD_BEACON0_VALID;
|
||||
b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
|
||||
} else if (!beacon1_valid) {
|
||||
b43legacy_upload_beacon1(dev);
|
||||
cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
|
||||
cmd |= B43legacy_MACCMD_BEACON1_VALID;
|
||||
b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void b43legacy_beacon_update_trigger_work(struct work_struct *work)
|
||||
{
|
||||
struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
|
||||
beacon_update_trigger);
|
||||
struct b43legacy_wldev *dev;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
dev = wl->current_dev;
|
||||
if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) {
|
||||
spin_lock_irq(&wl->irq_lock);
|
||||
/* update beacon right away or defer to irq */
|
||||
dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
|
||||
handle_irq_beacon(dev);
|
||||
/* The handler might have updated the IRQ mask. */
|
||||
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
|
||||
dev->irq_savedstate);
|
||||
mmiowb();
|
||||
spin_unlock_irq(&wl->irq_lock);
|
||||
}
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
/* Asynchronously update the packet templates in template RAM.
|
||||
* Locking: Requires wl->irq_lock to be locked. */
|
||||
static void b43legacy_update_templates(struct b43legacy_wl *wl)
|
||||
|
@ -1156,54 +1282,24 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
|
|||
wl->current_beacon = beacon;
|
||||
wl->beacon0_uploaded = 0;
|
||||
wl->beacon1_uploaded = 0;
|
||||
queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
|
||||
}
|
||||
|
||||
static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
|
||||
u16 beacon_int)
|
||||
{
|
||||
b43legacy_time_lock(dev);
|
||||
if (dev->dev->id.revision >= 3)
|
||||
b43legacy_write32(dev, 0x188, (beacon_int << 16));
|
||||
else {
|
||||
if (dev->dev->id.revision >= 3) {
|
||||
b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_REP,
|
||||
(beacon_int << 16));
|
||||
b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_START,
|
||||
(beacon_int << 10));
|
||||
} else {
|
||||
b43legacy_write16(dev, 0x606, (beacon_int >> 6));
|
||||
b43legacy_write16(dev, 0x610, beacon_int);
|
||||
}
|
||||
b43legacy_time_unlock(dev);
|
||||
}
|
||||
|
||||
static void handle_irq_beacon(struct b43legacy_wldev *dev)
|
||||
{
|
||||
struct b43legacy_wl *wl = dev->wl;
|
||||
u32 cmd;
|
||||
|
||||
if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
|
||||
return;
|
||||
|
||||
/* This is the bottom half of the asynchronous beacon update. */
|
||||
|
||||
cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
|
||||
if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) {
|
||||
if (!wl->beacon0_uploaded) {
|
||||
b43legacy_write_beacon_template(dev, 0x68,
|
||||
B43legacy_SHM_SH_BTL0,
|
||||
B43legacy_CCK_RATE_1MB);
|
||||
b43legacy_write_probe_resp_template(dev, 0x268,
|
||||
B43legacy_SHM_SH_PRTLEN,
|
||||
&__b43legacy_ratetable[3]);
|
||||
wl->beacon0_uploaded = 1;
|
||||
}
|
||||
cmd |= B43legacy_MACCMD_BEACON0_VALID;
|
||||
}
|
||||
if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) {
|
||||
if (!wl->beacon1_uploaded) {
|
||||
b43legacy_write_beacon_template(dev, 0x468,
|
||||
B43legacy_SHM_SH_BTL1,
|
||||
B43legacy_CCK_RATE_1MB);
|
||||
wl->beacon1_uploaded = 1;
|
||||
}
|
||||
cmd |= B43legacy_MACCMD_BEACON1_VALID;
|
||||
}
|
||||
b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
|
||||
b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
|
||||
}
|
||||
|
||||
static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
|
||||
|
@ -2297,6 +2393,7 @@ static void b43legacy_security_init(struct b43legacy_wldev *dev)
|
|||
dev->max_nr_keys - 8);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_B43LEGACY_HWRNG
|
||||
static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
|
||||
{
|
||||
struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
|
||||
|
@ -2312,17 +2409,21 @@ static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
|
|||
|
||||
return (sizeof(u16));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void b43legacy_rng_exit(struct b43legacy_wl *wl)
|
||||
{
|
||||
#ifdef CONFIG_B43LEGACY_HWRNG
|
||||
if (wl->rng_initialized)
|
||||
hwrng_unregister(&wl->rng);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int b43legacy_rng_init(struct b43legacy_wl *wl)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
#ifdef CONFIG_B43LEGACY_HWRNG
|
||||
snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
|
||||
"%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
|
||||
wl->rng.name = wl->rng_name;
|
||||
|
@ -2336,6 +2437,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
|
|||
"number generator (%d)\n", err);
|
||||
}
|
||||
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -3392,6 +3494,9 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
|
|||
memset(wl->bssid, 0, ETH_ALEN);
|
||||
memset(wl->mac_addr, 0, ETH_ALEN);
|
||||
wl->filter_flags = 0;
|
||||
wl->beacon0_uploaded = 0;
|
||||
wl->beacon1_uploaded = 0;
|
||||
wl->beacon_templates_virgin = 1;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
|
@ -3429,6 +3534,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
|
|||
struct b43legacy_wldev *dev = wl->current_dev;
|
||||
|
||||
b43legacy_rfkill_exit(dev);
|
||||
cancel_work_sync(&(wl->beacon_update_trigger));
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
|
||||
|
@ -3760,6 +3866,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
|
|||
spin_lock_init(&wl->leds_lock);
|
||||
mutex_init(&wl->mutex);
|
||||
INIT_LIST_HEAD(&wl->devlist);
|
||||
INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
|
||||
|
||||
ssb_set_devtypedata(dev, wl);
|
||||
b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
|
||||
|
|
|
@ -142,7 +142,6 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
|
|||
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
rfk->rfkill->data = dev;
|
||||
rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle;
|
||||
rfk->rfkill->user_claim_unsupported = 1;
|
||||
|
||||
rfk->poll_dev = input_allocate_polled_device();
|
||||
if (!rfk->poll_dev) {
|
||||
|
|
|
@ -274,7 +274,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
|
|||
|
||||
/* PHY TX Control word */
|
||||
if (rate_ofdm)
|
||||
phy_ctl |= B43legacy_TX4_PHY_OFDM;
|
||||
phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM;
|
||||
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
||||
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
|
||||
switch (info->antenna_sel_tx) {
|
||||
|
|
|
@ -67,7 +67,9 @@ struct b43legacy_txhdr_fw3 {
|
|||
#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
|
||||
|
||||
/* PHY TX control word */
|
||||
#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
|
||||
#define B43legacy_TX4_PHY_ENC 0x0003 /* Data frame encoding */
|
||||
#define B43legacy_TX4_PHY_ENC_CCK 0x0000 /* CCK */
|
||||
#define B43legacy_TX4_PHY_ENC_OFDM 0x0001 /* Data frame rate type */
|
||||
#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
|
||||
#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */
|
||||
#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
|
||||
|
|
|
@ -435,7 +435,7 @@ static int prism2_plx_probe(struct pci_dev *pdev,
|
|||
unsigned long pccard_attr_mem;
|
||||
unsigned int pccard_attr_len;
|
||||
void __iomem *attr_mem = NULL;
|
||||
unsigned int cor_offset, cor_index;
|
||||
unsigned int cor_offset = 0, cor_index = 0;
|
||||
u32 reg;
|
||||
local_info_t *local = NULL;
|
||||
struct net_device *dev = NULL;
|
||||
|
|
|
@ -719,7 +719,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
|
|||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
|
||||
hdr->addr1);
|
||||
sta_id = iwl3945_add_station(priv,
|
||||
hdr->addr1, 0, CMD_ASYNC);
|
||||
hdr->addr1, 0, CMD_ASYNC, NULL);
|
||||
}
|
||||
if (sta_id != IWL_INVALID_STATION)
|
||||
rs_sta->ibss_sta_added = 1;
|
||||
|
|
|
@ -1964,6 +1964,194 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
|
||||
{
|
||||
int rc = 0;
|
||||
struct iwl_rx_packet *res = NULL;
|
||||
struct iwl3945_rxon_assoc_cmd rxon_assoc;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_RXON_ASSOC,
|
||||
.len = sizeof(rxon_assoc),
|
||||
.meta.flags = CMD_WANT_SKB,
|
||||
.data = &rxon_assoc,
|
||||
};
|
||||
const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
|
||||
const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
|
||||
|
||||
if ((rxon1->flags == rxon2->flags) &&
|
||||
(rxon1->filter_flags == rxon2->filter_flags) &&
|
||||
(rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
|
||||
(rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
|
||||
IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rxon_assoc.flags = priv->staging_rxon.flags;
|
||||
rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
|
||||
rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
|
||||
rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
|
||||
rxon_assoc.reserved = 0;
|
||||
|
||||
rc = iwl_send_cmd_sync(priv, &cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
|
||||
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
priv->alloc_rxb_skb--;
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl3945_commit_rxon - commit staging_rxon to hardware
|
||||
*
|
||||
* The RXON command in staging_rxon is committed to the hardware and
|
||||
* the active_rxon structure is updated with the new data. This
|
||||
* function correctly transitions out of the RXON_ASSOC_MSK state if
|
||||
* a HW tune is required based on the RXON structure changes.
|
||||
*/
|
||||
static int iwl3945_commit_rxon(struct iwl_priv *priv)
|
||||
{
|
||||
/* cast away the const for active_rxon in this function */
|
||||
struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
|
||||
struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
|
||||
int rc = 0;
|
||||
bool new_assoc =
|
||||
!!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
|
||||
|
||||
if (!iwl_is_alive(priv))
|
||||
return -1;
|
||||
|
||||
/* always get timestamp with Rx frame */
|
||||
staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK;
|
||||
|
||||
/* select antenna */
|
||||
staging_rxon->flags &=
|
||||
~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
|
||||
staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
|
||||
|
||||
rc = iwl_check_rxon_cmd(priv);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If we don't need to send a full RXON, we can use
|
||||
* iwl3945_rxon_assoc_cmd which is used to reconfigure filter
|
||||
* and other flags for the current radio configuration. */
|
||||
if (!iwl_full_rxon_required(priv)) {
|
||||
rc = iwl_send_rxon_assoc(priv);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting RXON_ASSOC "
|
||||
"configuration (%d).\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we are currently associated and the new config requires
|
||||
* an RXON_ASSOC and the new config wants the associated mask enabled,
|
||||
* we must clear the associated from the active configuration
|
||||
* before we apply the new config */
|
||||
if (iwl_is_associated(priv) && new_assoc) {
|
||||
IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
|
||||
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
|
||||
/*
|
||||
* reserved4 and 5 could have been filled by the iwlcore code.
|
||||
* Let's clear them before pushing to the 3945.
|
||||
*/
|
||||
active_rxon->reserved4 = 0;
|
||||
active_rxon->reserved5 = 0;
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
|
||||
sizeof(struct iwl3945_rxon_cmd),
|
||||
&priv->active_rxon);
|
||||
|
||||
/* If the mask clearing failed then we set
|
||||
* active_rxon back to what it was previously */
|
||||
if (rc) {
|
||||
active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
|
||||
IWL_ERR(priv, "Error clearing ASSOC_MSK on current "
|
||||
"configuration (%d).\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Sending RXON\n"
|
||||
"* with%s RXON_FILTER_ASSOC_MSK\n"
|
||||
"* channel = %d\n"
|
||||
"* bssid = %pM\n",
|
||||
(new_assoc ? "" : "out"),
|
||||
le16_to_cpu(staging_rxon->channel),
|
||||
staging_rxon->bssid_addr);
|
||||
|
||||
/*
|
||||
* reserved4 and 5 could have been filled by the iwlcore code.
|
||||
* Let's clear them before pushing to the 3945.
|
||||
*/
|
||||
staging_rxon->reserved4 = 0;
|
||||
staging_rxon->reserved5 = 0;
|
||||
|
||||
iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
|
||||
|
||||
/* Apply the new configuration */
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
|
||||
sizeof(struct iwl3945_rxon_cmd),
|
||||
staging_rxon);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting new configuration (%d).\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
|
||||
|
||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
||||
|
||||
/* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||
rc = priv->cfg->ops->lib->send_tx_power(priv);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting Tx power (%d).\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Add the broadcast address so we can send broadcast frames */
|
||||
if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) ==
|
||||
IWL_INVALID_STATION) {
|
||||
IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* If we have set the ASSOC_MSK and we are in BSS mode then
|
||||
* add the IWL_AP_ID to the station rate table */
|
||||
if (iwl_is_associated(priv) &&
|
||||
(priv->iw_mode == NL80211_IFTYPE_STATION))
|
||||
if (priv->cfg->ops->smgmt->add_station(priv,
|
||||
priv->active_rxon.bssid_addr, 1, 0, NULL)
|
||||
== IWL_INVALID_STATION) {
|
||||
IWL_ERR(priv, "Error adding AP address for transmit\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Init the hardware's rate fallback order based on the band */
|
||||
rc = iwl3945_init_hw_rate_table(priv);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* will add 3945 channel switch cmd handling later */
|
||||
int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
|
||||
{
|
||||
|
@ -2729,6 +2917,11 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct iwl_hcmd_ops iwl3945_hcmd = {
|
||||
.rxon_assoc = iwl3945_send_rxon_assoc,
|
||||
.commit_rxon = iwl3945_commit_rxon,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl3945_lib = {
|
||||
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
|
||||
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
|
||||
|
@ -2758,6 +2951,17 @@ static struct iwl_lib_ops iwl3945_lib = {
|
|||
},
|
||||
.send_tx_power = iwl3945_send_tx_power,
|
||||
.is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
|
||||
.post_associate = iwl3945_post_associate,
|
||||
.config_ap = iwl3945_config_ap,
|
||||
};
|
||||
|
||||
static struct iwl_station_mgmt_ops iwl3945_station_mgmt = {
|
||||
.add_station = iwl3945_add_station,
|
||||
#if 0
|
||||
.remove_station = iwl3945_remove_station,
|
||||
#endif
|
||||
.find_station = iwl3945_hw_find_station,
|
||||
.clear_station_table = iwl3945_clear_stations_table,
|
||||
};
|
||||
|
||||
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
||||
|
@ -2767,7 +2971,9 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
|||
|
||||
static struct iwl_ops iwl3945_ops = {
|
||||
.lib = &iwl3945_lib,
|
||||
.hcmd = &iwl3945_hcmd,
|
||||
.utils = &iwl3945_hcmd_utils,
|
||||
.smgmt = &iwl3945_station_mgmt,
|
||||
};
|
||||
|
||||
static struct iwl_cfg iwl3945_bg_cfg = {
|
||||
|
|
|
@ -162,7 +162,6 @@ struct iwl3945_frame {
|
|||
#define STATUS_TEMPERATURE 8
|
||||
#define STATUS_GEO_CONFIGURED 9
|
||||
#define STATUS_EXIT_PENDING 10
|
||||
#define STATUS_IN_SUSPEND 11
|
||||
#define STATUS_STATISTICS 12
|
||||
#define STATUS_SCANNING 13
|
||||
#define STATUS_SCAN_ABORTING 14
|
||||
|
@ -207,7 +206,8 @@ struct iwl3945_addsta_cmd;
|
|||
extern int iwl3945_send_add_station(struct iwl_priv *priv,
|
||||
struct iwl3945_addsta_cmd *sta, u8 flags);
|
||||
extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid,
|
||||
int is_ap, u8 flags);
|
||||
int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
|
||||
extern void iwl3945_clear_stations_table(struct iwl_priv *priv);
|
||||
extern int iwl3945_power_init_handle(struct iwl_priv *priv);
|
||||
extern int iwl3945_eeprom_init(struct iwl_priv *priv);
|
||||
extern int iwl3945_calc_db_from_ratio(int sig_ratio);
|
||||
|
@ -278,6 +278,8 @@ extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
|
|||
struct iwl_rx_mem_buffer *rxb);
|
||||
extern void iwl3945_disable_events(struct iwl_priv *priv);
|
||||
extern int iwl4965_get_temperature(const struct iwl_priv *priv);
|
||||
extern void iwl3945_post_associate(struct iwl_priv *priv);
|
||||
extern void iwl3945_config_ap(struct iwl_priv *priv);
|
||||
|
||||
/**
|
||||
* iwl3945_hw_find_station - Find station id for a given BSSID
|
||||
|
|
|
@ -2268,9 +2268,17 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
|
|||
cancel_work_sync(&priv->txpower_work);
|
||||
}
|
||||
|
||||
static struct iwl_station_mgmt_ops iwl4965_station_mgmt = {
|
||||
.add_station = iwl_add_station_flags,
|
||||
.remove_station = iwl_remove_station,
|
||||
.find_station = iwl_find_station,
|
||||
.clear_station_table = iwl_clear_stations_table,
|
||||
};
|
||||
|
||||
static struct iwl_hcmd_ops iwl4965_hcmd = {
|
||||
.rxon_assoc = iwl4965_send_rxon_assoc,
|
||||
.commit_rxon = iwl_commit_rxon,
|
||||
.set_rxon_chain = iwl_set_rxon_chain,
|
||||
};
|
||||
|
||||
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
|
||||
|
@ -2324,12 +2332,15 @@ static struct iwl_lib_ops iwl4965_lib = {
|
|||
.send_tx_power = iwl4965_send_tx_power,
|
||||
.update_chain_flags = iwl_update_chain_flags,
|
||||
.temperature = iwl4965_temperature_calib,
|
||||
.post_associate = iwl_post_associate,
|
||||
.config_ap = iwl_config_ap,
|
||||
};
|
||||
|
||||
static struct iwl_ops iwl4965_ops = {
|
||||
.lib = &iwl4965_lib,
|
||||
.hcmd = &iwl4965_hcmd,
|
||||
.utils = &iwl4965_hcmd_utils,
|
||||
.smgmt = &iwl4965_station_mgmt,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl4965_agn_cfg = {
|
||||
|
@ -2350,8 +2361,6 @@ MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
|
|||
|
||||
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
|
||||
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
|
||||
module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
|
||||
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
|
||||
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
|
||||
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
|
||||
module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
|
||||
|
|
|
@ -678,7 +678,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv)
|
|||
goto restart;
|
||||
}
|
||||
|
||||
iwl_clear_stations_table(priv);
|
||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
||||
ret = priv->cfg->ops->lib->alive_notify(priv);
|
||||
if (ret) {
|
||||
IWL_WARN(priv,
|
||||
|
@ -1472,8 +1472,17 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
|
|||
return max_rssi - agc - IWL49_RSSI_OFFSET;
|
||||
}
|
||||
|
||||
struct iwl_station_mgmt_ops iwl5000_station_mgmt = {
|
||||
.add_station = iwl_add_station_flags,
|
||||
.remove_station = iwl_remove_station,
|
||||
.find_station = iwl_find_station,
|
||||
.clear_station_table = iwl_clear_stations_table,
|
||||
};
|
||||
|
||||
struct iwl_hcmd_ops iwl5000_hcmd = {
|
||||
.rxon_assoc = iwl5000_send_rxon_assoc,
|
||||
.commit_rxon = iwl_commit_rxon,
|
||||
.set_rxon_chain = iwl_set_rxon_chain,
|
||||
};
|
||||
|
||||
struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
|
||||
|
@ -1527,12 +1536,15 @@ struct iwl_lib_ops iwl5000_lib = {
|
|||
.calib_version = iwl5000_eeprom_calib_version,
|
||||
.query_addr = iwl5000_eeprom_query_addr,
|
||||
},
|
||||
.post_associate = iwl_post_associate,
|
||||
.config_ap = iwl_config_ap,
|
||||
};
|
||||
|
||||
struct iwl_ops iwl5000_ops = {
|
||||
.lib = &iwl5000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
.utils = &iwl5000_hcmd_utils,
|
||||
.smgmt = &iwl5000_station_mgmt,
|
||||
};
|
||||
|
||||
struct iwl_mod_params iwl50_mod_params = {
|
||||
|
@ -1643,9 +1655,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
|
|||
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
|
||||
|
||||
module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
|
||||
MODULE_PARM_DESC(disable50,
|
||||
"manually disable the 50XX radio (default 0 [radio on])");
|
||||
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
|
||||
MODULE_PARM_DESC(swcrypto50,
|
||||
"using software crypto engine (default 0 [hardware])\n");
|
||||
|
|
|
@ -72,6 +72,7 @@ static struct iwl_ops iwl6000_ops = {
|
|||
.lib = &iwl5000_lib,
|
||||
.hcmd = &iwl5000_hcmd,
|
||||
.utils = &iwl6000_hcmd_utils,
|
||||
.smgmt = &iwl5000_station_mgmt,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6000_2ag_cfg = {
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
/* max allowed rate miss before sync LQ cmd */
|
||||
#define IWL_MISSED_RATE_MAX 15
|
||||
/* max time to accum history 2 seconds */
|
||||
#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ)
|
||||
#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ)
|
||||
|
||||
static u8 rs_ht_to_legacy[] = {
|
||||
IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
|
||||
|
@ -135,7 +135,7 @@ struct iwl_lq_sta {
|
|||
u32 table_count;
|
||||
u32 total_failed; /* total failed frames, any/all rates */
|
||||
u32 total_success; /* total successful frames, any/all rates */
|
||||
u32 flush_timer; /* time staying in mode before new search */
|
||||
u64 flush_timer; /* time staying in mode before new search */
|
||||
|
||||
u8 action_counter; /* # mode-switch actions tried */
|
||||
u8 is_green;
|
||||
|
@ -167,6 +167,8 @@ struct iwl_lq_sta {
|
|||
|
||||
/* used to be in sta_info */
|
||||
int last_txrate_idx;
|
||||
/* last tx rate_n_flags */
|
||||
u32 last_rate_n_flags;
|
||||
};
|
||||
|
||||
static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
|
@ -191,7 +193,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
|
|||
* 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
|
||||
* "G" is the only table that supports CCK (the first 4 rates).
|
||||
*/
|
||||
/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/
|
||||
|
||||
static s32 expected_tpt_A[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
|
||||
};
|
||||
|
@ -208,11 +210,11 @@ static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
|
|||
0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {
|
||||
static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {
|
||||
static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
|
||||
};
|
||||
|
||||
|
@ -224,14 +226,48 @@ static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
|
|||
0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {
|
||||
static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
|
||||
static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
|
||||
};
|
||||
|
||||
/* Expected throughput metric MIMO3 */
|
||||
static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300
|
||||
};
|
||||
|
||||
/* mbps, mcs */
|
||||
const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
|
||||
{"1", ""},
|
||||
{"2", ""},
|
||||
{"5.5", ""},
|
||||
{"11", ""},
|
||||
{"6", "BPSK 1/2"},
|
||||
{"9", "BPSK 1/2"},
|
||||
{"12", "QPSK 1/2"},
|
||||
{"18", "QPSK 3/4"},
|
||||
{"24", "16QAM 1/2"},
|
||||
{"36", "16QAM 3/4"},
|
||||
{"48", "64QAM 2/3"},
|
||||
{"54", "64QAM 3/4"},
|
||||
{"60", "64QAM 5/6"}
|
||||
};
|
||||
|
||||
static inline u8 rs_extract_rate(u32 rate_n_flags)
|
||||
{
|
||||
return (u8)(rate_n_flags & 0xFF);
|
||||
|
@ -902,6 +938,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
* else look up the rate that was, finally, successful.
|
||||
*/
|
||||
tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
|
||||
lq_sta->last_rate_n_flags = tx_rate;
|
||||
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
|
||||
|
||||
/* Update frame history window with "success" if Tx got ACKed ... */
|
||||
|
@ -988,6 +1025,7 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
|
|||
lq_sta->table_count = 0;
|
||||
lq_sta->total_failed = 0;
|
||||
lq_sta->total_success = 0;
|
||||
lq_sta->flush_timer = jiffies;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1011,17 +1049,26 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
tbl->expected_tpt = expected_tpt_siso20MHzSGI;
|
||||
else
|
||||
tbl->expected_tpt = expected_tpt_siso20MHz;
|
||||
|
||||
} else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */
|
||||
} else if (is_mimo2(tbl->lq_type)) {
|
||||
if (tbl->is_fat && !lq_sta->is_dup)
|
||||
if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
|
||||
tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
|
||||
else
|
||||
tbl->expected_tpt = expected_tpt_mimo40MHz;
|
||||
tbl->expected_tpt = expected_tpt_mimo2_40MHz;
|
||||
else if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_mimo20MHzSGI;
|
||||
tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI;
|
||||
else
|
||||
tbl->expected_tpt = expected_tpt_mimo20MHz;
|
||||
tbl->expected_tpt = expected_tpt_mimo2_20MHz;
|
||||
} else if (is_mimo3(tbl->lq_type)) {
|
||||
if (tbl->is_fat && !lq_sta->is_dup)
|
||||
if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
|
||||
else
|
||||
tbl->expected_tpt = expected_tpt_mimo3_40MHz;
|
||||
else if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI;
|
||||
else
|
||||
tbl->expected_tpt = expected_tpt_mimo3_20MHz;
|
||||
} else
|
||||
tbl->expected_tpt = expected_tpt_G;
|
||||
}
|
||||
|
@ -1130,7 +1177,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
|
|||
}
|
||||
|
||||
/*
|
||||
* Set up search table for MIMO
|
||||
* Set up search table for MIMO2
|
||||
*/
|
||||
static int rs_switch_to_mimo2(struct iwl_priv *priv,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
|
@ -1183,7 +1230,73 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
|
|||
rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
|
||||
if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
|
||||
IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
|
||||
rate, rate_mask);
|
||||
return -1;
|
||||
}
|
||||
tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
|
||||
tbl->current_rate, is_green);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up search table for MIMO3
|
||||
*/
|
||||
static int rs_switch_to_mimo3(struct iwl_priv *priv,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_scale_tbl_info *tbl, int index)
|
||||
{
|
||||
u16 rate_mask;
|
||||
s32 rate;
|
||||
s8 is_green = lq_sta->is_green;
|
||||
|
||||
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
|
||||
return -1;
|
||||
|
||||
if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
|
||||
== WLAN_HT_CAP_SM_PS_STATIC)
|
||||
return -1;
|
||||
|
||||
/* Need both Tx chains/antennas to support MIMO */
|
||||
if (priv->hw_params.tx_chains_num < 3)
|
||||
return -1;
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
|
||||
|
||||
tbl->lq_type = LQ_MIMO3;
|
||||
tbl->is_dup = lq_sta->is_dup;
|
||||
tbl->action = 0;
|
||||
rate_mask = lq_sta->active_mimo3_rate;
|
||||
|
||||
if (priv->current_ht_config.supported_chan_width
|
||||
== IWL_CHANNEL_WIDTH_40MHZ)
|
||||
tbl->is_fat = 1;
|
||||
else
|
||||
tbl->is_fat = 0;
|
||||
|
||||
/* FIXME: - don't toggle SGI here
|
||||
if (tbl->is_fat) {
|
||||
if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
|
||||
tbl->is_SGI = 1;
|
||||
else
|
||||
tbl->is_SGI = 0;
|
||||
} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
|
||||
tbl->is_SGI = 1;
|
||||
else
|
||||
tbl->is_SGI = 0;
|
||||
*/
|
||||
|
||||
rs_set_expected_tpt_table(lq_sta, tbl);
|
||||
|
||||
rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
|
||||
rate, rate_mask);
|
||||
if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
|
||||
IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
|
||||
rate, rate_mask);
|
||||
|
@ -1342,9 +1455,29 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case IWL_LEGACY_SWITCH_MIMO3_ABC:
|
||||
IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");
|
||||
|
||||
/* Set up search table to try MIMO3 */
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
search_tbl->is_SGI = 0;
|
||||
|
||||
search_tbl->ant_type = ANT_ABC;
|
||||
|
||||
if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
|
||||
break;
|
||||
|
||||
ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
|
||||
search_tbl, index);
|
||||
if (!ret) {
|
||||
lq_sta->action_counter = 0;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC)
|
||||
if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
|
||||
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
|
||||
|
||||
if (tbl->action == start_action)
|
||||
|
@ -1357,7 +1490,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
out:
|
||||
lq_sta->search_better_tbl = 1;
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC)
|
||||
if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
|
||||
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
|
||||
return 0;
|
||||
|
||||
|
@ -1457,9 +1590,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
rate_n_flags_from_tbl(priv, search_tbl,
|
||||
index, is_green);
|
||||
goto out;
|
||||
case IWL_SISO_SWITCH_MIMO3_ABC:
|
||||
IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
search_tbl->is_SGI = 0;
|
||||
search_tbl->ant_type = ANT_ABC;
|
||||
|
||||
if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
|
||||
break;
|
||||
|
||||
ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
|
||||
search_tbl, index);
|
||||
if (!ret)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_SISO_SWITCH_GI)
|
||||
if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
|
||||
if (tbl->action == start_action)
|
||||
|
@ -1471,15 +1618,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
out:
|
||||
lq_sta->search_better_tbl = 1;
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_SISO_SWITCH_GI)
|
||||
if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to switch to new modulation mode from MIMO
|
||||
* Try to switch to new modulation mode from MIMO2
|
||||
*/
|
||||
static int rs_move_mimo_to_other(struct iwl_priv *priv,
|
||||
static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct ieee80211_sta *sta, int index)
|
||||
|
@ -1501,7 +1648,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
|
|||
switch (tbl->action) {
|
||||
case IWL_MIMO2_SWITCH_ANTENNA1:
|
||||
case IWL_MIMO2_SWITCH_ANTENNA2:
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO toggle Antennas\n");
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
|
||||
|
||||
if (tx_chains_num <= 2)
|
||||
break;
|
||||
|
@ -1549,7 +1696,160 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
|
|||
HT_SHORT_GI_40MHZ))
|
||||
break;
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO toggle SGI/NGI\n");
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
|
||||
|
||||
/* Set up new search table for MIMO2 */
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
search_tbl->is_SGI = !tbl->is_SGI;
|
||||
rs_set_expected_tpt_table(lq_sta, search_tbl);
|
||||
/*
|
||||
* If active table already uses the fastest possible
|
||||
* modulation (dual stream with short guard interval),
|
||||
* and it's working well, there's no need to look
|
||||
* for a better type of modulation!
|
||||
*/
|
||||
if (tbl->is_SGI) {
|
||||
s32 tpt = lq_sta->last_tpt / 100;
|
||||
if (tpt >= search_tbl->expected_tpt[index])
|
||||
break;
|
||||
}
|
||||
search_tbl->current_rate =
|
||||
rate_n_flags_from_tbl(priv, search_tbl,
|
||||
index, is_green);
|
||||
goto out;
|
||||
|
||||
case IWL_MIMO2_SWITCH_MIMO3_ABC:
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
search_tbl->is_SGI = 0;
|
||||
search_tbl->ant_type = ANT_ABC;
|
||||
|
||||
if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
|
||||
break;
|
||||
|
||||
ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
|
||||
search_tbl, index);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
break;
|
||||
}
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
|
||||
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
|
||||
|
||||
if (tbl->action == start_action)
|
||||
break;
|
||||
}
|
||||
search_tbl->lq_type = LQ_NONE;
|
||||
return 0;
|
||||
out:
|
||||
lq_sta->search_better_tbl = 1;
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
|
||||
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to switch to new modulation mode from MIMO3
|
||||
*/
|
||||
static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
struct ieee80211_conf *conf,
|
||||
struct ieee80211_sta *sta, int index)
|
||||
{
|
||||
s8 is_green = lq_sta->is_green;
|
||||
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
|
||||
struct iwl_scale_tbl_info *search_tbl =
|
||||
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
|
||||
struct iwl_rate_scale_data *window = &(tbl->win[index]);
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action = tbl->action;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
lq_sta->action_counter++;
|
||||
switch (tbl->action) {
|
||||
case IWL_MIMO3_SWITCH_ANTENNA1:
|
||||
case IWL_MIMO3_SWITCH_ANTENNA2:
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");
|
||||
|
||||
if (tx_chains_num <= 3)
|
||||
break;
|
||||
|
||||
if (window->success_ratio >= IWL_RS_GOOD_RATIO)
|
||||
break;
|
||||
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
if (rs_toggle_antenna(valid_tx_ant,
|
||||
&search_tbl->current_rate, search_tbl))
|
||||
goto out;
|
||||
break;
|
||||
case IWL_MIMO3_SWITCH_SISO_A:
|
||||
case IWL_MIMO3_SWITCH_SISO_B:
|
||||
case IWL_MIMO3_SWITCH_SISO_C:
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");
|
||||
|
||||
/* Set up new search table for SISO */
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
|
||||
if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
|
||||
search_tbl->ant_type = ANT_A;
|
||||
else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
|
||||
search_tbl->ant_type = ANT_B;
|
||||
else
|
||||
search_tbl->ant_type = ANT_C;
|
||||
|
||||
if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
|
||||
break;
|
||||
|
||||
ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
|
||||
search_tbl, index);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
break;
|
||||
|
||||
case IWL_MIMO3_SWITCH_MIMO2_AB:
|
||||
case IWL_MIMO3_SWITCH_MIMO2_AC:
|
||||
case IWL_MIMO3_SWITCH_MIMO2_BC:
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");
|
||||
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
search_tbl->is_SGI = 0;
|
||||
if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
|
||||
search_tbl->ant_type = ANT_AB;
|
||||
else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
|
||||
search_tbl->ant_type = ANT_AC;
|
||||
else
|
||||
search_tbl->ant_type = ANT_BC;
|
||||
|
||||
if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
|
||||
break;
|
||||
|
||||
ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
|
||||
search_tbl, index);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
break;
|
||||
|
||||
case IWL_MIMO3_SWITCH_GI:
|
||||
if (!tbl->is_fat &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_20MHZ))
|
||||
break;
|
||||
if (tbl->is_fat &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_40MHZ))
|
||||
break;
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
|
||||
|
||||
/* Set up new search table for MIMO */
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
|
@ -1570,11 +1870,10 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
|
|||
rate_n_flags_from_tbl(priv, search_tbl,
|
||||
index, is_green);
|
||||
goto out;
|
||||
|
||||
}
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_MIMO2_SWITCH_GI)
|
||||
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
|
||||
if (tbl->action > IWL_MIMO3_SWITCH_GI)
|
||||
tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
|
||||
|
||||
if (tbl->action == start_action)
|
||||
break;
|
||||
|
@ -1584,8 +1883,8 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
|
|||
out:
|
||||
lq_sta->search_better_tbl = 1;
|
||||
tbl->action++;
|
||||
if (tbl->action > IWL_MIMO2_SWITCH_GI)
|
||||
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
|
||||
if (tbl->action > IWL_MIMO3_SWITCH_GI)
|
||||
tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -1616,8 +1915,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
|
|||
/* Elapsed time using current modulation mode */
|
||||
if (lq_sta->flush_timer)
|
||||
flush_interval_passed =
|
||||
time_after(jiffies,
|
||||
(unsigned long)(lq_sta->flush_timer +
|
||||
time_after(jiffies,
|
||||
(unsigned long)(lq_sta->flush_timer +
|
||||
IWL_RATE_SCALE_FLUSH_INTVL));
|
||||
|
||||
/*
|
||||
|
@ -1951,6 +2250,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
update_lq = 1;
|
||||
index = low;
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
/* Increase starting rate, update uCode's rate table */
|
||||
|
@ -1997,8 +2297,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
rs_move_legacy_other(priv, lq_sta, conf, sta, index);
|
||||
else if (is_siso(tbl->lq_type))
|
||||
rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
|
||||
else if (is_mimo2(tbl->lq_type))
|
||||
rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
|
||||
else
|
||||
rs_move_mimo_to_other(priv, lq_sta, conf, sta, index);
|
||||
rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
|
||||
|
||||
/* If new "search" mode was selected, set up in uCode table */
|
||||
if (lq_sta->search_better_tbl) {
|
||||
|
@ -2014,8 +2316,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
tbl->current_rate, index);
|
||||
rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
|
||||
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
}
|
||||
} else
|
||||
done_search = 1;
|
||||
}
|
||||
|
||||
if (done_search && !lq_sta->stay_in_tbl) {
|
||||
/* If the "active" (non-search) mode was legacy,
|
||||
* and we've tried switching antennas,
|
||||
* but we haven't been able to try HT modes (not available),
|
||||
|
@ -2050,17 +2355,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
lq_sta->action_counter = 0;
|
||||
rs_set_stay_in_table(priv, 0, lq_sta);
|
||||
}
|
||||
|
||||
/*
|
||||
* Else, don't search for a new modulation mode.
|
||||
* Put new timestamp in stay-in-modulation-mode flush timer if:
|
||||
* 1) Not changing rates right now
|
||||
* 2) Not just finishing up a search
|
||||
* 3) flush timer is empty
|
||||
*/
|
||||
} else {
|
||||
if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer))
|
||||
lq_sta->flush_timer = jiffies;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -2173,13 +2467,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
|
|||
|
||||
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
|
||||
!lq_sta->ibss_sta_added) {
|
||||
u8 sta_id = iwl_find_station(priv, hdr->addr1);
|
||||
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
|
||||
hdr->addr1);
|
||||
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
|
||||
hdr->addr1);
|
||||
sta_id = iwl_add_station_flags(priv, hdr->addr1,
|
||||
0, CMD_ASYNC, NULL);
|
||||
sta_id = priv->cfg->ops->smgmt->add_station(priv,
|
||||
hdr->addr1, 0,
|
||||
CMD_ASYNC, NULL);
|
||||
}
|
||||
if ((sta_id != IWL_INVALID_STATION)) {
|
||||
lq_sta->lq.sta_id = sta_id;
|
||||
|
@ -2246,15 +2542,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
|
||||
lq_sta->ibss_sta_added = 0;
|
||||
if (priv->iw_mode == NL80211_IFTYPE_AP) {
|
||||
u8 sta_id = iwl_find_station(priv, sta->addr);
|
||||
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
|
||||
sta->addr);
|
||||
|
||||
/* for IBSS the call are from tasklet */
|
||||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
|
||||
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
|
||||
sta_id = iwl_add_station_flags(priv, sta->addr,
|
||||
0, CMD_ASYNC, NULL);
|
||||
sta_id = priv->cfg->ops->smgmt->add_station(priv,
|
||||
sta->addr, 0,
|
||||
CMD_ASYNC, NULL);
|
||||
}
|
||||
if ((sta_id != IWL_INVALID_STATION)) {
|
||||
lq_sta->lq.sta_id = sta_id;
|
||||
|
@ -2539,6 +2837,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
char *buff;
|
||||
int desc = 0;
|
||||
int i = 0;
|
||||
int index = 0;
|
||||
ssize_t ret;
|
||||
|
||||
struct iwl_lq_sta *lq_sta = file->private_data;
|
||||
|
@ -2570,6 +2869,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
(tbl->is_fat) ? "40MHz" : "20MHz");
|
||||
desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : "");
|
||||
}
|
||||
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
|
||||
lq_sta->last_rate_n_flags);
|
||||
desc += sprintf(buff+desc, "general:"
|
||||
"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
|
||||
lq_sta->lq.general_params.flags,
|
||||
|
@ -2590,10 +2891,19 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
lq_sta->lq.general_params.start_rate_index[2],
|
||||
lq_sta->lq.general_params.start_rate_index[3]);
|
||||
|
||||
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
|
||||
i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
|
||||
index = iwl_hwrate_to_plcp_idx(
|
||||
le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
|
||||
if (is_legacy(tbl->lq_type)) {
|
||||
desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
|
||||
i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
|
||||
iwl_rate_mcs[index].mbps);
|
||||
} else {
|
||||
desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
|
||||
i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
|
||||
iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
|
||||
}
|
||||
}
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
|
||||
kfree(buff);
|
||||
|
|
|
@ -241,6 +241,7 @@ enum {
|
|||
#define IWL_LEGACY_SWITCH_MIMO2_AB 3
|
||||
#define IWL_LEGACY_SWITCH_MIMO2_AC 4
|
||||
#define IWL_LEGACY_SWITCH_MIMO2_BC 5
|
||||
#define IWL_LEGACY_SWITCH_MIMO3_ABC 6
|
||||
|
||||
/* possible actions when in siso mode */
|
||||
#define IWL_SISO_SWITCH_ANTENNA1 0
|
||||
|
@ -249,6 +250,8 @@ enum {
|
|||
#define IWL_SISO_SWITCH_MIMO2_AC 3
|
||||
#define IWL_SISO_SWITCH_MIMO2_BC 4
|
||||
#define IWL_SISO_SWITCH_GI 5
|
||||
#define IWL_SISO_SWITCH_MIMO3_ABC 6
|
||||
|
||||
|
||||
/* possible actions when in mimo mode */
|
||||
#define IWL_MIMO2_SWITCH_ANTENNA1 0
|
||||
|
@ -257,6 +260,21 @@ enum {
|
|||
#define IWL_MIMO2_SWITCH_SISO_B 3
|
||||
#define IWL_MIMO2_SWITCH_SISO_C 4
|
||||
#define IWL_MIMO2_SWITCH_GI 5
|
||||
#define IWL_MIMO2_SWITCH_MIMO3_ABC 6
|
||||
|
||||
|
||||
/* possible actions when in mimo3 mode */
|
||||
#define IWL_MIMO3_SWITCH_ANTENNA1 0
|
||||
#define IWL_MIMO3_SWITCH_ANTENNA2 1
|
||||
#define IWL_MIMO3_SWITCH_SISO_A 2
|
||||
#define IWL_MIMO3_SWITCH_SISO_B 3
|
||||
#define IWL_MIMO3_SWITCH_SISO_C 4
|
||||
#define IWL_MIMO3_SWITCH_MIMO2_AB 5
|
||||
#define IWL_MIMO3_SWITCH_MIMO2_AC 6
|
||||
#define IWL_MIMO3_SWITCH_MIMO2_BC 7
|
||||
#define IWL_MIMO3_SWITCH_GI 8
|
||||
|
||||
|
||||
|
||||
/*FIXME:RS:add possible actions for MIMO3*/
|
||||
|
||||
|
@ -307,6 +325,13 @@ enum iwl_table_type {
|
|||
#define ANT_BC (ANT_B | ANT_C)
|
||||
#define ANT_ABC (ANT_AB | ANT_C)
|
||||
|
||||
#define IWL_MAX_MCS_DISPLAY_SIZE 12
|
||||
|
||||
struct iwl_rate_mcs_info {
|
||||
char mbps[IWL_MAX_MCS_DISPLAY_SIZE];
|
||||
char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
|
||||
};
|
||||
|
||||
static inline u8 num_of_ant(u8 mask)
|
||||
{
|
||||
return !!((mask) & ANT_A) +
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2469,11 +2469,12 @@ struct iwl_ssid_ie {
|
|||
u8 ssid[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define PROBE_OPTION_MAX_API1 0x4
|
||||
#define PROBE_OPTION_MAX 0x14
|
||||
#define PROBE_OPTION_MAX_3945 4
|
||||
#define PROBE_OPTION_MAX 20
|
||||
#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
|
||||
#define IWL_GOOD_CRC_TH cpu_to_le16(1)
|
||||
#define IWL_MAX_SCAN_SIZE 1024
|
||||
#define IWL_MAX_PROBE_REQUEST 200
|
||||
|
||||
/*
|
||||
* REPLY_SCAN_CMD = 0x80 (command)
|
||||
|
@ -2552,7 +2553,7 @@ struct iwl3945_scan_cmd {
|
|||
struct iwl3945_tx_cmd tx_cmd;
|
||||
|
||||
/* For directed active scans (set to all-0s otherwise) */
|
||||
struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_API1];
|
||||
struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945];
|
||||
|
||||
/*
|
||||
* Probe request frame, followed by channel list.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue