Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: arch/arm/mach-omap2/board-omap3pandora.c drivers/net/wireless/ath/ath5k/base.c
This commit is contained in:
commit
b618f6f885
|
@ -1120,6 +1120,13 @@ W: http://wireless.kernel.org/en/users/Drivers/ar9170
|
|||
S: Maintained
|
||||
F: drivers/net/wireless/ath/ar9170/
|
||||
|
||||
CARL9170 LINUX COMMUNITY WIRELESS DRIVER
|
||||
M: Christian Lamparter <chunkeey@googlemail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org/en/users/Drivers/carl9170
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/ath/carl9170/
|
||||
|
||||
ATK0110 HWMON DRIVER
|
||||
M: Luca Tettamanti <kronos.it@gmail.com>
|
||||
L: lm-sensors@lm-sensors.org
|
||||
|
@ -6427,7 +6434,7 @@ W: http://wireless.kernel.org
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/wl12xx/wl1271*
|
||||
F: include/linux/spi/wl12xx.h
|
||||
F: include/linux/wl12xx.h
|
||||
|
||||
WL3501 WIRELESS PCMCIA CARD DRIVER
|
||||
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/spi/ads7846.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/spi/wl12xx.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/leds.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/wl12xx.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/clk.h>
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/wl12xx.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -27,6 +29,9 @@
|
|||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
|
||||
#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
|
||||
#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
|
||||
|
||||
/* Zoom2 has Qwerty keyboard*/
|
||||
static int board_keymap[] = {
|
||||
KEY(0, 0, KEY_E),
|
||||
|
@ -106,6 +111,11 @@ static struct regulator_consumer_supply zoom_vmmc2_supply = {
|
|||
.supply = "vmmc",
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply zoom_vmmc3_supply = {
|
||||
.supply = "vmmc",
|
||||
.dev_name = "mmci-omap-hs.2",
|
||||
};
|
||||
|
||||
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
|
||||
static struct regulator_init_data zoom_vmmc1 = {
|
||||
.constraints = {
|
||||
|
@ -151,6 +161,38 @@ static struct regulator_init_data zoom_vsim = {
|
|||
.consumer_supplies = &zoom_vsim_supply,
|
||||
};
|
||||
|
||||
static struct regulator_init_data zoom_vmmc3 = {
|
||||
.constraints = {
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = 1,
|
||||
.consumer_supplies = &zoom_vmmc3_supply,
|
||||
};
|
||||
|
||||
static struct fixed_voltage_config zoom_vwlan = {
|
||||
.supply_name = "vwl1271",
|
||||
.microvolts = 1800000, /* 1.8V */
|
||||
.gpio = OMAP_ZOOM_WLAN_PMENA_GPIO,
|
||||
.startup_delay = 70000, /* 70msec */
|
||||
.enable_high = 1,
|
||||
.enabled_at_boot = 0,
|
||||
.init_data = &zoom_vmmc3,
|
||||
};
|
||||
|
||||
static struct platform_device omap_vwlan_device = {
|
||||
.name = "reg-fixed-voltage",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.platform_data = &zoom_vwlan,
|
||||
},
|
||||
};
|
||||
|
||||
struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
|
||||
.irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
|
||||
/* ZOOM ref clock is 26 MHz */
|
||||
.board_ref_clock = 1,
|
||||
};
|
||||
|
||||
static struct omap2_hsmmc_info mmc[] __initdata = {
|
||||
{
|
||||
.name = "external",
|
||||
|
@ -168,6 +210,14 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
|
|||
.nonremovable = true,
|
||||
.power_saving = true,
|
||||
},
|
||||
{
|
||||
.name = "wl1271",
|
||||
.mmc = 3,
|
||||
.wires = 4,
|
||||
.gpio_wp = -EINVAL,
|
||||
.gpio_cd = -EINVAL,
|
||||
.nonremovable = true,
|
||||
},
|
||||
{} /* Terminator */
|
||||
};
|
||||
|
||||
|
@ -279,7 +329,11 @@ static void enable_board_wakeup_source(void)
|
|||
|
||||
void __init zoom_peripherals_init(void)
|
||||
{
|
||||
if (wl12xx_set_platform_data(&omap_zoom_wlan_data))
|
||||
pr_err("error setting wl12xx data\n");
|
||||
|
||||
omap_i2c_init();
|
||||
platform_device_register(&omap_vwlan_device);
|
||||
usb_musb_init(&musb_board_data);
|
||||
enable_board_wakeup_source();
|
||||
}
|
||||
|
|
|
@ -50,5 +50,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
|
|||
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
|
||||
|
||||
obj-$(CONFIG_WL12XX) += wl12xx/
|
||||
# small builtin driver bit
|
||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/wl12xx_platform_data.o
|
||||
|
||||
obj-$(CONFIG_IWM) += iwmc3200wifi/
|
||||
|
|
|
@ -105,7 +105,7 @@ static struct pci_driver airo_driver = {
|
|||
of statistics in the /proc filesystem */
|
||||
|
||||
#define IGNLABEL(comment) NULL
|
||||
static char *statsLabels[] = {
|
||||
static const char *statsLabels[] = {
|
||||
"RxOverrun",
|
||||
IGNLABEL("RxPlcpCrcErr"),
|
||||
IGNLABEL("RxPlcpFormatErr"),
|
||||
|
@ -932,7 +932,7 @@ typedef struct aironet_ioctl {
|
|||
unsigned char __user *data; // d-data
|
||||
} aironet_ioctl;
|
||||
|
||||
static char swversion[] = "2.1";
|
||||
static const char swversion[] = "2.1";
|
||||
#endif /* CISCO_EXT */
|
||||
|
||||
#define NUM_MODULES 2
|
||||
|
@ -1374,7 +1374,7 @@ static int micsetup(struct airo_info *ai) {
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
|
||||
static const u8 micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
|
||||
|
||||
/*===========================================================================
|
||||
* Description: Mic a packet
|
||||
|
@ -5023,7 +5023,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file)
|
|||
airo_config_commit(dev, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static char *get_rmode(__le16 mode)
|
||||
static const char *get_rmode(__le16 mode)
|
||||
{
|
||||
switch(mode & RXMODE_MASK) {
|
||||
case RXMODE_RFMON: return "rfmon";
|
||||
|
|
|
@ -25,5 +25,6 @@ config ATH_DEBUG
|
|||
source "drivers/net/wireless/ath/ath5k/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath9k/Kconfig"
|
||||
source "drivers/net/wireless/ath/ar9170/Kconfig"
|
||||
source "drivers/net/wireless/ath/carl9170/Kconfig"
|
||||
|
||||
endif
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
obj-$(CONFIG_ATH5K) += ath5k/
|
||||
obj-$(CONFIG_ATH9K_HW) += ath9k/
|
||||
obj-$(CONFIG_AR9170_USB) += ar9170/
|
||||
obj-$(CONFIG_CARL9170) += carl9170/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
|
||||
ath-objs := main.o \
|
||||
regd.o \
|
||||
hw.o
|
||||
hw.o \
|
||||
key.o
|
||||
|
||||
ath-$(CONFIG_ATH_DEBUG) += debug.o
|
||||
|
|
|
@ -71,6 +71,32 @@ struct ath_regulatory {
|
|||
struct reg_dmn_pair_mapping *regpair;
|
||||
};
|
||||
|
||||
enum ath_crypt_caps {
|
||||
ATH_CRYPT_CAP_CIPHER_AESCCM = BIT(0),
|
||||
ATH_CRYPT_CAP_MIC_COMBINED = BIT(1),
|
||||
};
|
||||
|
||||
struct ath_keyval {
|
||||
u8 kv_type;
|
||||
u8 kv_pad;
|
||||
u16 kv_len;
|
||||
u8 kv_val[16]; /* TK */
|
||||
u8 kv_mic[8]; /* Michael MIC key */
|
||||
u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
|
||||
* supports both MIC keys in the same key cache entry;
|
||||
* in that case, kv_mic is the RX key) */
|
||||
};
|
||||
|
||||
enum ath_cipher {
|
||||
ATH_CIPHER_WEP = 0,
|
||||
ATH_CIPHER_AES_OCB = 1,
|
||||
ATH_CIPHER_AES_CCM = 2,
|
||||
ATH_CIPHER_CKIP = 3,
|
||||
ATH_CIPHER_TKIP = 4,
|
||||
ATH_CIPHER_CLR = 5,
|
||||
ATH_CIPHER_MIC = 127
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ath_ops - Register read/write operations
|
||||
*
|
||||
|
@ -120,7 +146,7 @@ struct ath_common {
|
|||
u32 keymax;
|
||||
DECLARE_BITMAP(keymap, ATH_KEYMAX);
|
||||
DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
|
||||
u8 splitmic;
|
||||
enum ath_crypt_caps crypt_caps;
|
||||
|
||||
struct ath_regulatory regulatory;
|
||||
const struct ath_ops *ops;
|
||||
|
@ -132,5 +158,11 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
|||
gfp_t gfp_mask);
|
||||
|
||||
void ath_hw_setbssidmask(struct ath_common *common);
|
||||
void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
|
||||
int ath_key_config(struct ath_common *common,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
bool ath_hw_keyreset(struct ath_common *common, u16 entry);
|
||||
|
||||
#endif /* ATH_H */
|
||||
|
|
|
@ -206,6 +206,8 @@
|
|||
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
|
||||
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */
|
||||
|
||||
#define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */
|
||||
|
||||
#define AR5K_INIT_CARR_SENSE_EN 1
|
||||
|
||||
/*Swap RX/TX Descriptor for big endian archs*/
|
||||
|
@ -256,8 +258,6 @@
|
|||
(AR5K_INIT_PROG_IFS_TURBO) \
|
||||
)
|
||||
|
||||
/* token to use for aifs, cwmin, cwmax in MadWiFi */
|
||||
#define AR5K_TXQ_USEDEFAULT ((u32) -1)
|
||||
|
||||
/* GENERIC CHIPSET DEFINITIONS */
|
||||
|
||||
|
@ -528,9 +528,9 @@ struct ath5k_txq_info {
|
|||
enum ath5k_tx_queue tqi_type;
|
||||
enum ath5k_tx_queue_subtype tqi_subtype;
|
||||
u16 tqi_flags; /* Tx queue flags (see above) */
|
||||
u32 tqi_aifs; /* Arbitrated Interframe Space */
|
||||
s32 tqi_cw_min; /* Minimum Contention Window */
|
||||
s32 tqi_cw_max; /* Maximum Contention Window */
|
||||
u8 tqi_aifs; /* Arbitrated Interframe Space */
|
||||
u16 tqi_cw_min; /* Minimum Contention Window */
|
||||
u16 tqi_cw_max; /* Maximum Contention Window */
|
||||
u32 tqi_cbr_period; /* Constant bit rate period */
|
||||
u32 tqi_cbr_overflow_limit;
|
||||
u32 tqi_burst_time;
|
||||
|
@ -1028,8 +1028,6 @@ struct ath5k_hw {
|
|||
bool ah_turbo;
|
||||
bool ah_calibration;
|
||||
bool ah_single_chip;
|
||||
bool ah_aes_support;
|
||||
bool ah_combined_mic;
|
||||
|
||||
enum ath5k_version ah_version;
|
||||
enum ath5k_radio ah_radio;
|
||||
|
@ -1044,9 +1042,6 @@ struct ath5k_hw {
|
|||
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
|
||||
|
||||
u32 ah_atim_window;
|
||||
u32 ah_aifs;
|
||||
u32 ah_cw_min;
|
||||
u32 ah_cw_max;
|
||||
u32 ah_limit_tx_retries;
|
||||
u8 ah_coverage_class;
|
||||
|
||||
|
@ -1207,11 +1202,6 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
|
|||
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
|
||||
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
|
||||
unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah);
|
||||
/* Key table (WEP) functions */
|
||||
int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
|
||||
int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
|
||||
const struct ieee80211_key_conf *key, const u8 *mac);
|
||||
int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
|
||||
|
||||
/* Queue Control Unit, DFS Control Unit Functions */
|
||||
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
|
||||
|
|
|
@ -119,8 +119,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
|
|||
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
|
||||
ah->ah_imr = 0;
|
||||
ah->ah_atim_window = 0;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS;
|
||||
ah->ah_cw_min = AR5K_TUNE_CWMIN;
|
||||
ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
|
||||
ah->ah_software_retry = false;
|
||||
ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
|
||||
|
@ -314,12 +312,16 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
|
|||
}
|
||||
|
||||
/* Crypto settings */
|
||||
ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
|
||||
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
|
||||
!AR5K_EEPROM_AES_DIS(ee->ee_misc5));
|
||||
common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
|
||||
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
|
||||
|
||||
if (srev >= AR5K_SREV_AR5212_V4 &&
|
||||
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
|
||||
!AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
|
||||
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
|
||||
|
||||
if (srev >= AR5K_SREV_AR2414) {
|
||||
ah->ah_combined_mic = true;
|
||||
common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
|
||||
AR5K_MISC_MODE_COMBINED_MIC);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -60,6 +60,9 @@
|
|||
#define ATH_TXBUF 200 /* number of TX buffers */
|
||||
#define ATH_BCBUF 1 /* number of beacon buffers */
|
||||
|
||||
#define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */
|
||||
#define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */
|
||||
|
||||
struct ath5k_buf {
|
||||
struct list_head list;
|
||||
struct ath5k_desc *desc; /* virtual addr of desc */
|
||||
|
@ -83,6 +86,9 @@ struct ath5k_txq {
|
|||
struct list_head q; /* transmit queue */
|
||||
spinlock_t lock; /* lock on q and link */
|
||||
bool setup;
|
||||
int txq_len; /* number of queued buffers */
|
||||
bool txq_poll_mark;
|
||||
unsigned int txq_stuck; /* informational counter */
|
||||
};
|
||||
|
||||
#define ATH5K_LED_MAX_NAME_LEN 31
|
||||
|
@ -204,7 +210,6 @@ struct ath5k_softc {
|
|||
spinlock_t txbuflock;
|
||||
unsigned int txbuf_len; /* buf count in txbuf list */
|
||||
struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
|
||||
struct ath5k_txq *txq; /* main tx queue */
|
||||
struct tasklet_struct txtq; /* tx intr tasklet */
|
||||
struct ath5k_led tx_led; /* tx led */
|
||||
|
||||
|
@ -230,6 +235,8 @@ struct ath5k_softc {
|
|||
|
||||
struct ath5k_ani_state ani_state;
|
||||
struct tasklet_struct ani_tasklet; /* ANI calibration */
|
||||
|
||||
struct delayed_work tx_complete_work;
|
||||
};
|
||||
|
||||
#define ath5k_hw_hasbssidmask(_ah) \
|
||||
|
|
|
@ -763,7 +763,7 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
|
|||
|
||||
struct ath5k_txq *txq;
|
||||
struct ath5k_buf *bf, *bf0;
|
||||
int i, n = 0;
|
||||
int i, n;
|
||||
|
||||
len += snprintf(buf+len, sizeof(buf)-len,
|
||||
"available txbuffers: %d\n", sc->txbuf_len);
|
||||
|
@ -777,9 +777,16 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
|
|||
if (!txq->setup)
|
||||
continue;
|
||||
|
||||
n = 0;
|
||||
spin_lock_bh(&txq->lock);
|
||||
list_for_each_entry_safe(bf, bf0, &txq->q, list)
|
||||
n++;
|
||||
len += snprintf(buf+len, sizeof(buf)-len, " len: %d\n", n);
|
||||
spin_unlock_bh(&txq->lock);
|
||||
|
||||
len += snprintf(buf+len, sizeof(buf)-len,
|
||||
" len: %d bufs: %d\n", txq->txq_len, n);
|
||||
len += snprintf(buf+len, sizeof(buf)-len,
|
||||
" stuck: %d\n", txq->txq_stuck);
|
||||
}
|
||||
|
||||
if (len > sizeof(buf))
|
||||
|
|
|
@ -640,197 +640,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
|
|||
|
||||
}
|
||||
|
||||
|
||||
/*********************\
|
||||
* Key table functions *
|
||||
\*********************/
|
||||
|
||||
/*
|
||||
* Reset a key entry on the table
|
||||
*/
|
||||
int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
|
||||
{
|
||||
unsigned int i, type;
|
||||
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
|
||||
|
||||
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
|
||||
|
||||
type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
|
||||
|
||||
for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
|
||||
|
||||
/* Reset associated MIC entry if TKIP
|
||||
* is enabled located at offset (entry + 64) */
|
||||
if (type == AR5K_KEYTABLE_TYPE_TKIP) {
|
||||
AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
|
||||
for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
|
||||
ath5k_hw_reg_write(ah, 0,
|
||||
AR5K_KEYTABLE_OFF(micentry, i));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set NULL encryption on AR5212+
|
||||
*
|
||||
* Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
|
||||
* AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
|
||||
*
|
||||
* Note2: Windows driver (ndiswrapper) sets this to
|
||||
* 0x00000714 instead of 0x00000007
|
||||
*/
|
||||
if (ah->ah_version >= AR5K_AR5211) {
|
||||
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
|
||||
AR5K_KEYTABLE_TYPE(entry));
|
||||
|
||||
if (type == AR5K_KEYTABLE_TYPE_TKIP) {
|
||||
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
|
||||
AR5K_KEYTABLE_TYPE(micentry));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int ath5k_keycache_type(const struct ieee80211_key_conf *key)
|
||||
{
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
return AR5K_KEYTABLE_TYPE_TKIP;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
return AR5K_KEYTABLE_TYPE_CCM;
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
return AR5K_KEYTABLE_TYPE_40;
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
return AR5K_KEYTABLE_TYPE_104;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a key entry on the table
|
||||
*/
|
||||
int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
|
||||
const struct ieee80211_key_conf *key, const u8 *mac)
|
||||
{
|
||||
unsigned int i;
|
||||
int keylen;
|
||||
__le32 key_v[5] = {};
|
||||
__le32 key0 = 0, key1 = 0;
|
||||
__le32 *rxmic, *txmic;
|
||||
int keytype;
|
||||
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
|
||||
bool is_tkip;
|
||||
const u8 *key_ptr;
|
||||
|
||||
is_tkip = (key->cipher == WLAN_CIPHER_SUITE_TKIP);
|
||||
|
||||
/*
|
||||
* key->keylen comes in from mac80211 in bytes.
|
||||
* TKIP is 128 bit + 128 bit mic
|
||||
*/
|
||||
keylen = (is_tkip) ? (128 / 8) : key->keylen;
|
||||
|
||||
if (entry > AR5K_KEYTABLE_SIZE ||
|
||||
(is_tkip && micentry > AR5K_KEYTABLE_SIZE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (unlikely(keylen > 16))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
keytype = ath5k_keycache_type(key);
|
||||
if (keytype < 0)
|
||||
return keytype;
|
||||
|
||||
/*
|
||||
* each key block is 6 bytes wide, written as pairs of
|
||||
* alternating 32 and 16 bit le values.
|
||||
*/
|
||||
key_ptr = key->key;
|
||||
for (i = 0; keylen >= 6; keylen -= 6) {
|
||||
memcpy(&key_v[i], key_ptr, 6);
|
||||
i += 2;
|
||||
key_ptr += 6;
|
||||
}
|
||||
if (keylen)
|
||||
memcpy(&key_v[i], key_ptr, keylen);
|
||||
|
||||
/* intentionally corrupt key until mic is installed */
|
||||
if (is_tkip) {
|
||||
key0 = key_v[0] = ~key_v[0];
|
||||
key1 = key_v[1] = ~key_v[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_v); i++)
|
||||
ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
|
||||
AR5K_KEYTABLE_OFF(entry, i));
|
||||
|
||||
ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
|
||||
|
||||
if (is_tkip) {
|
||||
/* Install rx/tx MIC */
|
||||
rxmic = (__le32 *) &key->key[16];
|
||||
txmic = (__le32 *) &key->key[24];
|
||||
|
||||
if (ah->ah_combined_mic) {
|
||||
key_v[0] = rxmic[0];
|
||||
key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
|
||||
key_v[2] = rxmic[1];
|
||||
key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
|
||||
key_v[4] = txmic[1];
|
||||
} else {
|
||||
key_v[0] = rxmic[0];
|
||||
key_v[1] = 0;
|
||||
key_v[2] = rxmic[1];
|
||||
key_v[3] = 0;
|
||||
key_v[4] = 0;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(key_v); i++)
|
||||
ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
|
||||
AR5K_KEYTABLE_OFF(micentry, i));
|
||||
|
||||
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
|
||||
AR5K_KEYTABLE_TYPE(micentry));
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
|
||||
|
||||
/* restore first 2 words of key */
|
||||
ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
|
||||
AR5K_KEYTABLE_OFF(entry, 0));
|
||||
ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
|
||||
AR5K_KEYTABLE_OFF(entry, 1));
|
||||
}
|
||||
|
||||
return ath5k_hw_set_key_lladdr(ah, entry, mac);
|
||||
}
|
||||
|
||||
int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
|
||||
{
|
||||
u32 low_id, high_id;
|
||||
|
||||
/* Invalid entry (key table overflow) */
|
||||
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
|
||||
|
||||
/*
|
||||
* MAC may be NULL if it's a broadcast key. In this case no need to
|
||||
* to compute get_unaligned_le32 and get_unaligned_le16 as we
|
||||
* already know it.
|
||||
*/
|
||||
if (!mac) {
|
||||
low_id = 0xffffffff;
|
||||
high_id = 0xffff | AR5K_KEYTABLE_VALID;
|
||||
} else {
|
||||
low_id = get_unaligned_le32(mac);
|
||||
high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
|
||||
}
|
||||
|
||||
ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
|
||||
ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
|
||||
*
|
||||
|
|
|
@ -1377,7 +1377,7 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
|
|||
|
||||
/* protect against divide by 0 and loss of sign bits */
|
||||
if (i_coffd == 0 || q_coffd < 2)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
i_coff = (-iq_corr) / i_coffd;
|
||||
i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
|
||||
|
|
|
@ -35,25 +35,59 @@ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure cw is a power of 2 minus 1 and smaller than 1024
|
||||
*/
|
||||
static u16 ath5k_cw_validate(u16 cw_req)
|
||||
{
|
||||
u32 cw = 1;
|
||||
cw_req = min(cw_req, (u16)1023);
|
||||
|
||||
while (cw < cw_req)
|
||||
cw = (cw << 1) | 1;
|
||||
|
||||
return cw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set properties for a transmit queue
|
||||
*/
|
||||
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
|
||||
const struct ath5k_txq_info *queue_info)
|
||||
const struct ath5k_txq_info *qinfo)
|
||||
{
|
||||
struct ath5k_txq_info *qi;
|
||||
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
qi = &ah->ah_txq[queue];
|
||||
|
||||
if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
return -EIO;
|
||||
|
||||
memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
|
||||
/* copy and validate values */
|
||||
qi->tqi_type = qinfo->tqi_type;
|
||||
qi->tqi_subtype = qinfo->tqi_subtype;
|
||||
qi->tqi_flags = qinfo->tqi_flags;
|
||||
/*
|
||||
* According to the docs: Although the AIFS field is 8 bit wide,
|
||||
* the maximum supported value is 0xFC. Setting it higher than that
|
||||
* will cause the DCU to hang.
|
||||
*/
|
||||
qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
|
||||
qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
|
||||
qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
|
||||
qi->tqi_cbr_period = qinfo->tqi_cbr_period;
|
||||
qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
|
||||
qi->tqi_burst_time = qinfo->tqi_burst_time;
|
||||
qi->tqi_ready_time = qinfo->tqi_ready_time;
|
||||
|
||||
/*XXX: Is this supported on 5210 ?*/
|
||||
if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
|
||||
((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
|
||||
(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
|
||||
queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
|
||||
ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
|
||||
/*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
|
||||
if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
|
||||
((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
|
||||
(qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
|
||||
qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
|
||||
qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -186,7 +220,7 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
*/
|
||||
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
u32 cw_min, cw_max, retry_lg, retry_sh;
|
||||
u32 retry_lg, retry_sh;
|
||||
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
|
||||
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
@ -217,14 +251,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
/* Set IFS0 */
|
||||
if (ah->ah_turbo) {
|
||||
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
|
||||
(ah->ah_aifs + tq->tqi_aifs) *
|
||||
AR5K_INIT_SLOT_TIME_TURBO) <<
|
||||
tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
|
||||
AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
|
||||
AR5K_IFS0);
|
||||
} else {
|
||||
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
|
||||
(ah->ah_aifs + tq->tqi_aifs) *
|
||||
AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
|
||||
tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
|
||||
AR5K_IFS0_DIFS_S) |
|
||||
AR5K_INIT_SIFS, AR5K_IFS0);
|
||||
}
|
||||
|
||||
|
@ -247,35 +280,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
AR5K_PHY_FRAME_CTL_5210);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate cwmin/max by channel mode
|
||||
*/
|
||||
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
|
||||
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS;
|
||||
/*XR is only supported on 5212*/
|
||||
if (IS_CHAN_XR(ah->ah_current_channel) &&
|
||||
ah->ah_version == AR5K_AR5212) {
|
||||
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
|
||||
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS_XR;
|
||||
/*B mode is not supported on 5210*/
|
||||
} else if (IS_CHAN_B(ah->ah_current_channel) &&
|
||||
ah->ah_version != AR5K_AR5210) {
|
||||
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
|
||||
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS_11B;
|
||||
}
|
||||
|
||||
cw_min = 1;
|
||||
while (cw_min < ah->ah_cw_min)
|
||||
cw_min = (cw_min << 1) | 1;
|
||||
|
||||
cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
|
||||
((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
|
||||
cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
|
||||
((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
|
||||
|
||||
/*
|
||||
* Calculate and set retry limits
|
||||
*/
|
||||
|
@ -292,7 +296,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
/*No QCU/DCU [5210]*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
ath5k_hw_reg_write(ah,
|
||||
(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
|
||||
(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
|
||||
| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
|
||||
AR5K_NODCU_RETRY_LMT_SLG_RETRY)
|
||||
| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
|
||||
|
@ -314,14 +318,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
/*===Rest is also for QCU/DCU only [5211+]===*/
|
||||
|
||||
/*
|
||||
* Set initial content window (cw_min/cw_max)
|
||||
* Set contention window (cw_min/cw_max)
|
||||
* and arbitrated interframe space (aifs)...
|
||||
*/
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
|
||||
AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
|
||||
AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
|
||||
AR5K_DCU_LCL_IFS_AIFS),
|
||||
AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
|
||||
AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
|
||||
AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
|
||||
AR5K_QUEUE_DFS_LOCAL_IFS(queue));
|
||||
|
||||
/*
|
||||
|
|
|
@ -1822,50 +1822,8 @@
|
|||
|
||||
/*===5212 end===*/
|
||||
|
||||
/*
|
||||
* Key table (WEP) register
|
||||
*/
|
||||
#define AR5K_KEYTABLE_0_5210 0x9000
|
||||
#define AR5K_KEYTABLE_0_5211 0x8800
|
||||
#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5))
|
||||
#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5))
|
||||
#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \
|
||||
AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
|
||||
#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2))
|
||||
#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5)
|
||||
#define AR5K_KEYTABLE_TYPE_40 0x00000000
|
||||
#define AR5K_KEYTABLE_TYPE_104 0x00000001
|
||||
#define AR5K_KEYTABLE_TYPE_128 0x00000003
|
||||
#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */
|
||||
#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */
|
||||
#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */
|
||||
#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */
|
||||
#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */
|
||||
#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6)
|
||||
#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7)
|
||||
#define AR5K_KEYTABLE_VALID 0x00008000
|
||||
|
||||
/* If key type is TKIP and MIC is enabled
|
||||
* MIC key goes in offset entry + 64 */
|
||||
#define AR5K_KEYTABLE_MIC_OFFSET 64
|
||||
|
||||
/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit
|
||||
* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit
|
||||
* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit
|
||||
*
|
||||
* Some vendors have introduced bigger WEP keys to address
|
||||
* security vulnerabilities in WEP. This includes:
|
||||
*
|
||||
* WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
|
||||
*
|
||||
* We can expand this if we find ar5k Atheros cards with a larger
|
||||
* key table size.
|
||||
*/
|
||||
#define AR5K_KEYTABLE_SIZE_5210 64
|
||||
#define AR5K_KEYTABLE_SIZE_5211 128
|
||||
#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \
|
||||
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
|
||||
|
||||
|
||||
/*===PHY REGISTERS===*/
|
||||
|
||||
|
|
|
@ -32,6 +32,14 @@ config ATH9K_DEBUGFS
|
|||
|
||||
Also required for changing debug message flags at run time.
|
||||
|
||||
config ATH9K_RATE_CONTROL
|
||||
bool "Atheros ath9k rate control"
|
||||
depends on ATH9K
|
||||
default y
|
||||
---help---
|
||||
Say Y, if you want to use the ath9k specific rate control
|
||||
module instead of minstrel_ht.
|
||||
|
||||
config ATH9K_HTC
|
||||
tristate "Atheros HTC based wireless cards support"
|
||||
depends on USB && MAC80211
|
||||
|
|
|
@ -5,8 +5,8 @@ ath9k-y += beacon.o \
|
|||
recv.o \
|
||||
xmit.o \
|
||||
virtual.o \
|
||||
rc.o
|
||||
|
||||
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
|
||||
ath9k-$(CONFIG_PCI) += pci.o
|
||||
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
|
||||
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "hw.h"
|
||||
#include "hw-ops.h"
|
||||
|
||||
|
@ -48,7 +49,7 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = {
|
|||
{ 7, 8, 0 } /* lvl 9 */
|
||||
};
|
||||
#define ATH9K_ANI_OFDM_NUM_LEVEL \
|
||||
(sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0]))
|
||||
ARRAY_SIZE(ofdm_level_table)
|
||||
#define ATH9K_ANI_OFDM_MAX_LEVEL \
|
||||
(ATH9K_ANI_OFDM_NUM_LEVEL-1)
|
||||
#define ATH9K_ANI_OFDM_DEF_LEVEL \
|
||||
|
@ -94,7 +95,7 @@ static const struct ani_cck_level_entry cck_level_table[] = {
|
|||
};
|
||||
|
||||
#define ATH9K_ANI_CCK_NUM_LEVEL \
|
||||
(sizeof(cck_level_table)/sizeof(cck_level_table[0]))
|
||||
ARRAY_SIZE(cck_level_table)
|
||||
#define ATH9K_ANI_CCK_MAX_LEVEL \
|
||||
(ATH9K_ANI_CCK_NUM_LEVEL-1)
|
||||
#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
|
||||
|
|
|
@ -580,3 +580,53 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
|
|||
else
|
||||
ath9k_hw_attach_ani_ops_old(ah);
|
||||
}
|
||||
|
||||
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
u32 modesIndex;
|
||||
int i;
|
||||
|
||||
switch (chan->chanmode) {
|
||||
case CHANNEL_A:
|
||||
case CHANNEL_A_HT20:
|
||||
modesIndex = 1;
|
||||
break;
|
||||
case CHANNEL_A_HT40PLUS:
|
||||
case CHANNEL_A_HT40MINUS:
|
||||
modesIndex = 2;
|
||||
break;
|
||||
case CHANNEL_G:
|
||||
case CHANNEL_G_HT20:
|
||||
case CHANNEL_B:
|
||||
modesIndex = 4;
|
||||
break;
|
||||
case CHANNEL_G_HT40PLUS:
|
||||
case CHANNEL_G_HT40MINUS:
|
||||
modesIndex = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
for (i = 0; i < ah->iniModes_9271_ANI_reg.ia_rows; i++) {
|
||||
u32 reg = INI_RA(&ah->iniModes_9271_ANI_reg, i, 0);
|
||||
u32 val = INI_RA(&ah->iniModes_9271_ANI_reg, i, modesIndex);
|
||||
u32 val_orig;
|
||||
|
||||
if (reg == AR_PHY_CCK_DETECT) {
|
||||
val_orig = REG_READ(ah, reg);
|
||||
val &= AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
|
||||
val_orig &= ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
|
||||
|
||||
REG_WRITE(ah, reg, val|val_orig);
|
||||
} else
|
||||
REG_WRITE(ah, reg, val);
|
||||
}
|
||||
|
||||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
DISABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
}
|
||||
|
|
|
@ -530,3 +530,38 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
|
|||
|
||||
ar9002_hw_set_nf_limits(ah);
|
||||
}
|
||||
|
||||
void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
|
||||
struct ath_hw_antcomb_conf *antconf)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
|
||||
antconf->main_lna_conf = (regval & AR_PHY_9285_ANT_DIV_MAIN_LNACONF) >>
|
||||
AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S;
|
||||
antconf->alt_lna_conf = (regval & AR_PHY_9285_ANT_DIV_ALT_LNACONF) >>
|
||||
AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
|
||||
antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
|
||||
AR_PHY_9285_FAST_DIV_BIAS_S;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get);
|
||||
|
||||
void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
|
||||
struct ath_hw_antcomb_conf *antconf)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
|
||||
regval &= ~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
|
||||
AR_PHY_9285_ANT_DIV_ALT_LNACONF |
|
||||
AR_PHY_9285_FAST_DIV_BIAS);
|
||||
regval |= ((antconf->main_lna_conf << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S)
|
||||
& AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
|
||||
regval |= ((antconf->alt_lna_conf << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S)
|
||||
& AR_PHY_9285_ANT_DIV_ALT_LNACONF);
|
||||
regval |= ((antconf->fast_div_bias << AR_PHY_9285_FAST_DIV_BIAS_S)
|
||||
& AR_PHY_9285_FAST_DIV_BIAS);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set);
|
||||
|
|
|
@ -302,6 +302,8 @@
|
|||
#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
|
||||
|
||||
#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
|
||||
#define AR_PHY_9285_FAST_DIV_BIAS 0x00007E00
|
||||
#define AR_PHY_9285_FAST_DIV_BIAS_S 9
|
||||
#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
|
||||
#define AR_PHY_9285_ANT_DIV_CTL 0x01000000
|
||||
#define AR_PHY_9285_ANT_DIV_CTL_S 24
|
||||
|
|
|
@ -968,7 +968,7 @@ static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah)
|
|||
}
|
||||
|
||||
static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
|
||||
enum ieee80211_band freq_band)
|
||||
enum ath9k_hal_freq_band freq_band)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -616,7 +616,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
|
|||
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
} else if (rxsp->status11 & AR_MichaelErr) {
|
||||
rxs->rs_status |= ATH9K_RXERR_MIC;
|
||||
}
|
||||
} else if (rxsp->status11 & AR_KeyMiss)
|
||||
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -254,7 +254,7 @@ struct ath_atx_tid {
|
|||
struct list_head buf_q;
|
||||
struct ath_node *an;
|
||||
struct ath_atx_ac *ac;
|
||||
struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
|
||||
unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
|
||||
u16 seq_start;
|
||||
u16 seq_next;
|
||||
u16 baw_size;
|
||||
|
@ -345,9 +345,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|||
void ath_tx_tasklet(struct ath_softc *sc);
|
||||
void ath_tx_edma_tasklet(struct ath_softc *sc);
|
||||
void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
|
||||
void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn);
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn);
|
||||
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
void ath9k_enable_ps(struct ath_softc *sc);
|
||||
|
@ -481,6 +480,60 @@ struct ath_led {
|
|||
void ath_init_leds(struct ath_softc *sc);
|
||||
void ath_deinit_leds(struct ath_softc *sc);
|
||||
|
||||
/* Antenna diversity/combining */
|
||||
#define ATH_ANT_RX_CURRENT_SHIFT 4
|
||||
#define ATH_ANT_RX_MAIN_SHIFT 2
|
||||
#define ATH_ANT_RX_MASK 0x3
|
||||
|
||||
#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
|
||||
#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
|
||||
#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
|
||||
#define ATH_ANT_DIV_COMB_INIT_COUNT 95
|
||||
#define ATH_ANT_DIV_COMB_MAX_COUNT 100
|
||||
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
|
||||
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
|
||||
|
||||
#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
|
||||
#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
|
||||
#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
|
||||
#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
|
||||
#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
|
||||
|
||||
enum ath9k_ant_div_comb_lna_conf {
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
|
||||
ATH_ANT_DIV_COMB_LNA2,
|
||||
ATH_ANT_DIV_COMB_LNA1,
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
|
||||
};
|
||||
|
||||
struct ath_ant_comb {
|
||||
u16 count;
|
||||
u16 total_pkt_count;
|
||||
bool scan;
|
||||
bool scan_not_start;
|
||||
int main_total_rssi;
|
||||
int alt_total_rssi;
|
||||
int alt_recv_cnt;
|
||||
int main_recv_cnt;
|
||||
int rssi_lna1;
|
||||
int rssi_lna2;
|
||||
int rssi_add;
|
||||
int rssi_sub;
|
||||
int rssi_first;
|
||||
int rssi_second;
|
||||
int rssi_third;
|
||||
bool alt_good;
|
||||
int quick_scan_cnt;
|
||||
int main_conf;
|
||||
enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
|
||||
enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
|
||||
int first_bias;
|
||||
int second_bias;
|
||||
bool first_ratio;
|
||||
bool second_ratio;
|
||||
unsigned long scan_start_time;
|
||||
};
|
||||
|
||||
/********************/
|
||||
/* Main driver core */
|
||||
/********************/
|
||||
|
@ -509,7 +562,6 @@ void ath_deinit_leds(struct ath_softc *sc);
|
|||
#define SC_OP_RXFLUSH BIT(7)
|
||||
#define SC_OP_LED_ASSOCIATED BIT(8)
|
||||
#define SC_OP_LED_ON BIT(9)
|
||||
#define SC_OP_SCANNING BIT(10)
|
||||
#define SC_OP_TSF_RESET BIT(11)
|
||||
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
|
||||
#define SC_OP_BT_SCAN BIT(13)
|
||||
|
@ -597,6 +649,8 @@ struct ath_softc {
|
|||
struct ath_btcoex btcoex;
|
||||
|
||||
struct ath_descdma txsdma;
|
||||
|
||||
struct ath_ant_comb ant_comb;
|
||||
};
|
||||
|
||||
struct ath_wiphy {
|
||||
|
@ -663,7 +717,7 @@ static inline void ath_ahb_exit(void) {};
|
|||
void ath9k_ps_wakeup(struct ath_softc *sc);
|
||||
void ath9k_ps_restore(struct ath_softc *sc);
|
||||
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
int ath9k_wiphy_add(struct ath_softc *sc);
|
||||
int ath9k_wiphy_del(struct ath_wiphy *aphy);
|
||||
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
|
|
|
@ -148,276 +148,6 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
|
|||
}
|
||||
EXPORT_SYMBOL(ath9k_cmn_get_curchannel);
|
||||
|
||||
static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
|
||||
struct ath9k_keyval *hk, const u8 *addr,
|
||||
bool authenticator)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
const u8 *key_rxmic;
|
||||
const u8 *key_txmic;
|
||||
|
||||
key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
|
||||
key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
|
||||
|
||||
if (addr == NULL) {
|
||||
/*
|
||||
* Group key installation - only two key cache entries are used
|
||||
* regardless of splitmic capability since group key is only
|
||||
* used either for TX or RX.
|
||||
*/
|
||||
if (authenticator) {
|
||||
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
|
||||
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
|
||||
} else {
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
|
||||
}
|
||||
return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
|
||||
}
|
||||
if (!common->splitmic) {
|
||||
/* TX and RX keys share the same key cache entry. */
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
|
||||
return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
|
||||
}
|
||||
|
||||
/* Separate key cache entries for TX and RX */
|
||||
|
||||
/* TX key goes at first index, RX key at +32. */
|
||||
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
|
||||
if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
|
||||
/* TX MIC entry failed. No need to proceed further */
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Setting TX MIC Key Failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
/* XXX delete tx key on failure? */
|
||||
return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
|
||||
}
|
||||
|
||||
static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
|
||||
if (test_bit(i, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap))
|
||||
continue; /* At least one part of TKIP key allocated */
|
||||
if (common->splitmic &&
|
||||
(test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
continue; /* At least one part of TKIP key allocated */
|
||||
|
||||
/* Found a free slot for a TKIP key */
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ath_reserve_key_cache_slot(struct ath_common *common,
|
||||
u32 cipher)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
return ath_reserve_key_cache_slot_tkip(common);
|
||||
|
||||
/* First, try to find slots that would not be available for TKIP. */
|
||||
if (common->splitmic) {
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
|
||||
if (!test_bit(i, common->keymap) &&
|
||||
(test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
return i;
|
||||
if (!test_bit(i + 32, common->keymap) &&
|
||||
(test_bit(i, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
return i + 32;
|
||||
if (!test_bit(i + 64, common->keymap) &&
|
||||
(test_bit(i , common->keymap) ||
|
||||
test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
return i + 64;
|
||||
if (!test_bit(i + 64 + 32, common->keymap) &&
|
||||
(test_bit(i, common->keymap) ||
|
||||
test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap)))
|
||||
return i + 64 + 32;
|
||||
}
|
||||
} else {
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
|
||||
if (!test_bit(i, common->keymap) &&
|
||||
test_bit(i + 64, common->keymap))
|
||||
return i;
|
||||
if (test_bit(i, common->keymap) &&
|
||||
!test_bit(i + 64, common->keymap))
|
||||
return i + 64;
|
||||
}
|
||||
}
|
||||
|
||||
/* No partially used TKIP slots, pick any available slot */
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
|
||||
/* Do not allow slots that could be needed for TKIP group keys
|
||||
* to be used. This limitation could be removed if we know that
|
||||
* TKIP will not be used. */
|
||||
if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
|
||||
continue;
|
||||
if (common->splitmic) {
|
||||
if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
|
||||
continue;
|
||||
if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!test_bit(i, common->keymap))
|
||||
return i; /* Found a free slot for a key */
|
||||
}
|
||||
|
||||
/* No free slot found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure encryption in the HW.
|
||||
*/
|
||||
int ath9k_cmn_key_config(struct ath_common *common,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
struct ath9k_keyval hk;
|
||||
const u8 *mac = NULL;
|
||||
u8 gmac[ETH_ALEN];
|
||||
int ret = 0;
|
||||
int idx;
|
||||
|
||||
memset(&hk, 0, sizeof(hk));
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
hk.kv_type = ATH9K_CIPHER_WEP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
hk.kv_type = ATH9K_CIPHER_TKIP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
hk.kv_type = ATH9K_CIPHER_AES_CCM;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
hk.kv_len = key->keylen;
|
||||
memcpy(hk.kv_val, key->key, key->keylen);
|
||||
|
||||
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
memcpy(gmac, vif->addr, ETH_ALEN);
|
||||
gmac[0] |= 0x01;
|
||||
mac = gmac;
|
||||
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!sta) {
|
||||
idx = key->keyidx;
|
||||
break;
|
||||
}
|
||||
memcpy(gmac, sta->addr, ETH_ALEN);
|
||||
gmac[0] |= 0x01;
|
||||
mac = gmac;
|
||||
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||
break;
|
||||
default:
|
||||
idx = key->keyidx;
|
||||
break;
|
||||
}
|
||||
} else if (key->keyidx) {
|
||||
if (WARN_ON(!sta))
|
||||
return -EOPNOTSUPP;
|
||||
mac = sta->addr;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_AP) {
|
||||
/* Only keyidx 0 should be used with unicast key, but
|
||||
* allow this for client mode for now. */
|
||||
idx = key->keyidx;
|
||||
} else
|
||||
return -EIO;
|
||||
} else {
|
||||
if (WARN_ON(!sta))
|
||||
return -EOPNOTSUPP;
|
||||
mac = sta->addr;
|
||||
|
||||
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||
}
|
||||
|
||||
if (idx < 0)
|
||||
return -ENOSPC; /* no free key cache entries */
|
||||
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
|
||||
vif->type == NL80211_IFTYPE_AP);
|
||||
else
|
||||
ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
|
||||
|
||||
if (!ret)
|
||||
return -EIO;
|
||||
|
||||
set_bit(idx, common->keymap);
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||
set_bit(idx + 64, common->keymap);
|
||||
set_bit(idx, common->tkip_keymap);
|
||||
set_bit(idx + 64, common->tkip_keymap);
|
||||
if (common->splitmic) {
|
||||
set_bit(idx + 32, common->keymap);
|
||||
set_bit(idx + 64 + 32, common->keymap);
|
||||
set_bit(idx + 32, common->tkip_keymap);
|
||||
set_bit(idx + 64 + 32, common->tkip_keymap);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_cmn_key_config);
|
||||
|
||||
/*
|
||||
* Delete Key.
|
||||
*/
|
||||
void ath9k_cmn_key_delete(struct ath_common *common,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
|
||||
ath9k_hw_keyreset(ah, key->hw_key_idx);
|
||||
if (key->hw_key_idx < IEEE80211_WEP_NKID)
|
||||
return;
|
||||
|
||||
clear_bit(key->hw_key_idx, common->keymap);
|
||||
if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
|
||||
return;
|
||||
|
||||
clear_bit(key->hw_key_idx + 64, common->keymap);
|
||||
|
||||
clear_bit(key->hw_key_idx, common->tkip_keymap);
|
||||
clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
|
||||
|
||||
if (common->splitmic) {
|
||||
ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
|
||||
clear_bit(key->hw_key_idx + 32, common->keymap);
|
||||
clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
|
||||
|
||||
clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
|
||||
clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_cmn_key_delete);
|
||||
|
||||
int ath9k_cmn_count_streams(unsigned int chainmask, int max)
|
||||
{
|
||||
int streams = 0;
|
||||
|
|
|
@ -66,12 +66,6 @@ void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
|
|||
struct ath9k_channel *ichan);
|
||||
struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
|
||||
struct ath_hw *ah);
|
||||
int ath9k_cmn_key_config(struct ath_common *common,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
void ath9k_cmn_key_delete(struct ath_common *common,
|
||||
struct ieee80211_key_conf *key);
|
||||
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
|
||||
void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
|
||||
enum ath_stomp_type stomp_type);
|
||||
|
|
|
@ -492,12 +492,55 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
|
|||
unsigned int len = 0;
|
||||
int i;
|
||||
u8 addr[ETH_ALEN];
|
||||
u32 tmp;
|
||||
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"primary: %s (%s chan=%d ht=%d)\n",
|
||||
wiphy_name(sc->pri_wiphy->hw->wiphy),
|
||||
ath_wiphy_state_str(sc->pri_wiphy->state),
|
||||
sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht);
|
||||
|
||||
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
|
||||
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"addr: %pM\n", addr);
|
||||
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
|
||||
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"addrmask: %pM\n", addr);
|
||||
tmp = ath9k_hw_getrxfilter(sc->sc_ah);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"rfilt: 0x%x", tmp);
|
||||
if (tmp & ATH9K_RX_FILTER_UCAST)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
|
||||
if (tmp & ATH9K_RX_FILTER_MCAST)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
|
||||
if (tmp & ATH9K_RX_FILTER_BCAST)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
|
||||
if (tmp & ATH9K_RX_FILTER_CONTROL)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
|
||||
if (tmp & ATH9K_RX_FILTER_BEACON)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
|
||||
if (tmp & ATH9K_RX_FILTER_PROM)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " PROM");
|
||||
if (tmp & ATH9K_RX_FILTER_PROBEREQ)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
|
||||
if (tmp & ATH9K_RX_FILTER_PHYERR)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
|
||||
if (tmp & ATH9K_RX_FILTER_MYBEACON)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
|
||||
if (tmp & ATH9K_RX_FILTER_COMP_BAR)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
|
||||
if (tmp & ATH9K_RX_FILTER_PSPOLL)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
|
||||
if (tmp & ATH9K_RX_FILTER_PHYRADAR)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
|
||||
if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n");
|
||||
else
|
||||
len += snprintf(buf + len, sizeof(buf) - len, "\n");
|
||||
|
||||
/* Put variable-length stuff down here, and check for overflows. */
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (aphy == NULL)
|
||||
|
@ -508,16 +551,6 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
|
|||
ath_wiphy_state_str(aphy->state),
|
||||
aphy->chan_idx, aphy->chan_is_ht);
|
||||
}
|
||||
|
||||
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
|
||||
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"addr: %pM\n", addr);
|
||||
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
|
||||
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"addrmask: %pM\n", addr);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
|
|
|
@ -266,6 +266,8 @@ enum eeprom_param {
|
|||
EEP_INTERNAL_REGULATOR,
|
||||
EEP_SWREG,
|
||||
EEP_PAPRD,
|
||||
EEP_MODAL_VER,
|
||||
EEP_ANT_DIV_CTL1,
|
||||
};
|
||||
|
||||
enum ar5416_rates {
|
||||
|
@ -670,7 +672,8 @@ struct eeprom_ops {
|
|||
bool (*fill_eeprom)(struct ath_hw *hw);
|
||||
int (*get_eeprom_ver)(struct ath_hw *hw);
|
||||
int (*get_eeprom_rev)(struct ath_hw *hw);
|
||||
u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
|
||||
u8 (*get_num_ant_config)(struct ath_hw *hw,
|
||||
enum ath9k_hal_freq_band band);
|
||||
u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
|
||||
struct ath9k_channel *chan);
|
||||
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
|
||||
|
|
|
@ -213,6 +213,10 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
|
|||
return 0;
|
||||
case EEP_PWR_TABLE_OFFSET:
|
||||
return AR5416_PWR_TABLE_OFFSET_DB;
|
||||
case EEP_MODAL_VER:
|
||||
return pModal->version;
|
||||
case EEP_ANT_DIV_CTL1:
|
||||
return pModal->antdiv_ctl1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -1157,7 +1161,7 @@ static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
|
||||
enum ieee80211_band freq_band)
|
||||
enum ath9k_hal_freq_band freq_band)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1126,7 +1126,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
|
||||
enum ieee80211_band freq_band)
|
||||
enum ath9k_hal_freq_band freq_band)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1418,11 +1418,11 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
|
||||
enum ieee80211_band freq_band)
|
||||
enum ath9k_hal_freq_band freq_band)
|
||||
{
|
||||
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
|
||||
struct modal_eep_header *pModal =
|
||||
&(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
|
||||
&(eep->modalHeader[freq_band]);
|
||||
struct base_eep_header *pBase = &eep->baseEepHeader;
|
||||
u8 num_ant_config;
|
||||
|
||||
|
|
|
@ -92,10 +92,10 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
|
|||
cmd->skb = skb;
|
||||
cmd->hif_dev = hif_dev;
|
||||
|
||||
usb_fill_int_urb(urb, hif_dev->udev,
|
||||
usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE),
|
||||
usb_fill_bulk_urb(urb, hif_dev->udev,
|
||||
usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE),
|
||||
skb->data, skb->len,
|
||||
hif_usb_regout_cb, cmd, 1);
|
||||
hif_usb_regout_cb, cmd);
|
||||
|
||||
usb_anchor_urb(urb, &hif_dev->regout_submitted);
|
||||
ret = usb_submit_urb(urb, GFP_KERNEL);
|
||||
|
@ -541,7 +541,8 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
|
|||
}
|
||||
|
||||
usb_fill_int_urb(urb, hif_dev->udev,
|
||||
usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
|
||||
usb_rcvbulkpipe(hif_dev->udev,
|
||||
USB_REG_IN_PIPE),
|
||||
nskb->data, MAX_REG_IN_BUF_SIZE,
|
||||
ath9k_hif_usb_reg_in_cb, nskb, 1);
|
||||
|
||||
|
@ -720,7 +721,8 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
|
|||
goto err;
|
||||
|
||||
usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev,
|
||||
usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
|
||||
usb_rcvbulkpipe(hif_dev->udev,
|
||||
USB_REG_IN_PIPE),
|
||||
skb->data, MAX_REG_IN_BUF_SIZE,
|
||||
ath9k_hif_usb_reg_in_cb, skb, 1);
|
||||
|
||||
|
@ -822,7 +824,9 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
|
|||
|
||||
static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
|
||||
{
|
||||
int ret;
|
||||
int ret, idx;
|
||||
struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
|
||||
struct usb_endpoint_descriptor *endp;
|
||||
|
||||
/* Request firmware */
|
||||
ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
|
||||
|
@ -850,6 +854,22 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
|
|||
goto err_fw_download;
|
||||
}
|
||||
|
||||
/* On downloading the firmware to the target, the USB descriptor of EP4
|
||||
* is 'patched' to change the type of the endpoint to Bulk. This will
|
||||
* bring down CPU usage during the scan period.
|
||||
*/
|
||||
for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
|
||||
endp = &alt->endpoint[idx].desc;
|
||||
if (((endp->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
|
||||
== 0x04) &&
|
||||
((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_INT)) {
|
||||
endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
|
||||
endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
|
||||
endp->bInterval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_fw_download:
|
||||
|
|
|
@ -566,7 +566,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
|
|||
* reset the contents on initial power up.
|
||||
*/
|
||||
for (i = 0; i < common->keymax; i++)
|
||||
ath9k_hw_keyreset(priv->ah, (u16) i);
|
||||
ath_hw_keyreset(common, (u16) i);
|
||||
}
|
||||
|
||||
static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
|
||||
|
@ -601,8 +601,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
|
|||
common->tx_chainmask = priv->ah->caps.tx_chainmask;
|
||||
common->rx_chainmask = priv->ah->caps.rx_chainmask;
|
||||
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
|
||||
priv->ah->opmode = NL80211_IFTYPE_STATION;
|
||||
}
|
||||
|
|
|
@ -137,8 +137,6 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
|
|||
if (priv->op_flags & OP_FULL_RESET)
|
||||
fastcc = false;
|
||||
|
||||
/* Fiddle around with fastcc later on, for now just use full reset */
|
||||
fastcc = false;
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
htc_stop(priv->htc);
|
||||
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||
|
@ -146,9 +144,10 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
|
|||
WMI_CMD(WMI_STOP_RECV_CMDID);
|
||||
|
||||
ath_print(common, ATH_DBG_CONFIG,
|
||||
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
|
||||
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
|
||||
priv->ah->curchan->channel,
|
||||
channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
|
||||
channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
|
||||
fastcc);
|
||||
|
||||
caldata = &priv->caldata[channel->hw_value];
|
||||
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
|
||||
|
@ -1591,7 +1590,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
|
|||
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
ret = ath9k_cmn_key_config(common, vif, sta, key);
|
||||
ret = ath_key_config(common, vif, sta, key);
|
||||
if (ret >= 0) {
|
||||
key->hw_key_idx = ret;
|
||||
/* push IV and Michael MIC generation to stack */
|
||||
|
@ -1605,7 +1604,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
|
|||
}
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
ath9k_cmn_key_delete(common, key);
|
||||
ath_key_delete(common, key);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -415,8 +415,7 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
|
|||
ath9k_hw_setrxfilter(ah, rfilt);
|
||||
|
||||
/* configure bssid mask */
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
ath_hw_setbssidmask(common);
|
||||
ath_hw_setbssidmask(common);
|
||||
|
||||
/* configure operational mode */
|
||||
ath9k_hw_setopmode(ah);
|
||||
|
|
|
@ -1258,11 +1258,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
(chan->channel != ah->curchan->channel) &&
|
||||
((chan->channelFlags & CHANNEL_ALL) ==
|
||||
(ah->curchan->channelFlags & CHANNEL_ALL)) &&
|
||||
!AR_SREV_9280(ah)) {
|
||||
(!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) {
|
||||
|
||||
if (ath9k_hw_channel_change(ah, chan)) {
|
||||
ath9k_hw_loadnf(ah, ah->curchan);
|
||||
ath9k_hw_start_nfcal(ah, true);
|
||||
if (AR_SREV_9271(ah))
|
||||
ar9002_hw_load_ani_reg(ah, chan);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1474,283 +1476,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_reset);
|
||||
|
||||
/************************/
|
||||
/* Key Cache Management */
|
||||
/************************/
|
||||
|
||||
bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
|
||||
{
|
||||
u32 keyType;
|
||||
|
||||
if (entry >= ah->caps.keycache_size) {
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
|
||||
"keychache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
|
||||
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
|
||||
|
||||
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
|
||||
u16 micentry = entry + 64;
|
||||
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_keyreset);
|
||||
|
||||
static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
|
||||
{
|
||||
u32 macHi, macLo;
|
||||
u32 unicast_flag = AR_KEYTABLE_VALID;
|
||||
|
||||
if (entry >= ah->caps.keycache_size) {
|
||||
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
|
||||
"keychache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mac != NULL) {
|
||||
/*
|
||||
* AR_KEYTABLE_VALID indicates that the address is a unicast
|
||||
* address, which must match the transmitter address for
|
||||
* decrypting frames.
|
||||
* Not setting this bit allows the hardware to use the key
|
||||
* for multicast frame decryption.
|
||||
*/
|
||||
if (mac[0] & 0x01)
|
||||
unicast_flag = 0;
|
||||
|
||||
macHi = (mac[5] << 8) | mac[4];
|
||||
macLo = (mac[3] << 24) |
|
||||
(mac[2] << 16) |
|
||||
(mac[1] << 8) |
|
||||
mac[0];
|
||||
macLo >>= 1;
|
||||
macLo |= (macHi & 1) << 31;
|
||||
macHi >>= 1;
|
||||
} else {
|
||||
macLo = macHi = 0;
|
||||
}
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
||||
const struct ath9k_keyval *k,
|
||||
const u8 *mac)
|
||||
{
|
||||
const struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u32 key0, key1, key2, key3, key4;
|
||||
u32 keyType;
|
||||
|
||||
if (entry >= pCap->keycache_size) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"keycache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (k->kv_type) {
|
||||
case ATH9K_CIPHER_AES_OCB:
|
||||
keyType = AR_KEYTABLE_TYPE_AES;
|
||||
break;
|
||||
case ATH9K_CIPHER_AES_CCM:
|
||||
if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"AES-CCM not supported by mac rev 0x%x\n",
|
||||
ah->hw_version.macRev);
|
||||
return false;
|
||||
}
|
||||
keyType = AR_KEYTABLE_TYPE_CCM;
|
||||
break;
|
||||
case ATH9K_CIPHER_TKIP:
|
||||
keyType = AR_KEYTABLE_TYPE_TKIP;
|
||||
if (ATH9K_IS_MIC_ENABLED(ah)
|
||||
&& entry + 64 >= pCap->keycache_size) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"entry %u inappropriate for TKIP\n", entry);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ATH9K_CIPHER_WEP:
|
||||
if (k->kv_len < WLAN_KEY_LEN_WEP40) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"WEP key length %u too small\n", k->kv_len);
|
||||
return false;
|
||||
}
|
||||
if (k->kv_len <= WLAN_KEY_LEN_WEP40)
|
||||
keyType = AR_KEYTABLE_TYPE_40;
|
||||
else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
|
||||
keyType = AR_KEYTABLE_TYPE_104;
|
||||
else
|
||||
keyType = AR_KEYTABLE_TYPE_128;
|
||||
break;
|
||||
case ATH9K_CIPHER_CLR:
|
||||
keyType = AR_KEYTABLE_TYPE_CLR;
|
||||
break;
|
||||
default:
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"cipher %u not supported\n", k->kv_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
key0 = get_unaligned_le32(k->kv_val + 0);
|
||||
key1 = get_unaligned_le16(k->kv_val + 4);
|
||||
key2 = get_unaligned_le32(k->kv_val + 6);
|
||||
key3 = get_unaligned_le16(k->kv_val + 10);
|
||||
key4 = get_unaligned_le32(k->kv_val + 12);
|
||||
if (k->kv_len <= WLAN_KEY_LEN_WEP104)
|
||||
key4 &= 0xff;
|
||||
|
||||
/*
|
||||
* Note: Key cache registers access special memory area that requires
|
||||
* two 32-bit writes to actually update the values in the internal
|
||||
* memory. Consequently, the exact order and pairs used here must be
|
||||
* maintained.
|
||||
*/
|
||||
|
||||
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
|
||||
u16 micentry = entry + 64;
|
||||
|
||||
/*
|
||||
* Write inverted key[47:0] first to avoid Michael MIC errors
|
||||
* on frames that could be sent or received at the same time.
|
||||
* The correct key will be written in the end once everything
|
||||
* else is ready.
|
||||
*/
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
|
||||
|
||||
/* Write key[95:48] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
|
||||
|
||||
/* Write key[127:96] and key type */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
|
||||
|
||||
/* Write MAC address for the entry */
|
||||
(void) ath9k_hw_keysetmac(ah, entry, mac);
|
||||
|
||||
if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
|
||||
/*
|
||||
* TKIP uses two key cache entries:
|
||||
* Michael MIC TX/RX keys in the same key cache entry
|
||||
* (idx = main index + 64):
|
||||
* key0 [31:0] = RX key [31:0]
|
||||
* key1 [15:0] = TX key [31:16]
|
||||
* key1 [31:16] = reserved
|
||||
* key2 [31:0] = RX key [63:32]
|
||||
* key3 [15:0] = TX key [15:0]
|
||||
* key3 [31:16] = reserved
|
||||
* key4 [31:0] = TX key [63:32]
|
||||
*/
|
||||
u32 mic0, mic1, mic2, mic3, mic4;
|
||||
|
||||
mic0 = get_unaligned_le32(k->kv_mic + 0);
|
||||
mic2 = get_unaligned_le32(k->kv_mic + 4);
|
||||
mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
|
||||
mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
|
||||
mic4 = get_unaligned_le32(k->kv_txmic + 4);
|
||||
|
||||
/* Write RX[31:0] and TX[31:16] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
|
||||
|
||||
/* Write RX[63:32] and TX[15:0] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
|
||||
|
||||
/* Write TX[63:32] and keyType(reserved) */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
|
||||
AR_KEYTABLE_TYPE_CLR);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* TKIP uses four key cache entries (two for group
|
||||
* keys):
|
||||
* Michael MIC TX/RX keys are in different key cache
|
||||
* entries (idx = main index + 64 for TX and
|
||||
* main index + 32 + 96 for RX):
|
||||
* key0 [31:0] = TX/RX MIC key [31:0]
|
||||
* key1 [31:0] = reserved
|
||||
* key2 [31:0] = TX/RX MIC key [63:32]
|
||||
* key3 [31:0] = reserved
|
||||
* key4 [31:0] = reserved
|
||||
*
|
||||
* Upper layer code will call this function separately
|
||||
* for TX and RX keys when these registers offsets are
|
||||
* used.
|
||||
*/
|
||||
u32 mic0, mic2;
|
||||
|
||||
mic0 = get_unaligned_le32(k->kv_mic + 0);
|
||||
mic2 = get_unaligned_le32(k->kv_mic + 4);
|
||||
|
||||
/* Write MIC key[31:0] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
|
||||
|
||||
/* Write MIC key[63:32] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
|
||||
|
||||
/* Write TX[63:32] and keyType(reserved) */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
|
||||
AR_KEYTABLE_TYPE_CLR);
|
||||
}
|
||||
|
||||
/* MAC address registers are reserved for the MIC entry */
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
|
||||
|
||||
/*
|
||||
* Write the correct (un-inverted) key[47:0] last to enable
|
||||
* TKIP now that all other registers are set with correct
|
||||
* values.
|
||||
*/
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
|
||||
} else {
|
||||
/* Write key[47:0] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
|
||||
|
||||
/* Write key[95:48] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
|
||||
|
||||
/* Write key[127:96] and key type */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
|
||||
|
||||
/* Write MAC address for the entry */
|
||||
(void) ath9k_hw_keysetmac(ah, entry, mac);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
|
||||
|
||||
/******************************/
|
||||
/* Power Management (Chipset) */
|
||||
/******************************/
|
||||
|
@ -2056,6 +1781,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
||||
|
||||
u16 capField = 0, eeval;
|
||||
u8 ant_div_ctl1;
|
||||
|
||||
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
|
||||
regulatory->current_rd = eeval;
|
||||
|
@ -2140,24 +1866,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
pCap->low_5ghz_chan = 4920;
|
||||
pCap->high_5ghz_chan = 6100;
|
||||
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
|
||||
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
|
||||
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
|
||||
|
||||
if (ah->config.ht_enable)
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_HT;
|
||||
else
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
|
||||
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_GTT;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
|
||||
|
||||
if (capField & AR_EEPROM_EEPCAP_MAXQCU)
|
||||
pCap->total_queues =
|
||||
MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
|
||||
|
@ -2170,8 +1885,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
else
|
||||
pCap->keycache_size = AR_KEYTABLE_SIZE;
|
||||
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
|
||||
|
||||
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
|
||||
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
|
||||
else
|
||||
|
@ -2280,6 +1993,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
|
||||
|
||||
if (AR_SREV_9285(ah))
|
||||
if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
|
||||
ant_div_ctl1 =
|
||||
ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
|
||||
if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -181,29 +181,19 @@ enum wireless_mode {
|
|||
};
|
||||
|
||||
enum ath9k_hw_caps {
|
||||
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_EDMA = BIT(17),
|
||||
ATH9K_HW_CAP_RAC_SUPPORTED = BIT(18),
|
||||
ATH9K_HW_CAP_LDPC = BIT(19),
|
||||
ATH9K_HW_CAP_FASTCLOCK = BIT(20),
|
||||
ATH9K_HW_CAP_SGI_20 = BIT(21),
|
||||
ATH9K_HW_CAP_PAPRD = BIT(22),
|
||||
ATH9K_HW_CAP_HT = BIT(0),
|
||||
ATH9K_HW_CAP_RFSILENT = BIT(1),
|
||||
ATH9K_HW_CAP_CST = BIT(2),
|
||||
ATH9K_HW_CAP_ENHANCEDPM = BIT(3),
|
||||
ATH9K_HW_CAP_AUTOSLEEP = BIT(4),
|
||||
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5),
|
||||
ATH9K_HW_CAP_EDMA = BIT(6),
|
||||
ATH9K_HW_CAP_RAC_SUPPORTED = BIT(7),
|
||||
ATH9K_HW_CAP_LDPC = BIT(8),
|
||||
ATH9K_HW_CAP_FASTCLOCK = BIT(9),
|
||||
ATH9K_HW_CAP_SGI_20 = BIT(10),
|
||||
ATH9K_HW_CAP_PAPRD = BIT(11),
|
||||
ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12),
|
||||
};
|
||||
|
||||
struct ath9k_hw_capabilities {
|
||||
|
@ -495,6 +485,12 @@ struct ath_gen_timer_table {
|
|||
} timer_mask;
|
||||
};
|
||||
|
||||
struct ath_hw_antcomb_conf {
|
||||
u8 main_lna_conf;
|
||||
u8 alt_lna_conf;
|
||||
u8 fast_div_bias;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ath_hw_private_ops - callbacks used internally by hardware code
|
||||
*
|
||||
|
@ -874,12 +870,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
int ath9k_hw_fill_cap_info(struct ath_hw *ah);
|
||||
u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
|
||||
|
||||
/* Key Cache Management */
|
||||
bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
|
||||
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
||||
const struct ath9k_keyval *k,
|
||||
const u8 *mac);
|
||||
|
||||
/* GPIO / RFKILL / Antennae */
|
||||
void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
|
||||
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
|
||||
|
@ -888,6 +878,10 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
|
|||
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
|
||||
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
|
||||
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
|
||||
void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
|
||||
struct ath_hw_antcomb_conf *antconf);
|
||||
void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
|
||||
struct ath_hw_antcomb_conf *antconf);
|
||||
|
||||
/* General Operation */
|
||||
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
|
||||
|
@ -985,6 +979,7 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
|
|||
void ar9002_hw_attach_ops(struct ath_hw *ah);
|
||||
void ar9003_hw_attach_ops(struct ath_hw *ah);
|
||||
|
||||
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
/*
|
||||
* ANI work can be shared between all families but a next
|
||||
* generation implementation of ANI will be used only for AR9003 only
|
||||
|
|
|
@ -381,7 +381,7 @@ static void ath9k_init_crypto(struct ath_softc *sc)
|
|||
* reset the contents on initial power up.
|
||||
*/
|
||||
for (i = 0; i < common->keymax; i++)
|
||||
ath9k_hw_keyreset(sc->sc_ah, (u16) i);
|
||||
ath_hw_keyreset(common, (u16) i);
|
||||
|
||||
/*
|
||||
* Check whether the separate key cache entries
|
||||
|
@ -389,8 +389,8 @@ static void ath9k_init_crypto(struct ath_softc *sc)
|
|||
* With split mic keys the number of stations is limited
|
||||
* to 27 otherwise 59.
|
||||
*/
|
||||
if (!(sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA))
|
||||
common->splitmic = 1;
|
||||
if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
|
||||
common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
|
||||
}
|
||||
|
||||
static int ath9k_init_btcoex(struct ath_softc *sc)
|
||||
|
@ -522,8 +522,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
|||
ath9k_hw_set_diversity(sc->sc_ah, true);
|
||||
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
|
||||
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
|
||||
|
@ -531,6 +530,9 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
|||
sc->beacon.bslot[i] = NULL;
|
||||
sc->beacon.bslot_aphy[i] = NULL;
|
||||
}
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
|
||||
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
|
||||
}
|
||||
|
||||
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
|
@ -641,7 +643,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
if (AR_SREV_5416(sc->sc_ah))
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
|
@ -651,7 +654,9 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
hw->sta_data_size = sizeof(struct ath_node);
|
||||
hw->vif_data_size = sizeof(struct ath_vif);
|
||||
|
||||
#ifdef CONFIG_ATH9K_RATE_CONTROL
|
||||
hw->rate_control_algorithm = "ath9k_rate_control";
|
||||
#endif
|
||||
|
||||
if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
|
||||
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
|
||||
|
|
|
@ -714,6 +714,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
|||
else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
|
||||
rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
|
||||
rs->rs_status |= ATH9K_RXERR_MIC;
|
||||
else if (ads.ds_rxstatus8 & AR_KeyMiss)
|
||||
rs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -660,17 +660,6 @@ struct ath9k_11n_rate_series {
|
|||
u32 RateFlags;
|
||||
};
|
||||
|
||||
struct ath9k_keyval {
|
||||
u8 kv_type;
|
||||
u8 kv_pad;
|
||||
u16 kv_len;
|
||||
u8 kv_val[16]; /* TK */
|
||||
u8 kv_mic[8]; /* Michael MIC key */
|
||||
u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
|
||||
* supports both MIC keys in the same key cache entry;
|
||||
* in that case, kv_mic is the RX key) */
|
||||
};
|
||||
|
||||
enum ath9k_key_type {
|
||||
ATH9K_KEY_TYPE_CLEAR,
|
||||
ATH9K_KEY_TYPE_WEP,
|
||||
|
@ -678,16 +667,6 @@ enum ath9k_key_type {
|
|||
ATH9K_KEY_TYPE_TKIP,
|
||||
};
|
||||
|
||||
enum ath9k_cipher {
|
||||
ATH9K_CIPHER_WEP = 0,
|
||||
ATH9K_CIPHER_AES_OCB = 1,
|
||||
ATH9K_CIPHER_AES_CCM = 2,
|
||||
ATH9K_CIPHER_CKIP = 3,
|
||||
ATH9K_CIPHER_TKIP = 4,
|
||||
ATH9K_CIPHER_CLR = 5,
|
||||
ATH9K_CIPHER_MIC = 127
|
||||
};
|
||||
|
||||
struct ath_hw;
|
||||
struct ath9k_channel;
|
||||
|
||||
|
|
|
@ -255,10 +255,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
ath_update_txpow(sc);
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
|
||||
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL | SC_OP_SCANNING))) {
|
||||
ath_start_ani(common);
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
|
||||
ath_beacon_config(sc, NULL);
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
ps_restore:
|
||||
|
@ -957,7 +957,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
|||
|
||||
ath_update_txpow(sc);
|
||||
|
||||
if (sc->sc_flags & SC_OP_BEACONS)
|
||||
if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
|
||||
ath_beacon_config(sc, NULL); /* restart beacons */
|
||||
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
|
@ -1156,8 +1156,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
|||
else
|
||||
ah->imask |= ATH9K_INT_RX;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
|
||||
ah->imask |= ATH9K_INT_GTT;
|
||||
ah->imask |= ATH9K_INT_GTT;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
|
||||
ah->imask |= ATH9K_INT_CST;
|
||||
|
@ -1379,12 +1378,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
|
||||
sc->nvifs > 0) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ic_opmode = NL80211_IFTYPE_STATION;
|
||||
|
@ -1414,8 +1407,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||
|
||||
sc->nvifs++;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
ath9k_set_bssid_mask(hw);
|
||||
ath9k_set_bssid_mask(hw, vif);
|
||||
|
||||
if (sc->nvifs > 1)
|
||||
goto out; /* skip global settings for secondary vif */
|
||||
|
@ -1562,6 +1554,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
* IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
|
||||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_PS) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if (conf->flags & IEEE80211_CONF_PS) {
|
||||
sc->ps_flags |= PS_ENABLED;
|
||||
/*
|
||||
|
@ -1576,7 +1570,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
sc->ps_enabled = false;
|
||||
sc->ps_flags &= ~(PS_ENABLED |
|
||||
PS_NULLFUNC_COMPLETED);
|
||||
ath9k_setpower(sc, ATH9K_PM_AWAKE);
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 0);
|
||||
|
@ -1591,6 +1585,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
|
||||
|
@ -1777,7 +1772,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
|||
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
ret = ath9k_cmn_key_config(common, vif, sta, key);
|
||||
ret = ath_key_config(common, vif, sta, key);
|
||||
if (ret >= 0) {
|
||||
key->hw_key_idx = ret;
|
||||
/* push IV and Michael MIC generation to stack */
|
||||
|
@ -1791,7 +1786,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
|||
}
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
ath9k_cmn_key_delete(common, key);
|
||||
ath_key_delete(common, key);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -1975,8 +1970,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
|||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath_tx_aggr_start(sc, sta, tid, ssn);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
ret = ath_tx_aggr_start(sc, sta, tid, ssn);
|
||||
if (!ret)
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
ath9k_ps_restore(sc);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
|
@ -2039,7 +2035,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
|
|||
|
||||
aphy->state = ATH_WIPHY_SCAN;
|
||||
ath9k_wiphy_pause_all_forced(sc, aphy);
|
||||
sc->sc_flags |= SC_OP_SCANNING;
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
|
@ -2054,7 +2049,6 @@ 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;
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,6 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define ATH9K_IS_MIC_ENABLED(ah) \
|
||||
((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
|
||||
|
||||
#define ANTSWAP_AB 0x0001
|
||||
#define REDUCE_CHAIN_0 0x00000050
|
||||
#define REDUCE_CHAIN_1 0x00000051
|
||||
|
|
|
@ -1320,6 +1320,22 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
|
|||
return caps;
|
||||
}
|
||||
|
||||
static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an,
|
||||
u8 tidno)
|
||||
{
|
||||
struct ath_atx_tid *txtid;
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_TXAGGR))
|
||||
return false;
|
||||
|
||||
txtid = ATH_AN_2_TID(an, tidno);
|
||||
|
||||
if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************/
|
||||
/* mac80211 Rate Control callbacks */
|
||||
/***********************************/
|
||||
|
|
|
@ -224,7 +224,18 @@ enum ath9k_internal_frame_type {
|
|||
ATH9K_IFT_UNPAUSE
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH9K_RATE_CONTROL
|
||||
int ath_rate_control_register(void);
|
||||
void ath_rate_control_unregister(void);
|
||||
#else
|
||||
static inline int ath_rate_control_register(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath_rate_control_unregister(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RC_H */
|
||||
|
|
|
@ -19,6 +19,15 @@
|
|||
|
||||
#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb))
|
||||
|
||||
static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
|
||||
int mindelta, int main_rssi_avg,
|
||||
int alt_rssi_avg, int pkt_count)
|
||||
{
|
||||
return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
|
||||
(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
|
||||
}
|
||||
|
||||
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
|
||||
{
|
||||
return sc->ps_enabled &&
|
||||
|
@ -110,8 +119,7 @@ static void ath_opmode_init(struct ath_softc *sc)
|
|||
ath9k_hw_setrxfilter(ah, rfilt);
|
||||
|
||||
/* configure bssid mask */
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
ath_hw_setbssidmask(common);
|
||||
ath_hw_setbssidmask(common);
|
||||
|
||||
/* configure operational mode */
|
||||
ath9k_hw_setopmode(ah);
|
||||
|
@ -292,7 +300,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
|
|||
|
||||
ath_opmode_init(sc);
|
||||
|
||||
ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING));
|
||||
ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
|
||||
}
|
||||
|
||||
static void ath_edma_stop_recv(struct ath_softc *sc)
|
||||
|
@ -440,6 +448,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
|||
rfilt |= ATH9K_RX_FILTER_CONTROL;
|
||||
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
|
||||
(sc->nvifs <= 1) &&
|
||||
!(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
|
||||
rfilt |= ATH9K_RX_FILTER_MYBEACON;
|
||||
else
|
||||
|
@ -454,9 +463,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
|||
if (conf_is_ht(&sc->hw->conf))
|
||||
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
|
||||
|
||||
if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
|
||||
/* TODO: only needed if more than one BSSID is in use in
|
||||
* station/adhoc mode */
|
||||
if (sc->sec_wiphy || (sc->nvifs > 1) ||
|
||||
(sc->rx.rxfilter & FIF_OTHER_BSS)) {
|
||||
/* The following may also be needed for other older chips */
|
||||
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
|
@ -498,7 +506,7 @@ int ath_startrecv(struct ath_softc *sc)
|
|||
start_recv:
|
||||
spin_unlock_bh(&sc->rx.rxbuflock);
|
||||
ath_opmode_init(sc);
|
||||
ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING));
|
||||
ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -631,7 +639,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
|
|||
* No more broadcast/multicast frames to be received at this
|
||||
* point.
|
||||
*/
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_CAB;
|
||||
sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON);
|
||||
ath_print(common, ATH_DBG_PS,
|
||||
"All PS CAB frames received, back to sleep\n");
|
||||
} else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
|
||||
|
@ -1076,6 +1084,539 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
|
|||
rxs->flag &= ~RX_FLAG_DECRYPTED;
|
||||
}
|
||||
|
||||
static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
|
||||
struct ath_hw_antcomb_conf ant_conf,
|
||||
int main_rssi_avg)
|
||||
{
|
||||
antcomb->quick_scan_cnt = 0;
|
||||
|
||||
if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
|
||||
switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
|
||||
case (0x10): /* LNA2 A-B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
break;
|
||||
case (0x20): /* LNA1 A-B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
break;
|
||||
case (0x21): /* LNA1 LNA2 */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case (0x12): /* LNA2 LNA1 */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case (0x13): /* LNA2 A+B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
break;
|
||||
case (0x23): /* LNA1 A+B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
|
||||
struct ath_hw_antcomb_conf *div_ant_conf,
|
||||
int main_rssi_avg, int alt_rssi_avg,
|
||||
int alt_ratio)
|
||||
{
|
||||
/* alt_good */
|
||||
switch (antcomb->quick_scan_cnt) {
|
||||
case 0:
|
||||
/* set alt to main, and alt to first conf */
|
||||
div_ant_conf->main_lna_conf = antcomb->main_conf;
|
||||
div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
|
||||
break;
|
||||
case 1:
|
||||
/* set alt to main, and alt to first conf */
|
||||
div_ant_conf->main_lna_conf = antcomb->main_conf;
|
||||
div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
|
||||
antcomb->rssi_first = main_rssi_avg;
|
||||
antcomb->rssi_second = alt_rssi_avg;
|
||||
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
|
||||
/* main is LNA1 */
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
} else {
|
||||
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
|
||||
(alt_rssi_avg > main_rssi_avg)) &&
|
||||
(antcomb->total_pkt_count > 50))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
antcomb->alt_good = false;
|
||||
antcomb->scan_not_start = false;
|
||||
antcomb->scan = false;
|
||||
antcomb->rssi_first = main_rssi_avg;
|
||||
antcomb->rssi_third = alt_rssi_avg;
|
||||
|
||||
if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = alt_rssi_avg;
|
||||
else if (antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = alt_rssi_avg;
|
||||
else if (antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
}
|
||||
|
||||
if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
|
||||
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
} else {
|
||||
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
|
||||
(alt_rssi_avg > main_rssi_avg)) &&
|
||||
(antcomb->total_pkt_count > 50))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
}
|
||||
|
||||
/* set alt to the conf with maximun ratio */
|
||||
if (antcomb->first_ratio && antcomb->second_ratio) {
|
||||
if (antcomb->rssi_second > antcomb->rssi_third) {
|
||||
/* first alt*/
|
||||
if ((antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2*/
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->first_quick_scan_conf;
|
||||
} else if ((antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)) {
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
} else {
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->second_quick_scan_conf;
|
||||
}
|
||||
} else if (antcomb->first_ratio) {
|
||||
/* first alt */
|
||||
if ((antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->first_quick_scan_conf;
|
||||
} else if (antcomb->second_ratio) {
|
||||
/* second alt */
|
||||
if ((antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->second_quick_scan_conf;
|
||||
} else {
|
||||
/* main is largest */
|
||||
if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf = antcomb->main_conf;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf)
|
||||
{
|
||||
/* Adjust the fast_div_bias based on main and alt lna conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
|
||||
case (0x01): /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x3b;
|
||||
break;
|
||||
case (0x02): /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x3d;
|
||||
break;
|
||||
case (0x03): /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case (0x10): /* LNA2 A-B */
|
||||
ant_conf->fast_div_bias = 0x7;
|
||||
break;
|
||||
case (0x12): /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
break;
|
||||
case (0x13): /* LNA2 A+B */
|
||||
ant_conf->fast_div_bias = 0x7;
|
||||
break;
|
||||
case (0x20): /* LNA1 A-B */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case (0x21): /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x0;
|
||||
break;
|
||||
case (0x23): /* LNA1 A+B */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case (0x30): /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case (0x31): /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x3b;
|
||||
break;
|
||||
case (0x32): /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x3d;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Antenna diversity and combining */
|
||||
static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
|
||||
{
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
struct ath_ant_comb *antcomb = &sc->ant_comb;
|
||||
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
|
||||
int curr_main_set, curr_bias;
|
||||
int main_rssi = rs->rs_rssi_ctl0;
|
||||
int alt_rssi = rs->rs_rssi_ctl1;
|
||||
int rx_ant_conf, main_ant_conf;
|
||||
bool short_scan = false;
|
||||
|
||||
rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
|
||||
/* Record packet only when alt_rssi is positive */
|
||||
if (alt_rssi > 0) {
|
||||
antcomb->total_pkt_count++;
|
||||
antcomb->main_total_rssi += main_rssi;
|
||||
antcomb->alt_total_rssi += alt_rssi;
|
||||
if (main_ant_conf == rx_ant_conf)
|
||||
antcomb->main_recv_cnt++;
|
||||
else
|
||||
antcomb->alt_recv_cnt++;
|
||||
}
|
||||
|
||||
/* Short scan check */
|
||||
if (antcomb->scan && antcomb->alt_good) {
|
||||
if (time_after(jiffies, antcomb->scan_start_time +
|
||||
msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
|
||||
short_scan = true;
|
||||
else
|
||||
if (antcomb->total_pkt_count ==
|
||||
ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
|
||||
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
|
||||
antcomb->total_pkt_count);
|
||||
if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
|
||||
short_scan = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
|
||||
rs->rs_moreaggr) && !short_scan)
|
||||
return;
|
||||
|
||||
if (antcomb->total_pkt_count) {
|
||||
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
|
||||
antcomb->total_pkt_count);
|
||||
main_rssi_avg = (antcomb->main_total_rssi /
|
||||
antcomb->total_pkt_count);
|
||||
alt_rssi_avg = (antcomb->alt_total_rssi /
|
||||
antcomb->total_pkt_count);
|
||||
}
|
||||
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
|
||||
curr_alt_set = div_ant_conf.alt_lna_conf;
|
||||
curr_main_set = div_ant_conf.main_lna_conf;
|
||||
curr_bias = div_ant_conf.fast_div_bias;
|
||||
|
||||
antcomb->count++;
|
||||
|
||||
if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
|
||||
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
|
||||
ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
|
||||
main_rssi_avg);
|
||||
antcomb->alt_good = true;
|
||||
} else {
|
||||
antcomb->alt_good = false;
|
||||
}
|
||||
|
||||
antcomb->count = 0;
|
||||
antcomb->scan = true;
|
||||
antcomb->scan_not_start = true;
|
||||
}
|
||||
|
||||
if (!antcomb->scan) {
|
||||
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
|
||||
if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
|
||||
/* Switch main and alt LNA */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
|
||||
goto div_comb_done;
|
||||
} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
|
||||
/* Set alt to another LNA */
|
||||
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
|
||||
goto div_comb_done;
|
||||
}
|
||||
|
||||
if ((alt_rssi_avg < (main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
|
||||
goto div_comb_done;
|
||||
}
|
||||
|
||||
if (!antcomb->scan_not_start) {
|
||||
switch (curr_alt_set) {
|
||||
case ATH_ANT_DIV_COMB_LNA2:
|
||||
antcomb->rssi_lna2 = alt_rssi_avg;
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1:
|
||||
antcomb->rssi_lna1 = alt_rssi_avg;
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
|
||||
antcomb->rssi_add = alt_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A-B */
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
|
||||
antcomb->rssi_sub = alt_rssi_avg;
|
||||
antcomb->scan = false;
|
||||
if (antcomb->rssi_lna2 >
|
||||
(antcomb->rssi_lna1 +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
|
||||
/* use LNA2 as main LNA */
|
||||
if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
|
||||
(antcomb->rssi_add > antcomb->rssi_sub)) {
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
} else if (antcomb->rssi_sub >
|
||||
antcomb->rssi_lna1) {
|
||||
/* set to A-B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
} else {
|
||||
/* set to LNA1 */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
}
|
||||
} else {
|
||||
/* use LNA1 as main LNA */
|
||||
if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
|
||||
(antcomb->rssi_add > antcomb->rssi_sub)) {
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
} else if (antcomb->rssi_sub >
|
||||
antcomb->rssi_lna1) {
|
||||
/* set to A-B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
} else {
|
||||
/* set to LNA2 */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!antcomb->alt_good) {
|
||||
antcomb->scan_not_start = false;
|
||||
/* Set alt to another LNA */
|
||||
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
goto div_comb_done;
|
||||
}
|
||||
}
|
||||
|
||||
ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
alt_ratio);
|
||||
|
||||
antcomb->quick_scan_cnt++;
|
||||
|
||||
div_comb_done:
|
||||
ath_ant_div_conf_fast_divbias(&div_ant_conf);
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
|
||||
|
||||
antcomb->scan_start_time = jiffies;
|
||||
antcomb->total_pkt_count = 0;
|
||||
antcomb->main_total_rssi = 0;
|
||||
antcomb->alt_total_rssi = 0;
|
||||
antcomb->main_recv_cnt = 0;
|
||||
antcomb->alt_recv_cnt = 0;
|
||||
}
|
||||
|
||||
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
{
|
||||
struct ath_buf *bf;
|
||||
|
@ -1099,6 +1640,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
u8 rx_status_len = ah->caps.rx_status_len;
|
||||
u64 tsf = 0;
|
||||
u32 tsf_lower = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (edma)
|
||||
dma_type = DMA_BIDIRECTIONAL;
|
||||
|
@ -1207,11 +1749,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
sc->rx.rxotherant = 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if (unlikely(ath9k_check_auto_sleep(sc) ||
|
||||
(sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||
PS_WAIT_FOR_CAB |
|
||||
PS_WAIT_FOR_PSPOLL_DATA))))
|
||||
ath_rx_ps(sc, skb);
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
|
||||
ath_ant_comb_scan(sc, &rs);
|
||||
|
||||
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
|
||||
|
||||
|
|
|
@ -19,45 +19,36 @@
|
|||
#include "ath9k.h"
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
int count;
|
||||
u8 *addr;
|
||||
const u8 *hw_macaddr;
|
||||
u8 mask[ETH_ALEN];
|
||||
};
|
||||
|
||||
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath9k_vif_iter_data *iter_data = data;
|
||||
u8 *nbuf;
|
||||
int i;
|
||||
|
||||
nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
|
||||
GFP_ATOMIC);
|
||||
if (nbuf == NULL)
|
||||
return;
|
||||
|
||||
memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
|
||||
iter_data->addr = nbuf;
|
||||
iter_data->count++;
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
|
||||
}
|
||||
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
int i, j;
|
||||
u8 mask[ETH_ALEN];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Add primary MAC address even if it is not in active use since it
|
||||
* will be configured to the hardware as the starting point and the
|
||||
* BSSID mask will need to be changed if another address is active.
|
||||
* Use the hardware MAC address as reference, the hardware uses it
|
||||
* together with the BSSID mask when matching addresses.
|
||||
*/
|
||||
iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
|
||||
if (iter_data.addr) {
|
||||
memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
|
||||
iter_data.count = 1;
|
||||
} else
|
||||
iter_data.count = 0;
|
||||
iter_data.hw_macaddr = common->macaddr;
|
||||
memset(&iter_data.mask, 0xff, ETH_ALEN);
|
||||
|
||||
if (vif)
|
||||
ath9k_vif_iter(&iter_data, vif->addr, vif);
|
||||
|
||||
/* Get list of all active MAC addresses */
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
|
@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
|
|||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
/* Generate an address mask to cover all active addresses */
|
||||
memset(mask, 0, ETH_ALEN);
|
||||
for (i = 0; i < iter_data.count; i++) {
|
||||
u8 *a1 = iter_data.addr + i * ETH_ALEN;
|
||||
for (j = i + 1; j < iter_data.count; j++) {
|
||||
u8 *a2 = iter_data.addr + j * ETH_ALEN;
|
||||
mask[0] |= a1[0] ^ a2[0];
|
||||
mask[1] |= a1[1] ^ a2[1];
|
||||
mask[2] |= a1[2] ^ a2[2];
|
||||
mask[3] |= a1[3] ^ a2[3];
|
||||
mask[4] |= a1[4] ^ a2[4];
|
||||
mask[5] |= a1[5] ^ a2[5];
|
||||
}
|
||||
}
|
||||
|
||||
kfree(iter_data.addr);
|
||||
|
||||
/* Invert the mask and configure hardware */
|
||||
common->bssidmask[0] = ~mask[0];
|
||||
common->bssidmask[1] = ~mask[1];
|
||||
common->bssidmask[2] = ~mask[2];
|
||||
common->bssidmask[3] = ~mask[3];
|
||||
common->bssidmask[4] = ~mask[4];
|
||||
common->bssidmask[5] = ~mask[5];
|
||||
|
||||
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
||||
ath_hw_setbssidmask(common);
|
||||
}
|
||||
|
||||
|
|
|
@ -124,55 +124,11 @@ void ath9k_wmi_tasklet(unsigned long data)
|
|||
{
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct wmi_cmd_hdr *hdr;
|
||||
struct wmi_swba *swba_hdr;
|
||||
enum wmi_event_id event;
|
||||
struct sk_buff *skb;
|
||||
void *wmi_event;
|
||||
unsigned long flags;
|
||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||
__be32 txrate;
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
|
||||
skb = priv->wmi->wmi_skb;
|
||||
spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
|
||||
ath_print(common, ATH_DBG_WMI, "SWBA Event received\n");
|
||||
|
||||
hdr = (struct wmi_cmd_hdr *) skb->data;
|
||||
event = be16_to_cpu(hdr->command_id);
|
||||
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
|
||||
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
|
||||
|
||||
ath_print(common, ATH_DBG_WMI,
|
||||
"WMI Event: 0x%x\n", event);
|
||||
|
||||
switch (event) {
|
||||
case WMI_TGT_RDY_EVENTID:
|
||||
break;
|
||||
case WMI_SWBA_EVENTID:
|
||||
swba_hdr = (struct wmi_swba *) wmi_event;
|
||||
ath9k_htc_swba(priv, swba_hdr->beacon_pending);
|
||||
break;
|
||||
case WMI_FATAL_EVENTID:
|
||||
break;
|
||||
case WMI_TXTO_EVENTID:
|
||||
break;
|
||||
case WMI_BMISS_EVENTID:
|
||||
break;
|
||||
case WMI_WLAN_TXCOMP_EVENTID:
|
||||
break;
|
||||
case WMI_DELBA_EVENTID:
|
||||
break;
|
||||
case WMI_TXRATE_EVENTID:
|
||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||
txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
|
||||
priv->debug.txrate = be32_to_cpu(txrate);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
|
||||
|
@ -191,6 +147,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
|
|||
struct wmi *wmi = (struct wmi *) priv;
|
||||
struct wmi_cmd_hdr *hdr;
|
||||
u16 cmd_id;
|
||||
void *wmi_event;
|
||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||
__be32 txrate;
|
||||
#endif
|
||||
|
||||
if (unlikely(wmi->stopped))
|
||||
goto free_skb;
|
||||
|
@ -199,10 +159,22 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
|
|||
cmd_id = be16_to_cpu(hdr->command_id);
|
||||
|
||||
if (cmd_id & 0x1000) {
|
||||
spin_lock(&wmi->wmi_lock);
|
||||
wmi->wmi_skb = skb;
|
||||
spin_unlock(&wmi->wmi_lock);
|
||||
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
|
||||
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
|
||||
switch (cmd_id) {
|
||||
case WMI_SWBA_EVENTID:
|
||||
wmi->beacon_pending = *(u8 *)wmi_event;
|
||||
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
|
||||
break;
|
||||
case WMI_TXRATE_EVENTID:
|
||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||
txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
|
||||
wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,10 +31,6 @@ struct wmi_cmd_hdr {
|
|||
__be16 seq_no;
|
||||
} __packed;
|
||||
|
||||
struct wmi_swba {
|
||||
u8 beacon_pending;
|
||||
} __packed;
|
||||
|
||||
enum wmi_cmd_id {
|
||||
WMI_ECHO_CMDID = 0x0001,
|
||||
WMI_ACCESS_MEMORY_CMDID,
|
||||
|
@ -104,7 +100,7 @@ struct wmi {
|
|||
u32 cmd_rsp_len;
|
||||
bool stopped;
|
||||
|
||||
struct sk_buff *wmi_skb;
|
||||
u8 beacon_pending;
|
||||
spinlock_t wmi_lock;
|
||||
|
||||
atomic_t mwrite_cnt;
|
||||
|
|
|
@ -61,6 +61,8 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
|
|||
struct ath_tx_status *ts, int txok);
|
||||
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
||||
int nbad, int txok, bool update_rc);
|
||||
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
|
||||
int seqno);
|
||||
|
||||
enum {
|
||||
MCS_HT20,
|
||||
|
@ -143,18 +145,23 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
|||
struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
|
||||
struct ath_buf *bf;
|
||||
struct list_head bf_head;
|
||||
struct ath_tx_status ts;
|
||||
|
||||
INIT_LIST_HEAD(&bf_head);
|
||||
|
||||
WARN_ON(!tid->paused);
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
tid->paused = false;
|
||||
|
||||
while (!list_empty(&tid->buf_q)) {
|
||||
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
|
||||
BUG_ON(bf_isretried(bf));
|
||||
list_move_tail(&bf->list, &bf_head);
|
||||
ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
|
||||
|
||||
if (bf_isretried(bf)) {
|
||||
ath_tx_update_baw(sc, tid, bf->bf_seqno);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
|
||||
} else {
|
||||
ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
|
@ -168,9 +175,9 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
|
|||
index = ATH_BA_INDEX(tid->seq_start, seqno);
|
||||
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
|
||||
|
||||
tid->tx_buf[cindex] = NULL;
|
||||
__clear_bit(cindex, tid->tx_buf);
|
||||
|
||||
while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) {
|
||||
while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
|
||||
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
|
||||
INCR(tid->baw_head, ATH_TID_MAX_BUFS);
|
||||
}
|
||||
|
@ -186,9 +193,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
|
|||
|
||||
index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
|
||||
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
|
||||
|
||||
BUG_ON(tid->tx_buf[cindex] != NULL);
|
||||
tid->tx_buf[cindex] = bf;
|
||||
__set_bit(cindex, tid->tx_buf);
|
||||
|
||||
if (index >= ((tid->baw_tail - tid->baw_head) &
|
||||
(ATH_TID_MAX_BUFS - 1))) {
|
||||
|
@ -431,7 +436,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
list_move_tail(&bf->list, &bf_head);
|
||||
}
|
||||
|
||||
if (!txpending) {
|
||||
if (!txpending || (tid->state & AGGR_CLEANUP)) {
|
||||
/*
|
||||
* complete the acked-ones/xretried ones; update
|
||||
* block-ack window
|
||||
|
@ -510,15 +515,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
}
|
||||
|
||||
if (tid->state & AGGR_CLEANUP) {
|
||||
ath_tx_flush_tid(sc, tid);
|
||||
|
||||
if (tid->baw_head == tid->baw_tail) {
|
||||
tid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
tid->state &= ~AGGR_CLEANUP;
|
||||
|
||||
/* send buffered frames as singles */
|
||||
ath_tx_flush_tid(sc, tid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
@ -785,17 +787,23 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
status != ATH_AGGR_BAW_CLOSED);
|
||||
}
|
||||
|
||||
void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
{
|
||||
struct ath_atx_tid *txtid;
|
||||
struct ath_node *an;
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
txtid = ATH_AN_2_TID(an, tid);
|
||||
|
||||
if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
|
||||
return -EAGAIN;
|
||||
|
||||
txtid->state |= AGGR_ADDBA_PROGRESS;
|
||||
txtid->paused = true;
|
||||
*ssn = txtid->seq_start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
|
@ -803,12 +811,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
|||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
|
||||
struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
|
||||
struct ath_tx_status ts;
|
||||
struct ath_buf *bf;
|
||||
struct list_head bf_head;
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
INIT_LIST_HEAD(&bf_head);
|
||||
|
||||
if (txtid->state & AGGR_CLEANUP)
|
||||
return;
|
||||
|
@ -818,31 +820,22 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
|||
return;
|
||||
}
|
||||
|
||||
/* drop all software retried frames and mark this TID */
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
txtid->paused = true;
|
||||
while (!list_empty(&txtid->buf_q)) {
|
||||
bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
|
||||
if (!bf_isretried(bf)) {
|
||||
/*
|
||||
* NB: it's based on the assumption that
|
||||
* software retried frame will always stay
|
||||
* at the head of software queue.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
list_move_tail(&bf->list, &bf_head);
|
||||
ath_tx_update_baw(sc, txtid, bf->bf_seqno);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If frames are still being transmitted for this TID, they will be
|
||||
* cleaned up during tx completion. To prevent race conditions, this
|
||||
* TID can only be reused after all in-progress subframes have been
|
||||
* completed.
|
||||
*/
|
||||
if (txtid->baw_head != txtid->baw_tail)
|
||||
txtid->state |= AGGR_CLEANUP;
|
||||
else
|
||||
txtid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
|
||||
if (txtid->baw_head != txtid->baw_tail) {
|
||||
txtid->state |= AGGR_CLEANUP;
|
||||
} else {
|
||||
txtid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
ath_tx_flush_tid(sc, txtid);
|
||||
}
|
||||
ath_tx_flush_tid(sc, txtid);
|
||||
}
|
||||
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
|
@ -862,20 +855,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
|
|||
}
|
||||
}
|
||||
|
||||
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
|
||||
{
|
||||
struct ath_atx_tid *txtid;
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_TXAGGR))
|
||||
return false;
|
||||
|
||||
txtid = ATH_AN_2_TID(an, tidno);
|
||||
|
||||
if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/********************/
|
||||
/* Queue Management */
|
||||
/********************/
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
config CARL9170
|
||||
tristate "Linux Community AR9170 802.11n USB support"
|
||||
depends on USB && MAC80211 && EXPERIMENTAL
|
||||
select FW_LOADER
|
||||
select CRC32
|
||||
help
|
||||
This is another driver for the Atheros "otus" 802.11n USB devices.
|
||||
|
||||
This driver provides more features than the original,
|
||||
but it needs a special firmware (carl9170-1.fw) to do that.
|
||||
|
||||
The firmware can be downloaded from our wiki here:
|
||||
http://wireless.kernel.org/en/users/Drivers/carl9170
|
||||
|
||||
If you choose to build a module, it'll be called carl9170.
|
||||
|
||||
config CARL9170_LEDS
|
||||
bool "SoftLED Support"
|
||||
depends on CARL9170
|
||||
select MAC80211_LEDS
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
default y
|
||||
help
|
||||
This option is necessary, if you want your device' LEDs to blink
|
||||
|
||||
Say Y, unless you need the LEDs for firmware debugging.
|
||||
|
||||
config CARL9170_DEBUGFS
|
||||
bool "DebugFS Support"
|
||||
depends on CARL9170 && DEBUG_FS && MAC80211_DEBUGFS
|
||||
default n
|
||||
help
|
||||
Export several driver and device internals to user space.
|
||||
|
||||
Say N.
|
||||
|
||||
config CARL9170_WPC
|
||||
bool
|
||||
depends on CARL9170 && (INPUT = y || INPUT = CARL9170)
|
||||
default y
|
|
@ -0,0 +1,4 @@
|
|||
carl9170-objs := main.o usb.o cmd.o mac.o phy.o led.o fw.o tx.o rx.o
|
||||
carl9170-$(CONFIG_CARL9170_DEBUGFS) += debug.o
|
||||
|
||||
obj-$(CONFIG_CARL9170) += carl9170.o
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* Driver specific definitions
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
#ifndef __CARL9170_H
|
||||
#define __CARL9170_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/usb.h>
|
||||
#ifdef CONFIG_CARL9170_LEDS
|
||||
#include <linux/leds.h>
|
||||
#endif /* CONFIG_CARL170_LEDS */
|
||||
#ifdef CONFIG_CARL9170_WPC
|
||||
#include <linux/input.h>
|
||||
#endif /* CONFIG_CARL9170_WPC */
|
||||
#include "eeprom.h"
|
||||
#include "wlan.h"
|
||||
#include "hw.h"
|
||||
#include "fwdesc.h"
|
||||
#include "fwcmd.h"
|
||||
#include "../regd.h"
|
||||
|
||||
#ifdef CONFIG_CARL9170_DEBUGFS
|
||||
#include "debug.h"
|
||||
#endif /* CONFIG_CARL9170_DEBUGFS */
|
||||
|
||||
#define CARL9170FW_NAME "carl9170-1.fw"
|
||||
|
||||
#define PAYLOAD_MAX (CARL9170_MAX_CMD_LEN / 4 - 1)
|
||||
|
||||
enum carl9170_rf_init_mode {
|
||||
CARL9170_RFI_NONE,
|
||||
CARL9170_RFI_WARM,
|
||||
CARL9170_RFI_COLD,
|
||||
};
|
||||
|
||||
#define CARL9170_MAX_RX_BUFFER_SIZE 8192
|
||||
|
||||
enum carl9170_device_state {
|
||||
CARL9170_UNKNOWN_STATE,
|
||||
CARL9170_STOPPED,
|
||||
CARL9170_IDLE,
|
||||
CARL9170_STARTED,
|
||||
};
|
||||
|
||||
#define CARL9170_NUM_TID 16
|
||||
#define WME_BA_BMP_SIZE 64
|
||||
#define CARL9170_TX_USER_RATE_TRIES 3
|
||||
|
||||
#define WME_AC_BE 2
|
||||
#define WME_AC_BK 3
|
||||
#define WME_AC_VI 1
|
||||
#define WME_AC_VO 0
|
||||
|
||||
#define TID_TO_WME_AC(_tid) \
|
||||
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
|
||||
(((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
|
||||
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
|
||||
WME_AC_VO)
|
||||
|
||||
#define SEQ_DIFF(_start, _seq) \
|
||||
(((_start) - (_seq)) & 0x0fff)
|
||||
#define SEQ_PREV(_seq) \
|
||||
(((_seq) - 1) & 0x0fff)
|
||||
#define SEQ_NEXT(_seq) \
|
||||
(((_seq) + 1) & 0x0fff)
|
||||
#define BAW_WITHIN(_start, _bawsz, _seqno) \
|
||||
((((_seqno) - (_start)) & 0xfff) < (_bawsz))
|
||||
|
||||
enum carl9170_tid_state {
|
||||
CARL9170_TID_STATE_INVALID,
|
||||
CARL9170_TID_STATE_KILLED,
|
||||
CARL9170_TID_STATE_SHUTDOWN,
|
||||
CARL9170_TID_STATE_SUSPEND,
|
||||
CARL9170_TID_STATE_PROGRESS,
|
||||
CARL9170_TID_STATE_IDLE,
|
||||
CARL9170_TID_STATE_XMIT,
|
||||
};
|
||||
|
||||
#define CARL9170_BAW_BITS (2 * WME_BA_BMP_SIZE)
|
||||
#define CARL9170_BAW_SIZE (BITS_TO_LONGS(CARL9170_BAW_BITS))
|
||||
#define CARL9170_BAW_LEN (DIV_ROUND_UP(CARL9170_BAW_BITS, BITS_PER_BYTE))
|
||||
|
||||
struct carl9170_sta_tid {
|
||||
/* must be the first entry! */
|
||||
struct list_head list;
|
||||
|
||||
/* temporary list for RCU unlink procedure */
|
||||
struct list_head tmp_list;
|
||||
|
||||
/* lock for the following data structures */
|
||||
spinlock_t lock;
|
||||
|
||||
unsigned int counter;
|
||||
enum carl9170_tid_state state;
|
||||
u8 tid; /* TID number ( 0 - 15 ) */
|
||||
u16 max; /* max. AMPDU size */
|
||||
|
||||
u16 snx; /* awaiting _next_ frame */
|
||||
u16 hsn; /* highest _queued_ sequence */
|
||||
u16 bsn; /* base of the tx/agg bitmap */
|
||||
unsigned long bitmap[CARL9170_BAW_SIZE];
|
||||
|
||||
/* Preaggregation reorder queue */
|
||||
struct sk_buff_head queue;
|
||||
};
|
||||
|
||||
#define CARL9170_QUEUE_TIMEOUT 256
|
||||
#define CARL9170_BUMP_QUEUE 1000
|
||||
#define CARL9170_TX_TIMEOUT 2500
|
||||
#define CARL9170_JANITOR_DELAY 128
|
||||
#define CARL9170_QUEUE_STUCK_TIMEOUT 5500
|
||||
|
||||
#define CARL9170_NUM_TX_AGG_MAX 30
|
||||
|
||||
/*
|
||||
* Tradeoff between stability/latency and speed.
|
||||
*
|
||||
* AR9170_TXQ_DEPTH is devised by dividing the amount of available
|
||||
* tx buffers with the size of a full ethernet frame + overhead.
|
||||
*
|
||||
* Naturally: The higher the limit, the faster the device CAN send.
|
||||
* However, even a slight over-commitment at the wrong time and the
|
||||
* hardware is doomed to send all already-queued frames at suboptimal
|
||||
* rates. This in turn leads to an enourmous amount of unsuccessful
|
||||
* retries => Latency goes up, whereas the throughput goes down. CRASH!
|
||||
*/
|
||||
#define CARL9170_NUM_TX_LIMIT_HARD ((AR9170_TXQ_DEPTH * 3) / 2)
|
||||
#define CARL9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH)
|
||||
|
||||
struct carl9170_tx_queue_stats {
|
||||
unsigned int count;
|
||||
unsigned int limit;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct carl9170_vif {
|
||||
unsigned int id;
|
||||
struct ieee80211_vif *vif;
|
||||
};
|
||||
|
||||
struct carl9170_vif_info {
|
||||
struct list_head list;
|
||||
bool active;
|
||||
unsigned int id;
|
||||
struct sk_buff *beacon;
|
||||
bool enable_beacon;
|
||||
};
|
||||
|
||||
#define AR9170_NUM_RX_URBS 16
|
||||
#define AR9170_NUM_RX_URBS_MUL 2
|
||||
#define AR9170_NUM_TX_URBS 8
|
||||
#define AR9170_NUM_RX_URBS_POOL (AR9170_NUM_RX_URBS_MUL * AR9170_NUM_RX_URBS)
|
||||
|
||||
enum carl9170_device_features {
|
||||
CARL9170_WPS_BUTTON = BIT(0),
|
||||
CARL9170_ONE_LED = BIT(1),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CARL9170_LEDS
|
||||
struct ar9170;
|
||||
|
||||
struct carl9170_led {
|
||||
struct ar9170 *ar;
|
||||
struct led_classdev l;
|
||||
char name[32];
|
||||
unsigned int toggled;
|
||||
bool last_state;
|
||||
bool registered;
|
||||
};
|
||||
#endif /* CONFIG_CARL9170_LEDS */
|
||||
|
||||
enum carl9170_restart_reasons {
|
||||
CARL9170_RR_NO_REASON = 0,
|
||||
CARL9170_RR_FATAL_FIRMWARE_ERROR,
|
||||
CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS,
|
||||
CARL9170_RR_WATCHDOG,
|
||||
CARL9170_RR_STUCK_TX,
|
||||
CARL9170_RR_SLOW_SYSTEM,
|
||||
CARL9170_RR_COMMAND_TIMEOUT,
|
||||
CARL9170_RR_TOO_MANY_PHY_ERRORS,
|
||||
CARL9170_RR_LOST_RSP,
|
||||
CARL9170_RR_INVALID_RSP,
|
||||
CARL9170_RR_USER_REQUEST,
|
||||
|
||||
__CARL9170_RR_LAST,
|
||||
};
|
||||
|
||||
enum carl9170_erp_modes {
|
||||
CARL9170_ERP_INVALID,
|
||||
CARL9170_ERP_AUTO,
|
||||
CARL9170_ERP_MAC80211,
|
||||
CARL9170_ERP_OFF,
|
||||
CARL9170_ERP_CTS,
|
||||
CARL9170_ERP_RTS,
|
||||
__CARL9170_ERP_NUM,
|
||||
};
|
||||
|
||||
struct ar9170 {
|
||||
struct ath_common common;
|
||||
struct ieee80211_hw *hw;
|
||||
struct mutex mutex;
|
||||
enum carl9170_device_state state;
|
||||
spinlock_t state_lock;
|
||||
enum carl9170_restart_reasons last_reason;
|
||||
bool registered;
|
||||
|
||||
/* USB */
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct usb_anchor rx_anch;
|
||||
struct usb_anchor rx_work;
|
||||
struct usb_anchor rx_pool;
|
||||
struct usb_anchor tx_wait;
|
||||
struct usb_anchor tx_anch;
|
||||
struct usb_anchor tx_cmd;
|
||||
struct usb_anchor tx_err;
|
||||
struct tasklet_struct usb_tasklet;
|
||||
atomic_t tx_cmd_urbs;
|
||||
atomic_t tx_anch_urbs;
|
||||
atomic_t rx_anch_urbs;
|
||||
atomic_t rx_work_urbs;
|
||||
atomic_t rx_pool_urbs;
|
||||
kernel_ulong_t features;
|
||||
|
||||
/* firmware settings */
|
||||
struct completion fw_load_wait;
|
||||
struct completion fw_boot_wait;
|
||||
struct {
|
||||
const struct carl9170fw_desc_head *desc;
|
||||
const struct firmware *fw;
|
||||
unsigned int offset;
|
||||
unsigned int address;
|
||||
unsigned int cmd_bufs;
|
||||
unsigned int api_version;
|
||||
unsigned int vif_num;
|
||||
unsigned int err_counter;
|
||||
unsigned int bug_counter;
|
||||
u32 beacon_addr;
|
||||
unsigned int beacon_max_len;
|
||||
bool rx_stream;
|
||||
bool tx_stream;
|
||||
unsigned int mem_blocks;
|
||||
unsigned int mem_block_size;
|
||||
unsigned int rx_size;
|
||||
} fw;
|
||||
|
||||
/* reset / stuck frames/queue detection */
|
||||
struct work_struct restart_work;
|
||||
unsigned int restart_counter;
|
||||
unsigned long queue_stop_timeout[__AR9170_NUM_TXQ];
|
||||
unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ];
|
||||
bool needs_full_reset;
|
||||
atomic_t pending_restarts;
|
||||
|
||||
/* interface mode settings */
|
||||
struct list_head vif_list;
|
||||
unsigned long vif_bitmap;
|
||||
unsigned int vifs;
|
||||
struct carl9170_vif vif_priv[AR9170_MAX_VIRTUAL_MAC];
|
||||
|
||||
/* beaconing */
|
||||
spinlock_t beacon_lock;
|
||||
unsigned int global_pretbtt;
|
||||
unsigned int global_beacon_int;
|
||||
struct carl9170_vif_info *beacon_iter;
|
||||
unsigned int beacon_enabled;
|
||||
|
||||
/* cryptographic engine */
|
||||
u64 usedkeys;
|
||||
bool rx_software_decryption;
|
||||
bool disable_offload;
|
||||
|
||||
/* filter settings */
|
||||
u64 cur_mc_hash;
|
||||
u32 cur_filter;
|
||||
unsigned int filter_state;
|
||||
bool sniffer_enabled;
|
||||
|
||||
/* MAC */
|
||||
enum carl9170_erp_modes erp_mode;
|
||||
|
||||
/* PHY */
|
||||
struct ieee80211_channel *channel;
|
||||
int noise[4];
|
||||
unsigned int chan_fail;
|
||||
unsigned int total_chan_fail;
|
||||
u8 heavy_clip;
|
||||
u8 ht_settings;
|
||||
|
||||
/* power calibration data */
|
||||
u8 power_5G_leg[4];
|
||||
u8 power_2G_cck[4];
|
||||
u8 power_2G_ofdm[4];
|
||||
u8 power_5G_ht20[8];
|
||||
u8 power_5G_ht40[8];
|
||||
u8 power_2G_ht20[8];
|
||||
u8 power_2G_ht40[8];
|
||||
|
||||
#ifdef CONFIG_CARL9170_LEDS
|
||||
/* LED */
|
||||
struct delayed_work led_work;
|
||||
struct carl9170_led leds[AR9170_NUM_LEDS];
|
||||
#endif /* CONFIG_CARL9170_LEDS */
|
||||
|
||||
/* qos queue settings */
|
||||
spinlock_t tx_stats_lock;
|
||||
struct carl9170_tx_queue_stats tx_stats[__AR9170_NUM_TXQ];
|
||||
struct ieee80211_tx_queue_params edcf[5];
|
||||
struct completion tx_flush;
|
||||
|
||||
/* CMD */
|
||||
int cmd_seq;
|
||||
int readlen;
|
||||
u8 *readbuf;
|
||||
spinlock_t cmd_lock;
|
||||
struct completion cmd_wait;
|
||||
union {
|
||||
__le32 cmd_buf[PAYLOAD_MAX + 1];
|
||||
struct carl9170_cmd cmd;
|
||||
struct carl9170_rsp rsp;
|
||||
};
|
||||
|
||||
/* statistics */
|
||||
unsigned int tx_dropped;
|
||||
unsigned int tx_ack_failures;
|
||||
unsigned int tx_fcs_errors;
|
||||
unsigned int tx_ampdu_timeout;
|
||||
unsigned int rx_dropped;
|
||||
|
||||
/* EEPROM */
|
||||
struct ar9170_eeprom eeprom;
|
||||
|
||||
/* tx queuing */
|
||||
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
|
||||
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
|
||||
struct delayed_work tx_janitor;
|
||||
unsigned long tx_janitor_last_run;
|
||||
bool tx_schedule;
|
||||
|
||||
/* tx ampdu */
|
||||
struct work_struct ampdu_work;
|
||||
spinlock_t tx_ampdu_list_lock;
|
||||
struct carl9170_sta_tid *tx_ampdu_iter;
|
||||
struct list_head tx_ampdu_list;
|
||||
atomic_t tx_ampdu_upload;
|
||||
atomic_t tx_ampdu_scheduler;
|
||||
atomic_t tx_total_pending;
|
||||
atomic_t tx_total_queued;
|
||||
unsigned int tx_ampdu_list_len;
|
||||
int current_density;
|
||||
int current_factor;
|
||||
bool tx_ampdu_schedule;
|
||||
|
||||
/* internal memory management */
|
||||
spinlock_t mem_lock;
|
||||
unsigned long *mem_bitmap;
|
||||
atomic_t mem_free_blocks;
|
||||
atomic_t mem_allocs;
|
||||
|
||||
/* rxstream mpdu merge */
|
||||
struct ar9170_rx_head rx_plcp;
|
||||
bool rx_has_plcp;
|
||||
struct sk_buff *rx_failover;
|
||||
int rx_failover_missing;
|
||||
|
||||
#ifdef CONFIG_CARL9170_WPC
|
||||
struct {
|
||||
bool pbc_state;
|
||||
struct input_dev *pbc;
|
||||
char name[32];
|
||||
char phys[32];
|
||||
} wps;
|
||||
#endif /* CONFIG_CARL9170_WPC */
|
||||
|
||||
#ifdef CONFIG_CARL9170_DEBUGFS
|
||||
struct carl9170_debug debug;
|
||||
struct dentry *debug_dir;
|
||||
#endif /* CONFIG_CARL9170_DEBUGFS */
|
||||
|
||||
/* PSM */
|
||||
struct work_struct ps_work;
|
||||
struct {
|
||||
unsigned int dtim_counter;
|
||||
unsigned long last_beacon;
|
||||
unsigned long last_action;
|
||||
unsigned long last_slept;
|
||||
unsigned int sleep_ms;
|
||||
unsigned int off_override;
|
||||
bool state;
|
||||
} ps;
|
||||
};
|
||||
|
||||
enum carl9170_ps_off_override_reasons {
|
||||
PS_OFF_VIF = BIT(0),
|
||||
PS_OFF_BCN = BIT(1),
|
||||
PS_OFF_5GHZ = BIT(2),
|
||||
};
|
||||
|
||||
struct carl9170_ba_stats {
|
||||
u8 ampdu_len;
|
||||
u8 ampdu_ack_len;
|
||||
bool clear;
|
||||
};
|
||||
|
||||
struct carl9170_sta_info {
|
||||
bool ht_sta;
|
||||
unsigned int ampdu_max_len;
|
||||
struct carl9170_sta_tid *agg[CARL9170_NUM_TID];
|
||||
struct carl9170_ba_stats stats[CARL9170_NUM_TID];
|
||||
};
|
||||
|
||||
struct carl9170_tx_info {
|
||||
unsigned long timeout;
|
||||
struct ar9170 *ar;
|
||||
struct kref ref;
|
||||
};
|
||||
|
||||
#define CHK_DEV_STATE(a, s) (((struct ar9170 *)a)->state >= (s))
|
||||
#define IS_INITIALIZED(a) (CHK_DEV_STATE(a, CARL9170_STOPPED))
|
||||
#define IS_ACCEPTING_CMD(a) (CHK_DEV_STATE(a, CARL9170_IDLE))
|
||||
#define IS_STARTED(a) (CHK_DEV_STATE(a, CARL9170_STARTED))
|
||||
|
||||
static inline void __carl9170_set_state(struct ar9170 *ar,
|
||||
enum carl9170_device_state newstate)
|
||||
{
|
||||
ar->state = newstate;
|
||||
}
|
||||
|
||||
static inline void carl9170_set_state(struct ar9170 *ar,
|
||||
enum carl9170_device_state newstate)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ar->state_lock, flags);
|
||||
__carl9170_set_state(ar, newstate);
|
||||
spin_unlock_irqrestore(&ar->state_lock, flags);
|
||||
}
|
||||
|
||||
static inline void carl9170_set_state_when(struct ar9170 *ar,
|
||||
enum carl9170_device_state min, enum carl9170_device_state newstate)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ar->state_lock, flags);
|
||||
if (CHK_DEV_STATE(ar, min))
|
||||
__carl9170_set_state(ar, newstate);
|
||||
spin_unlock_irqrestore(&ar->state_lock, flags);
|
||||
}
|
||||
|
||||
/* exported interface */
|
||||
void *carl9170_alloc(size_t priv_size);
|
||||
int carl9170_register(struct ar9170 *ar);
|
||||
void carl9170_unregister(struct ar9170 *ar);
|
||||
void carl9170_free(struct ar9170 *ar);
|
||||
void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r);
|
||||
void carl9170_ps_check(struct ar9170 *ar);
|
||||
|
||||
/* USB back-end */
|
||||
int carl9170_usb_open(struct ar9170 *ar);
|
||||
void carl9170_usb_stop(struct ar9170 *ar);
|
||||
void carl9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb);
|
||||
void carl9170_usb_handle_tx_err(struct ar9170 *ar);
|
||||
int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids,
|
||||
u32 plen, void *payload, u32 rlen, void *resp);
|
||||
int __carl9170_exec_cmd(struct ar9170 *ar, struct carl9170_cmd *cmd,
|
||||
const bool free_buf);
|
||||
int carl9170_usb_restart(struct ar9170 *ar);
|
||||
void carl9170_usb_reset(struct ar9170 *ar);
|
||||
|
||||
/* MAC */
|
||||
int carl9170_init_mac(struct ar9170 *ar);
|
||||
int carl9170_set_qos(struct ar9170 *ar);
|
||||
int carl9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
|
||||
int carl9170_mod_virtual_mac(struct ar9170 *ar, const unsigned int id,
|
||||
const u8 *mac);
|
||||
int carl9170_set_operating_mode(struct ar9170 *ar);
|
||||
int carl9170_set_beacon_timers(struct ar9170 *ar);
|
||||
int carl9170_set_dyn_sifs_ack(struct ar9170 *ar);
|
||||
int carl9170_set_rts_cts_rate(struct ar9170 *ar);
|
||||
int carl9170_set_ampdu_settings(struct ar9170 *ar);
|
||||
int carl9170_set_slot_time(struct ar9170 *ar);
|
||||
int carl9170_set_mac_rates(struct ar9170 *ar);
|
||||
int carl9170_set_hwretry_limit(struct ar9170 *ar, const u32 max_retry);
|
||||
int carl9170_update_beacon(struct ar9170 *ar, const bool submit);
|
||||
int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
|
||||
const u8 ktype, const u8 keyidx, const u8 *keydata, const int keylen);
|
||||
int carl9170_disable_key(struct ar9170 *ar, const u8 id);
|
||||
|
||||
/* RX */
|
||||
void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len);
|
||||
void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
|
||||
|
||||
/* TX */
|
||||
int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
void carl9170_tx_janitor(struct work_struct *work);
|
||||
void carl9170_tx_process_status(struct ar9170 *ar,
|
||||
const struct carl9170_rsp *cmd);
|
||||
void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
|
||||
const bool success);
|
||||
void carl9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb);
|
||||
void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb);
|
||||
void carl9170_tx_scheduler(struct ar9170 *ar);
|
||||
void carl9170_tx_get_skb(struct sk_buff *skb);
|
||||
int carl9170_tx_put_skb(struct sk_buff *skb);
|
||||
|
||||
/* LEDs */
|
||||
#ifdef CONFIG_CARL9170_LEDS
|
||||
int carl9170_led_register(struct ar9170 *ar);
|
||||
void carl9170_led_unregister(struct ar9170 *ar);
|
||||
#endif /* CONFIG_CARL9170_LEDS */
|
||||
int carl9170_led_init(struct ar9170 *ar);
|
||||
int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
|
||||
|
||||
/* PHY / RF */
|
||||
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type bw, enum carl9170_rf_init_mode rfi);
|
||||
int carl9170_get_noisefloor(struct ar9170 *ar);
|
||||
|
||||
/* FW */
|
||||
int carl9170_parse_firmware(struct ar9170 *ar);
|
||||
int carl9170_fw_fix_eeprom(struct ar9170 *ar);
|
||||
|
||||
extern struct ieee80211_rate __carl9170_ratetable[];
|
||||
extern int modparam_noht;
|
||||
|
||||
static inline struct ar9170 *carl9170_get_priv(struct carl9170_vif *carl_vif)
|
||||
{
|
||||
return container_of(carl_vif, struct ar9170,
|
||||
vif_priv[carl_vif->id]);
|
||||
}
|
||||
|
||||
static inline struct ieee80211_hdr *carl9170_get_hdr(struct sk_buff *skb)
|
||||
{
|
||||
return (void *)((struct _carl9170_tx_superframe *)
|
||||
skb->data)->frame_data;
|
||||
}
|
||||
|
||||
static inline u16 get_seq_h(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
return le16_to_cpu(hdr->seq_ctrl) >> 4;
|
||||
}
|
||||
|
||||
static inline u16 carl9170_get_seq(struct sk_buff *skb)
|
||||
{
|
||||
return get_seq_h(carl9170_get_hdr(skb));
|
||||
}
|
||||
|
||||
static inline u16 get_tid_h(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
}
|
||||
|
||||
static inline u16 carl9170_get_tid(struct sk_buff *skb)
|
||||
{
|
||||
return get_tid_h(carl9170_get_hdr(skb));
|
||||
}
|
||||
|
||||
static inline struct ieee80211_vif *
|
||||
carl9170_get_vif(struct carl9170_vif_info *priv)
|
||||
{
|
||||
return container_of((void *)priv, struct ieee80211_vif, drv_priv);
|
||||
}
|
||||
|
||||
/* Protected by ar->mutex or RCU */
|
||||
static inline struct ieee80211_vif *carl9170_get_main_vif(struct ar9170 *ar)
|
||||
{
|
||||
struct carl9170_vif_info *cvif;
|
||||
|
||||
list_for_each_entry_rcu(cvif, &ar->vif_list, list) {
|
||||
if (cvif->active)
|
||||
return carl9170_get_vif(cvif);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool is_main_vif(struct ar9170 *ar, struct ieee80211_vif *vif)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
rcu_read_lock();
|
||||
ret = (carl9170_get_main_vif(ar) == vif);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __CARL9170_H */
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* Basic HW register/memory/command access functions
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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 "carl9170.h"
|
||||
#include "cmd.h"
|
||||
|
||||
int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
|
||||
{
|
||||
__le32 buf[2] = {
|
||||
cpu_to_le32(reg),
|
||||
cpu_to_le32(val),
|
||||
};
|
||||
int err;
|
||||
|
||||
err = carl9170_exec_cmd(ar, CARL9170_CMD_WREG, sizeof(buf),
|
||||
(u8 *) buf, 0, NULL);
|
||||
if (err) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "writing reg %#x "
|
||||
"(val %#x) failed (%d)\n", reg, val, err);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
|
||||
const u32 *regs, u32 *out)
|
||||
{
|
||||
int i, err;
|
||||
__le32 *offs, *res;
|
||||
|
||||
/* abuse "out" for the register offsets, must be same length */
|
||||
offs = (__le32 *)out;
|
||||
for (i = 0; i < nregs; i++)
|
||||
offs[i] = cpu_to_le32(regs[i]);
|
||||
|
||||
/* also use the same buffer for the input */
|
||||
res = (__le32 *)out;
|
||||
|
||||
err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
|
||||
4 * nregs, (u8 *)offs,
|
||||
4 * nregs, (u8 *)res);
|
||||
if (err) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "reading regs failed (%d)\n",
|
||||
err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* convert result to cpu endian */
|
||||
for (i = 0; i < nregs; i++)
|
||||
out[i] = le32_to_cpu(res[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int carl9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
|
||||
{
|
||||
return carl9170_read_mreg(ar, 1, ®, val);
|
||||
}
|
||||
|
||||
int carl9170_echo_test(struct ar9170 *ar, const u32 v)
|
||||
{
|
||||
u32 echores;
|
||||
int err;
|
||||
|
||||
err = carl9170_exec_cmd(ar, CARL9170_CMD_ECHO,
|
||||
4, (u8 *)&v,
|
||||
4, (u8 *)&echores);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (v != echores) {
|
||||
wiphy_info(ar->hw->wiphy, "wrong echo %x != %x", v, echores);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
|
||||
const enum carl9170_cmd_oids cmd, const unsigned int len)
|
||||
{
|
||||
struct carl9170_cmd *tmp;
|
||||
|
||||
tmp = kzalloc(sizeof(struct carl9170_cmd_head) + len, GFP_ATOMIC);
|
||||
if (tmp) {
|
||||
tmp->hdr.cmd = cmd;
|
||||
tmp->hdr.len = len;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int carl9170_reboot(struct ar9170 *ar)
|
||||
{
|
||||
struct carl9170_cmd *cmd;
|
||||
int err;
|
||||
|
||||
cmd = carl9170_cmd_buf(ar, CARL9170_CMD_REBOOT_ASYNC, 0);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
err = __carl9170_exec_cmd(ar, (struct carl9170_cmd *)cmd, true);
|
||||
return err;
|
||||
}
|
||||
|
||||
int carl9170_mac_reset(struct ar9170 *ar)
|
||||
{
|
||||
return carl9170_exec_cmd(ar, CARL9170_CMD_SWRST,
|
||||
0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
|
||||
const u32 mode, const u32 addr, const u32 len)
|
||||
{
|
||||
struct carl9170_cmd *cmd;
|
||||
|
||||
cmd = carl9170_cmd_buf(ar, CARL9170_CMD_BCN_CTRL_ASYNC,
|
||||
sizeof(struct carl9170_bcn_ctrl_cmd));
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->bcn_ctrl.vif_id = cpu_to_le32(vif_id);
|
||||
cmd->bcn_ctrl.mode = cpu_to_le32(mode);
|
||||
cmd->bcn_ctrl.bcn_addr = cpu_to_le32(addr);
|
||||
cmd->bcn_ctrl.bcn_len = cpu_to_le32(len);
|
||||
|
||||
return __carl9170_exec_cmd(ar, cmd, true);
|
||||
}
|
||||
|
||||
int carl9170_powersave(struct ar9170 *ar, const bool ps)
|
||||
{
|
||||
struct carl9170_cmd *cmd;
|
||||
u32 state;
|
||||
|
||||
cmd = carl9170_cmd_buf(ar, CARL9170_CMD_PSM_ASYNC,
|
||||
sizeof(struct carl9170_psm));
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ps) {
|
||||
/* Sleep until next TBTT */
|
||||
state = CARL9170_PSM_SLEEP | 1;
|
||||
} else {
|
||||
/* wake up immediately */
|
||||
state = 1;
|
||||
}
|
||||
|
||||
cmd->psm.state = cpu_to_le32(state);
|
||||
return __carl9170_exec_cmd(ar, cmd, true);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* Basic HW register/memory/command access functions
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
#ifndef __CMD_H
|
||||
#define __CMD_H
|
||||
|
||||
#include "carl9170.h"
|
||||
|
||||
/* basic HW access */
|
||||
int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
|
||||
int carl9170_read_reg(struct ar9170 *ar, const u32 reg, u32 *val);
|
||||
int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
|
||||
const u32 *regs, u32 *out);
|
||||
int carl9170_echo_test(struct ar9170 *ar, u32 v);
|
||||
int carl9170_reboot(struct ar9170 *ar);
|
||||
int carl9170_mac_reset(struct ar9170 *ar);
|
||||
int carl9170_powersave(struct ar9170 *ar, const bool power_on);
|
||||
int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
|
||||
const u32 mode, const u32 addr, const u32 len);
|
||||
|
||||
static inline int carl9170_flush_cab(struct ar9170 *ar,
|
||||
const unsigned int vif_id)
|
||||
{
|
||||
return carl9170_bcn_ctrl(ar, vif_id, CARL9170_BCN_CTRL_DRAIN, 0, 0);
|
||||
}
|
||||
|
||||
struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
|
||||
const enum carl9170_cmd_oids cmd, const unsigned int len);
|
||||
|
||||
/*
|
||||
* Macros to facilitate writing multiple registers in a single
|
||||
* write-combining USB command. Note that when the first group
|
||||
* fails the whole thing will fail without any others attempted,
|
||||
* but you won't know which write in the group failed.
|
||||
*/
|
||||
#define carl9170_regwrite_begin(ar) \
|
||||
do { \
|
||||
int __nreg = 0, __err = 0; \
|
||||
struct ar9170 *__ar = ar;
|
||||
|
||||
#define carl9170_regwrite(r, v) do { \
|
||||
__ar->cmd_buf[2 * __nreg + 1] = cpu_to_le32(r); \
|
||||
__ar->cmd_buf[2 * __nreg + 2] = cpu_to_le32(v); \
|
||||
__nreg++; \
|
||||
if ((__nreg >= PAYLOAD_MAX/2)) { \
|
||||
if (IS_ACCEPTING_CMD(__ar)) \
|
||||
__err = carl9170_exec_cmd(__ar, \
|
||||
CARL9170_CMD_WREG, 8 * __nreg, \
|
||||
(u8 *) &__ar->cmd_buf[1], 0, NULL); \
|
||||
else \
|
||||
goto __regwrite_out; \
|
||||
\
|
||||
__nreg = 0; \
|
||||
if (__err) \
|
||||
goto __regwrite_out; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define carl9170_regwrite_finish() \
|
||||
__regwrite_out : \
|
||||
if (__err == 0 && __nreg) { \
|
||||
if (IS_ACCEPTING_CMD(__ar)) \
|
||||
__err = carl9170_exec_cmd(__ar, \
|
||||
CARL9170_CMD_WREG, 8 * __nreg, \
|
||||
(u8 *) &__ar->cmd_buf[1], 0, NULL); \
|
||||
__nreg = 0; \
|
||||
}
|
||||
|
||||
#define carl9170_regwrite_result() \
|
||||
__err; \
|
||||
} while (0);
|
||||
|
||||
|
||||
#define carl9170_async_get_buf() \
|
||||
do { \
|
||||
__cmd = carl9170_cmd_buf(__carl, CARL9170_CMD_WREG_ASYNC, \
|
||||
CARL9170_MAX_CMD_PAYLOAD_LEN); \
|
||||
if (__cmd == NULL) { \
|
||||
__err = -ENOMEM; \
|
||||
goto __async_regwrite_out; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define carl9170_async_regwrite_begin(carl) \
|
||||
do { \
|
||||
int __nreg = 0, __err = 0; \
|
||||
struct ar9170 *__carl = carl; \
|
||||
struct carl9170_cmd *__cmd; \
|
||||
carl9170_async_get_buf(); \
|
||||
|
||||
#define carl9170_async_regwrite(r, v) do { \
|
||||
__cmd->wreg.regs[__nreg].addr = cpu_to_le32(r); \
|
||||
__cmd->wreg.regs[__nreg].val = cpu_to_le32(v); \
|
||||
__nreg++; \
|
||||
if ((__nreg >= PAYLOAD_MAX/2)) { \
|
||||
if (IS_ACCEPTING_CMD(__carl)) { \
|
||||
__cmd->hdr.len = 8 * __nreg; \
|
||||
__err = __carl9170_exec_cmd(__carl, __cmd, true);\
|
||||
__cmd = NULL; \
|
||||
carl9170_async_get_buf(); \
|
||||
} else { \
|
||||
goto __async_regwrite_out; \
|
||||
} \
|
||||
__nreg = 0; \
|
||||
if (__err) \
|
||||
goto __async_regwrite_out; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define carl9170_async_regwrite_finish() \
|
||||
__async_regwrite_out : \
|
||||
if (__err == 0 && __nreg) { \
|
||||
__cmd->hdr.len = 8 * __nreg; \
|
||||
if (IS_ACCEPTING_CMD(__carl)) \
|
||||
__err = __carl9170_exec_cmd(__carl, __cmd, true);\
|
||||
__nreg = 0; \
|
||||
}
|
||||
|
||||
#define carl9170_async_regwrite_result() \
|
||||
__err; \
|
||||
} while (0);
|
||||
|
||||
#endif /* __CMD_H */
|
|
@ -0,0 +1,906 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* debug(fs) probing
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2008-2009 Atheros Communications, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "carl9170.h"
|
||||
#include "cmd.h"
|
||||
|
||||
#define ADD(buf, off, max, fmt, args...) \
|
||||
off += snprintf(&buf[off], max - off, fmt, ##args);
|
||||
|
||||
static int carl9170_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct carl9170_debugfs_fops {
|
||||
unsigned int read_bufsize;
|
||||
mode_t attr;
|
||||
char *(*read)(struct ar9170 *ar, char *buf, size_t bufsize,
|
||||
ssize_t *len);
|
||||
ssize_t (*write)(struct ar9170 *aru, const char *buf, size_t size);
|
||||
const struct file_operations fops;
|
||||
|
||||
enum carl9170_device_state req_dev_state;
|
||||
};
|
||||
|
||||
static ssize_t carl9170_debugfs_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct carl9170_debugfs_fops *dfops;
|
||||
struct ar9170 *ar;
|
||||
char *buf = NULL, *res_buf = NULL;
|
||||
ssize_t ret = 0;
|
||||
int err = 0;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
ar = file->private_data;
|
||||
|
||||
if (!ar)
|
||||
return -ENODEV;
|
||||
dfops = container_of(file->f_op, struct carl9170_debugfs_fops, fops);
|
||||
|
||||
if (!dfops->read)
|
||||
return -ENOSYS;
|
||||
|
||||
if (dfops->read_bufsize) {
|
||||
buf = vmalloc(dfops->read_bufsize);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
if (!CHK_DEV_STATE(ar, dfops->req_dev_state)) {
|
||||
err = -ENODEV;
|
||||
res_buf = buf;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res_buf = dfops->read(ar, buf, dfops->read_bufsize, &ret);
|
||||
|
||||
if (ret > 0)
|
||||
err = simple_read_from_buffer(userbuf, count, ppos,
|
||||
res_buf, ret);
|
||||
else
|
||||
err = ret;
|
||||
|
||||
WARN_ON_ONCE(dfops->read_bufsize && (res_buf != buf));
|
||||
|
||||
out_free:
|
||||
vfree(res_buf);
|
||||
mutex_unlock(&ar->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t carl9170_debugfs_write(struct file *file,
|
||||
const char __user *userbuf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct carl9170_debugfs_fops *dfops;
|
||||
struct ar9170 *ar;
|
||||
char *buf = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (count > PAGE_SIZE)
|
||||
return -E2BIG;
|
||||
|
||||
ar = file->private_data;
|
||||
|
||||
if (!ar)
|
||||
return -ENODEV;
|
||||
dfops = container_of(file->f_op, struct carl9170_debugfs_fops, fops);
|
||||
|
||||
if (!dfops->write)
|
||||
return -ENOSYS;
|
||||
|
||||
buf = vmalloc(count);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, userbuf, count)) {
|
||||
err = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (mutex_trylock(&ar->mutex) == 0) {
|
||||
err = -EAGAIN;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (!CHK_DEV_STATE(ar, dfops->req_dev_state)) {
|
||||
err = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = dfops->write(ar, buf, count);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&ar->mutex);
|
||||
|
||||
out_free:
|
||||
vfree(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
#define __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \
|
||||
_attr, _dstate) \
|
||||
static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\
|
||||
.read_bufsize = _read_bufsize, \
|
||||
.read = _read, \
|
||||
.write = _write, \
|
||||
.attr = _attr, \
|
||||
.req_dev_state = _dstate, \
|
||||
.fops = { \
|
||||
.open = carl9170_debugfs_open, \
|
||||
.read = carl9170_debugfs_read, \
|
||||
.write = carl9170_debugfs_write, \
|
||||
.owner = THIS_MODULE \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, _attr) \
|
||||
__DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \
|
||||
_attr, CARL9170_STARTED) \
|
||||
|
||||
#define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \
|
||||
DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
|
||||
NULL, _read_bufsize, S_IRUSR)
|
||||
|
||||
#define DEBUGFS_DECLARE_WO_FILE(name) \
|
||||
DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\
|
||||
0, S_IWUSR)
|
||||
|
||||
#define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \
|
||||
DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
|
||||
carl9170_debugfs_##name ##_write, \
|
||||
_read_bufsize, S_IRUSR | S_IWUSR)
|
||||
|
||||
#define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \
|
||||
__DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
|
||||
carl9170_debugfs_##name ##_write, \
|
||||
_read_bufsize, S_IRUSR | S_IWUSR, _dstate)
|
||||
|
||||
#define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \
|
||||
static char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \
|
||||
char *buf, size_t buf_size,\
|
||||
ssize_t *len) \
|
||||
{ \
|
||||
ADD(buf, *len, buf_size, fmt "\n", ##value); \
|
||||
return buf; \
|
||||
} \
|
||||
DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize)
|
||||
|
||||
static char *carl9170_debugfs_mem_usage_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
ADD(buf, *len, bufsize, "jar: [");
|
||||
|
||||
spin_lock_bh(&ar->mem_lock);
|
||||
|
||||
*len += bitmap_scnprintf(&buf[*len], bufsize - *len,
|
||||
ar->mem_bitmap, ar->fw.mem_blocks);
|
||||
|
||||
ADD(buf, *len, bufsize, "]\n");
|
||||
|
||||
ADD(buf, *len, bufsize, "cookies: used:%3d / total:%3d, allocs:%d\n",
|
||||
bitmap_weight(ar->mem_bitmap, ar->fw.mem_blocks),
|
||||
ar->fw.mem_blocks, atomic_read(&ar->mem_allocs));
|
||||
|
||||
ADD(buf, *len, bufsize, "memory: free:%3d (%3d KiB) / total:%3d KiB)\n",
|
||||
atomic_read(&ar->mem_free_blocks),
|
||||
(atomic_read(&ar->mem_free_blocks) * ar->fw.mem_block_size) / 1024,
|
||||
(ar->fw.mem_blocks * ar->fw.mem_block_size) / 1024);
|
||||
|
||||
spin_unlock_bh(&ar->mem_lock);
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(mem_usage, 512);
|
||||
|
||||
static char *carl9170_debugfs_qos_stat_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
ADD(buf, *len, bufsize, "%s QoS AC\n", modparam_noht ? "Hardware" :
|
||||
"Software");
|
||||
|
||||
ADD(buf, *len, bufsize, "[ VO VI "
|
||||
" BE BK ]\n");
|
||||
|
||||
spin_lock_bh(&ar->tx_stats_lock);
|
||||
ADD(buf, *len, bufsize, "[length/limit length/limit "
|
||||
"length/limit length/limit ]\n"
|
||||
"[ %3d/%3d %3d/%3d "
|
||||
" %3d/%3d %3d/%3d ]\n\n",
|
||||
ar->tx_stats[0].len, ar->tx_stats[0].limit,
|
||||
ar->tx_stats[1].len, ar->tx_stats[1].limit,
|
||||
ar->tx_stats[2].len, ar->tx_stats[2].limit,
|
||||
ar->tx_stats[3].len, ar->tx_stats[3].limit);
|
||||
|
||||
ADD(buf, *len, bufsize, "[ total total "
|
||||
" total total ]\n"
|
||||
"[%10d %10d %10d %10d ]\n\n",
|
||||
ar->tx_stats[0].count, ar->tx_stats[1].count,
|
||||
ar->tx_stats[2].count, ar->tx_stats[3].count);
|
||||
|
||||
spin_unlock_bh(&ar->tx_stats_lock);
|
||||
|
||||
ADD(buf, *len, bufsize, "[ pend/waittx pend/waittx "
|
||||
" pend/waittx pend/waittx]\n"
|
||||
"[ %3d/%3d %3d/%3d "
|
||||
" %3d/%3d %3d/%3d ]\n\n",
|
||||
skb_queue_len(&ar->tx_pending[0]),
|
||||
skb_queue_len(&ar->tx_status[0]),
|
||||
skb_queue_len(&ar->tx_pending[1]),
|
||||
skb_queue_len(&ar->tx_status[1]),
|
||||
skb_queue_len(&ar->tx_pending[2]),
|
||||
skb_queue_len(&ar->tx_status[2]),
|
||||
skb_queue_len(&ar->tx_pending[3]),
|
||||
skb_queue_len(&ar->tx_status[3]));
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(qos_stat, 512);
|
||||
|
||||
static void carl9170_debugfs_format_frame(struct ar9170 *ar,
|
||||
struct sk_buff *skb, const char *prefix, char *buf,
|
||||
ssize_t *off, ssize_t bufsize)
|
||||
{
|
||||
struct _carl9170_tx_superframe *txc = (void *) skb->data;
|
||||
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
|
||||
struct carl9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
|
||||
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
|
||||
|
||||
ADD(buf, *off, bufsize, "%s %p, c:%2x, DA:%pM, sq:%4d, mc:%.4x, "
|
||||
"pc:%.8x, to:%d ms\n", prefix, skb, txc->s.cookie,
|
||||
ieee80211_get_DA(hdr), get_seq_h(hdr),
|
||||
le16_to_cpu(txc->f.mac_control), le32_to_cpu(txc->f.phy_control),
|
||||
jiffies_to_msecs(jiffies - arinfo->timeout));
|
||||
}
|
||||
|
||||
|
||||
static char *carl9170_debugfs_ampdu_state_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
struct carl9170_sta_tid *iter;
|
||||
struct sk_buff *skb;
|
||||
int cnt = 0, fc;
|
||||
int offset;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) {
|
||||
|
||||
spin_lock_bh(&iter->lock);
|
||||
ADD(buf, *len, bufsize, "Entry: #%2d TID:%1d, BSN:%4d, "
|
||||
"SNX:%4d, HSN:%4d, BAW:%2d, state:%1d, toggles:%d\n",
|
||||
cnt, iter->tid, iter->bsn, iter->snx, iter->hsn,
|
||||
iter->max, iter->state, iter->counter);
|
||||
|
||||
ADD(buf, *len, bufsize, "\tWindow: [");
|
||||
|
||||
*len += bitmap_scnprintf(&buf[*len], bufsize - *len,
|
||||
iter->bitmap, CARL9170_BAW_BITS);
|
||||
|
||||
#define BM_STR_OFF(offset) \
|
||||
((CARL9170_BAW_BITS - (offset) - 1) / 4 + \
|
||||
(CARL9170_BAW_BITS - (offset) - 1) / 32 + 1)
|
||||
|
||||
ADD(buf, *len, bufsize, ",W]\n");
|
||||
|
||||
offset = BM_STR_OFF(0);
|
||||
ADD(buf, *len, bufsize, "\tBase Seq: %*s\n", offset, "T");
|
||||
|
||||
offset = BM_STR_OFF(SEQ_DIFF(iter->snx, iter->bsn));
|
||||
ADD(buf, *len, bufsize, "\tNext Seq: %*s\n", offset, "W");
|
||||
|
||||
offset = BM_STR_OFF(((int)iter->hsn - (int)iter->bsn) %
|
||||
CARL9170_BAW_BITS);
|
||||
ADD(buf, *len, bufsize, "\tLast Seq: %*s\n", offset, "N");
|
||||
|
||||
ADD(buf, *len, bufsize, "\tPre-Aggregation reorder buffer: "
|
||||
" currently queued:%d\n", skb_queue_len(&iter->queue));
|
||||
|
||||
fc = 0;
|
||||
skb_queue_walk(&iter->queue, skb) {
|
||||
char prefix[32];
|
||||
|
||||
snprintf(prefix, sizeof(prefix), "\t\t%3d :", fc);
|
||||
carl9170_debugfs_format_frame(ar, skb, prefix, buf,
|
||||
len, bufsize);
|
||||
|
||||
fc++;
|
||||
}
|
||||
spin_unlock_bh(&iter->lock);
|
||||
cnt++;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(ampdu_state, 8000);
|
||||
|
||||
static void carl9170_debugfs_queue_dump(struct ar9170 *ar, char *buf,
|
||||
ssize_t *len, size_t bufsize, struct sk_buff_head *queue)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
char prefix[16];
|
||||
int fc = 0;
|
||||
|
||||
spin_lock_bh(&queue->lock);
|
||||
skb_queue_walk(queue, skb) {
|
||||
snprintf(prefix, sizeof(prefix), "%3d :", fc);
|
||||
carl9170_debugfs_format_frame(ar, skb, prefix, buf,
|
||||
len, bufsize);
|
||||
fc++;
|
||||
}
|
||||
spin_unlock_bh(&queue->lock);
|
||||
}
|
||||
|
||||
#define DEBUGFS_QUEUE_DUMP(q, qi) \
|
||||
static char *carl9170_debugfs_##q ##_##qi ##_read(struct ar9170 *ar, \
|
||||
char *buf, size_t bufsize, ssize_t *len) \
|
||||
{ \
|
||||
carl9170_debugfs_queue_dump(ar, buf, len, bufsize, &ar->q[qi]); \
|
||||
return buf; \
|
||||
} \
|
||||
DEBUGFS_DECLARE_RO_FILE(q##_##qi, 8000);
|
||||
|
||||
static char *carl9170_debugfs_sta_psm_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
ADD(buf, *len, bufsize, "psm state: %s\n", (ar->ps.off_override ?
|
||||
"FORCE CAM" : (ar->ps.state ? "PSM" : "CAM")));
|
||||
|
||||
ADD(buf, *len, bufsize, "sleep duration: %d ms.\n", ar->ps.sleep_ms);
|
||||
ADD(buf, *len, bufsize, "last power-state transition: %d ms ago.\n",
|
||||
jiffies_to_msecs(jiffies - ar->ps.last_action));
|
||||
ADD(buf, *len, bufsize, "last CAM->PSM transition: %d ms ago.\n",
|
||||
jiffies_to_msecs(jiffies - ar->ps.last_slept));
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(sta_psm, 160);
|
||||
|
||||
static char *carl9170_debugfs_tx_stuck_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ar->hw->queues; i++) {
|
||||
ADD(buf, *len, bufsize, "TX queue [%d]: %10d max:%10d ms.\n",
|
||||
i, ieee80211_queue_stopped(ar->hw, i) ?
|
||||
jiffies_to_msecs(jiffies - ar->queue_stop_timeout[i]) : 0,
|
||||
jiffies_to_msecs(ar->max_queue_stop_timeout[i]));
|
||||
|
||||
ar->max_queue_stop_timeout[i] = 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(tx_stuck, 180);
|
||||
|
||||
static char *carl9170_debugfs_phy_noise_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = carl9170_get_noisefloor(ar);
|
||||
if (err) {
|
||||
*len = err;
|
||||
return buf;
|
||||
}
|
||||
|
||||
ADD(buf, *len, bufsize, "Chain 0: %10d dBm, ext. chan.:%10d dBm\n",
|
||||
ar->noise[0], ar->noise[2]);
|
||||
ADD(buf, *len, bufsize, "Chain 2: %10d dBm, ext. chan.:%10d dBm\n",
|
||||
ar->noise[1], ar->noise[3]);
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(phy_noise, 180);
|
||||
|
||||
static char *carl9170_debugfs_vif_dump_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *len)
|
||||
{
|
||||
struct carl9170_vif_info *iter;
|
||||
int i = 0;
|
||||
|
||||
ADD(buf, *len, bufsize, "registered VIFs:%d \\ %d\n",
|
||||
ar->vifs, ar->fw.vif_num);
|
||||
|
||||
ADD(buf, *len, bufsize, "VIF bitmap: [");
|
||||
|
||||
*len += bitmap_scnprintf(&buf[*len], bufsize - *len,
|
||||
&ar->vif_bitmap, ar->fw.vif_num);
|
||||
|
||||
ADD(buf, *len, bufsize, "]\n");
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(iter, &ar->vif_list, list) {
|
||||
struct ieee80211_vif *vif = carl9170_get_vif(iter);
|
||||
ADD(buf, *len, bufsize, "\t%d = [%s VIF, id:%d, type:%x "
|
||||
" mac:%pM %s]\n", i, (carl9170_get_main_vif(ar) == vif ?
|
||||
"Master" : " Slave"), iter->id, vif->type, vif->addr,
|
||||
iter->enable_beacon ? "beaconing " : "");
|
||||
i++;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RO_FILE(vif_dump, 8000);
|
||||
|
||||
#define UPDATE_COUNTER(ar, name) ({ \
|
||||
u32 __tmp[ARRAY_SIZE(name##_regs)]; \
|
||||
unsigned int __i, __err = -ENODEV; \
|
||||
\
|
||||
for (__i = 0; __i < ARRAY_SIZE(name##_regs); __i++) { \
|
||||
__tmp[__i] = name##_regs[__i].reg; \
|
||||
ar->debug.stats.name##_counter[__i] = 0; \
|
||||
} \
|
||||
\
|
||||
if (IS_STARTED(ar)) \
|
||||
__err = carl9170_read_mreg(ar, ARRAY_SIZE(name##_regs), \
|
||||
__tmp, ar->debug.stats.name##_counter); \
|
||||
(__err); })
|
||||
|
||||
#define TALLY_SUM_UP(ar, name) do { \
|
||||
unsigned int __i; \
|
||||
\
|
||||
for (__i = 0; __i < ARRAY_SIZE(name##_regs); __i++) { \
|
||||
ar->debug.stats.name##_sum[__i] += \
|
||||
ar->debug.stats.name##_counter[__i]; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEBUGFS_HW_TALLY_FILE(name, f) \
|
||||
static char *carl9170_debugfs_##name ## _read(struct ar9170 *ar, \
|
||||
char *dum, size_t bufsize, ssize_t *ret) \
|
||||
{ \
|
||||
char *buf; \
|
||||
int i, max_len, err; \
|
||||
\
|
||||
max_len = ARRAY_SIZE(name##_regs) * 80; \
|
||||
buf = vmalloc(max_len); \
|
||||
if (!buf) \
|
||||
return NULL; \
|
||||
\
|
||||
err = UPDATE_COUNTER(ar, name); \
|
||||
if (err) { \
|
||||
*ret = err; \
|
||||
return buf; \
|
||||
} \
|
||||
\
|
||||
TALLY_SUM_UP(ar, name); \
|
||||
\
|
||||
for (i = 0; i < ARRAY_SIZE(name##_regs); i++) { \
|
||||
ADD(buf, *ret, max_len, "%22s = %" f "[+%" f "]\n", \
|
||||
name##_regs[i].nreg, ar->debug.stats.name ##_sum[i],\
|
||||
ar->debug.stats.name ##_counter[i]); \
|
||||
} \
|
||||
\
|
||||
return buf; \
|
||||
} \
|
||||
DEBUGFS_DECLARE_RO_FILE(name, 0);
|
||||
|
||||
#define DEBUGFS_HW_REG_FILE(name, f) \
|
||||
static char *carl9170_debugfs_##name ## _read(struct ar9170 *ar, \
|
||||
char *dum, size_t bufsize, ssize_t *ret) \
|
||||
{ \
|
||||
char *buf; \
|
||||
int i, max_len, err; \
|
||||
\
|
||||
max_len = ARRAY_SIZE(name##_regs) * 80; \
|
||||
buf = vmalloc(max_len); \
|
||||
if (!buf) \
|
||||
return NULL; \
|
||||
\
|
||||
err = UPDATE_COUNTER(ar, name); \
|
||||
if (err) { \
|
||||
*ret = err; \
|
||||
return buf; \
|
||||
} \
|
||||
\
|
||||
for (i = 0; i < ARRAY_SIZE(name##_regs); i++) { \
|
||||
ADD(buf, *ret, max_len, "%22s = %" f "\n", \
|
||||
name##_regs[i].nreg, \
|
||||
ar->debug.stats.name##_counter[i]); \
|
||||
} \
|
||||
\
|
||||
return buf; \
|
||||
} \
|
||||
DEBUGFS_DECLARE_RO_FILE(name, 0);
|
||||
|
||||
static ssize_t carl9170_debugfs_hw_ioread32_write(struct ar9170 *ar,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int err = 0, i, n = 0, max_len = 32, res;
|
||||
unsigned int reg, tmp;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (count > max_len)
|
||||
return -E2BIG;
|
||||
|
||||
res = sscanf(buf, "0x%X %d", ®, &n);
|
||||
if (res < 1) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (res == 1)
|
||||
n = 1;
|
||||
|
||||
if (n > 15) {
|
||||
err = -EMSGSIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((reg >= 0x280000) || ((reg + (n << 2)) >= 0x280000)) {
|
||||
err = -EADDRNOTAVAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (reg & 3) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
err = carl9170_read_reg(ar, reg + (i << 2), &tmp);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
ar->debug.ring[ar->debug.ring_tail].reg = reg + (i << 2);
|
||||
ar->debug.ring[ar->debug.ring_tail].value = tmp;
|
||||
ar->debug.ring_tail++;
|
||||
ar->debug.ring_tail %= CARL9170_DEBUG_RING_SIZE;
|
||||
}
|
||||
|
||||
out:
|
||||
return err ? err : count;
|
||||
}
|
||||
|
||||
static char *carl9170_debugfs_hw_ioread32_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *ret)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (ar->debug.ring_head != ar->debug.ring_tail) {
|
||||
ADD(buf, *ret, bufsize, "%.8x = %.8x\n",
|
||||
ar->debug.ring[ar->debug.ring_head].reg,
|
||||
ar->debug.ring[ar->debug.ring_head].value);
|
||||
|
||||
ar->debug.ring_head++;
|
||||
ar->debug.ring_head %= CARL9170_DEBUG_RING_SIZE;
|
||||
|
||||
if (i++ == 64)
|
||||
break;
|
||||
}
|
||||
ar->debug.ring_head = ar->debug.ring_tail;
|
||||
return buf;
|
||||
}
|
||||
DEBUGFS_DECLARE_RW_FILE(hw_ioread32, CARL9170_DEBUG_RING_SIZE * 40);
|
||||
|
||||
static ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
switch (buf[0]) {
|
||||
case 'F':
|
||||
ar->needs_full_reset = true;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (!IS_STARTED(ar)) {
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ar->needs_full_reset = false;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
err = carl9170_mac_reset(ar);
|
||||
if (err < 0)
|
||||
count = err;
|
||||
|
||||
goto out;
|
||||
|
||||
case 'P':
|
||||
err = carl9170_set_channel(ar, ar->hw->conf.channel,
|
||||
ar->hw->conf.channel_type, CARL9170_RFI_COLD);
|
||||
if (err < 0)
|
||||
count = err;
|
||||
|
||||
goto out;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
carl9170_restart(ar, CARL9170_RR_USER_REQUEST);
|
||||
|
||||
out:
|
||||
return count;
|
||||
}
|
||||
|
||||
static char *carl9170_debugfs_bug_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *ret)
|
||||
{
|
||||
ADD(buf, *ret, bufsize, "[P]hy reinit, [R]estart, [F]ull usb reset, "
|
||||
"[M]ac reset\n");
|
||||
ADD(buf, *ret, bufsize, "firmware restarts:%d, last reason:%d\n",
|
||||
ar->restart_counter, ar->last_reason);
|
||||
ADD(buf, *ret, bufsize, "phy reinit errors:%d (%d)\n",
|
||||
ar->total_chan_fail, ar->chan_fail);
|
||||
ADD(buf, *ret, bufsize, "reported firmware errors:%d\n",
|
||||
ar->fw.err_counter);
|
||||
ADD(buf, *ret, bufsize, "reported firmware BUGs:%d\n",
|
||||
ar->fw.bug_counter);
|
||||
ADD(buf, *ret, bufsize, "pending restart requests:%d\n",
|
||||
atomic_read(&ar->pending_restarts));
|
||||
return buf;
|
||||
}
|
||||
__DEBUGFS_DECLARE_RW_FILE(bug, 400, CARL9170_STOPPED);
|
||||
|
||||
static const char *erp_modes[] = {
|
||||
[CARL9170_ERP_INVALID] = "INVALID",
|
||||
[CARL9170_ERP_AUTO] = "Automatic",
|
||||
[CARL9170_ERP_MAC80211] = "Set by MAC80211",
|
||||
[CARL9170_ERP_OFF] = "Force Off",
|
||||
[CARL9170_ERP_RTS] = "Force RTS",
|
||||
[CARL9170_ERP_CTS] = "Force CTS"
|
||||
};
|
||||
|
||||
static char *carl9170_debugfs_erp_read(struct ar9170 *ar, char *buf,
|
||||
size_t bufsize, ssize_t *ret)
|
||||
{
|
||||
ADD(buf, *ret, bufsize, "ERP Setting: (%d) -> %s\n", ar->erp_mode,
|
||||
erp_modes[ar->erp_mode]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static ssize_t carl9170_debugfs_erp_write(struct ar9170 *ar, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int res, val;
|
||||
|
||||
if (count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
res = sscanf(buf, "%d", &val);
|
||||
if (res != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (!((val > CARL9170_ERP_INVALID) &&
|
||||
(val < __CARL9170_ERP_NUM)))
|
||||
return -EINVAL;
|
||||
|
||||
ar->erp_mode = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
DEBUGFS_DECLARE_RW_FILE(erp, 80);
|
||||
|
||||
static ssize_t carl9170_debugfs_hw_iowrite32_write(struct ar9170 *ar,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int err = 0, max_len = 22, res;
|
||||
u32 reg, val;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (count > max_len)
|
||||
return -E2BIG;
|
||||
|
||||
res = sscanf(buf, "0x%X 0x%X", ®, &val);
|
||||
if (res != 2) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (reg <= 0x100000 || reg >= 0x280000) {
|
||||
err = -EADDRNOTAVAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (reg & 3) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = carl9170_write_reg(ar, reg, val);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return err ? err : count;
|
||||
}
|
||||
DEBUGFS_DECLARE_WO_FILE(hw_iowrite32);
|
||||
|
||||
DEBUGFS_HW_TALLY_FILE(hw_tx_tally, "u");
|
||||
DEBUGFS_HW_TALLY_FILE(hw_rx_tally, "u");
|
||||
DEBUGFS_HW_TALLY_FILE(hw_phy_errors, "u");
|
||||
DEBUGFS_HW_REG_FILE(hw_wlan_queue, ".8x");
|
||||
DEBUGFS_HW_REG_FILE(hw_pta_queue, ".8x");
|
||||
DEBUGFS_HW_REG_FILE(hw_ampdu_info, ".8x");
|
||||
DEBUGFS_QUEUE_DUMP(tx_status, 0);
|
||||
DEBUGFS_QUEUE_DUMP(tx_status, 1);
|
||||
DEBUGFS_QUEUE_DUMP(tx_status, 2);
|
||||
DEBUGFS_QUEUE_DUMP(tx_status, 3);
|
||||
DEBUGFS_QUEUE_DUMP(tx_pending, 0);
|
||||
DEBUGFS_QUEUE_DUMP(tx_pending, 1);
|
||||
DEBUGFS_QUEUE_DUMP(tx_pending, 2);
|
||||
DEBUGFS_QUEUE_DUMP(tx_pending, 3);
|
||||
DEBUGFS_READONLY_FILE(usb_tx_anch_urbs, 20, "%d",
|
||||
atomic_read(&ar->tx_anch_urbs));
|
||||
DEBUGFS_READONLY_FILE(usb_rx_anch_urbs, 20, "%d",
|
||||
atomic_read(&ar->rx_anch_urbs));
|
||||
DEBUGFS_READONLY_FILE(usb_rx_work_urbs, 20, "%d",
|
||||
atomic_read(&ar->rx_work_urbs));
|
||||
DEBUGFS_READONLY_FILE(usb_rx_pool_urbs, 20, "%d",
|
||||
atomic_read(&ar->rx_pool_urbs));
|
||||
|
||||
DEBUGFS_READONLY_FILE(tx_total_queued, 20, "%d",
|
||||
atomic_read(&ar->tx_total_queued));
|
||||
DEBUGFS_READONLY_FILE(tx_ampdu_scheduler, 20, "%d",
|
||||
atomic_read(&ar->tx_ampdu_scheduler));
|
||||
DEBUGFS_READONLY_FILE(tx_ampdu_timeout, 20, "%d",
|
||||
ar->tx_ampdu_timeout);
|
||||
|
||||
DEBUGFS_READONLY_FILE(tx_total_pending, 20, "%d",
|
||||
atomic_read(&ar->tx_total_pending));
|
||||
|
||||
DEBUGFS_READONLY_FILE(tx_ampdu_list_len, 20, "%d",
|
||||
ar->tx_ampdu_list_len);
|
||||
|
||||
DEBUGFS_READONLY_FILE(tx_ampdu_upload, 20, "%d",
|
||||
atomic_read(&ar->tx_ampdu_upload));
|
||||
|
||||
DEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago",
|
||||
jiffies_to_msecs(jiffies - ar->tx_janitor_last_run));
|
||||
|
||||
DEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped);
|
||||
|
||||
DEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped);
|
||||
|
||||
DEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled);
|
||||
DEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d",
|
||||
ar->rx_software_decryption);
|
||||
DEBUGFS_READONLY_FILE(ampdu_factor, 20, "%d",
|
||||
ar->current_factor);
|
||||
DEBUGFS_READONLY_FILE(ampdu_density, 20, "%d",
|
||||
ar->current_density);
|
||||
|
||||
DEBUGFS_READONLY_FILE(beacon_int, 20, "%d TU", ar->global_beacon_int);
|
||||
DEBUGFS_READONLY_FILE(pretbtt, 20, "%d TU", ar->global_pretbtt);
|
||||
|
||||
void carl9170_debugfs_register(struct ar9170 *ar)
|
||||
{
|
||||
ar->debug_dir = debugfs_create_dir(KBUILD_MODNAME,
|
||||
ar->hw->wiphy->debugfsdir);
|
||||
|
||||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \
|
||||
ar->debug_dir, ar, \
|
||||
&carl_debugfs_##name ## _ops.fops);
|
||||
|
||||
DEBUGFS_ADD(usb_tx_anch_urbs);
|
||||
DEBUGFS_ADD(usb_rx_pool_urbs);
|
||||
DEBUGFS_ADD(usb_rx_anch_urbs);
|
||||
DEBUGFS_ADD(usb_rx_work_urbs);
|
||||
|
||||
DEBUGFS_ADD(tx_total_queued);
|
||||
DEBUGFS_ADD(tx_total_pending);
|
||||
DEBUGFS_ADD(tx_dropped);
|
||||
DEBUGFS_ADD(tx_stuck);
|
||||
DEBUGFS_ADD(tx_ampdu_upload);
|
||||
DEBUGFS_ADD(tx_ampdu_scheduler);
|
||||
DEBUGFS_ADD(tx_ampdu_list_len);
|
||||
|
||||
DEBUGFS_ADD(rx_dropped);
|
||||
DEBUGFS_ADD(sniffer_enabled);
|
||||
DEBUGFS_ADD(rx_software_decryption);
|
||||
|
||||
DEBUGFS_ADD(mem_usage);
|
||||
DEBUGFS_ADD(qos_stat);
|
||||
DEBUGFS_ADD(sta_psm);
|
||||
DEBUGFS_ADD(ampdu_state);
|
||||
|
||||
DEBUGFS_ADD(hw_tx_tally);
|
||||
DEBUGFS_ADD(hw_rx_tally);
|
||||
DEBUGFS_ADD(hw_phy_errors);
|
||||
DEBUGFS_ADD(phy_noise);
|
||||
|
||||
DEBUGFS_ADD(hw_wlan_queue);
|
||||
DEBUGFS_ADD(hw_pta_queue);
|
||||
DEBUGFS_ADD(hw_ampdu_info);
|
||||
|
||||
DEBUGFS_ADD(ampdu_density);
|
||||
DEBUGFS_ADD(ampdu_factor);
|
||||
|
||||
DEBUGFS_ADD(tx_ampdu_timeout);
|
||||
|
||||
DEBUGFS_ADD(tx_janitor_last_run);
|
||||
|
||||
DEBUGFS_ADD(tx_status_0);
|
||||
DEBUGFS_ADD(tx_status_1);
|
||||
DEBUGFS_ADD(tx_status_2);
|
||||
DEBUGFS_ADD(tx_status_3);
|
||||
|
||||
DEBUGFS_ADD(tx_pending_0);
|
||||
DEBUGFS_ADD(tx_pending_1);
|
||||
DEBUGFS_ADD(tx_pending_2);
|
||||
DEBUGFS_ADD(tx_pending_3);
|
||||
|
||||
DEBUGFS_ADD(hw_ioread32);
|
||||
DEBUGFS_ADD(hw_iowrite32);
|
||||
DEBUGFS_ADD(bug);
|
||||
|
||||
DEBUGFS_ADD(erp);
|
||||
|
||||
DEBUGFS_ADD(vif_dump);
|
||||
|
||||
DEBUGFS_ADD(beacon_int);
|
||||
DEBUGFS_ADD(pretbtt);
|
||||
|
||||
#undef DEBUGFS_ADD
|
||||
}
|
||||
|
||||
void carl9170_debugfs_unregister(struct ar9170 *ar)
|
||||
{
|
||||
debugfs_remove_recursive(ar->debug_dir);
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* debug header
|
||||
*
|
||||
* Copyright 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
#ifndef __DEBUG_H
|
||||
#define __DEBUG_H
|
||||
|
||||
#include "eeprom.h"
|
||||
#include "wlan.h"
|
||||
#include "hw.h"
|
||||
#include "fwdesc.h"
|
||||
#include "fwcmd.h"
|
||||
#include "../regd.h"
|
||||
|
||||
struct hw_stat_reg_entry {
|
||||
u32 reg;
|
||||
char nreg[32];
|
||||
};
|
||||
|
||||
#define STAT_MAC_REG(reg) \
|
||||
{ (AR9170_MAC_REG_##reg), #reg }
|
||||
|
||||
#define STAT_PTA_REG(reg) \
|
||||
{ (AR9170_PTA_REG_##reg), #reg }
|
||||
|
||||
#define STAT_USB_REG(reg) \
|
||||
{ (AR9170_USB_REG_##reg), #reg }
|
||||
|
||||
static const struct hw_stat_reg_entry hw_rx_tally_regs[] = {
|
||||
STAT_MAC_REG(RX_CRC32), STAT_MAC_REG(RX_CRC16),
|
||||
STAT_MAC_REG(RX_TIMEOUT_COUNT), STAT_MAC_REG(RX_ERR_DECRYPTION_UNI),
|
||||
STAT_MAC_REG(RX_ERR_DECRYPTION_MUL), STAT_MAC_REG(RX_MPDU),
|
||||
STAT_MAC_REG(RX_DROPPED_MPDU), STAT_MAC_REG(RX_DEL_MPDU),
|
||||
};
|
||||
|
||||
static const struct hw_stat_reg_entry hw_phy_errors_regs[] = {
|
||||
STAT_MAC_REG(RX_PHY_MISC_ERROR), STAT_MAC_REG(RX_PHY_XR_ERROR),
|
||||
STAT_MAC_REG(RX_PHY_OFDM_ERROR), STAT_MAC_REG(RX_PHY_CCK_ERROR),
|
||||
STAT_MAC_REG(RX_PHY_HT_ERROR), STAT_MAC_REG(RX_PHY_TOTAL),
|
||||
};
|
||||
|
||||
static const struct hw_stat_reg_entry hw_tx_tally_regs[] = {
|
||||
STAT_MAC_REG(TX_TOTAL), STAT_MAC_REG(TX_UNDERRUN),
|
||||
STAT_MAC_REG(TX_RETRY),
|
||||
};
|
||||
|
||||
static const struct hw_stat_reg_entry hw_wlan_queue_regs[] = {
|
||||
STAT_MAC_REG(DMA_STATUS), STAT_MAC_REG(DMA_TRIGGER),
|
||||
STAT_MAC_REG(DMA_TXQ0_ADDR), STAT_MAC_REG(DMA_TXQ0_CURR_ADDR),
|
||||
STAT_MAC_REG(DMA_TXQ1_ADDR), STAT_MAC_REG(DMA_TXQ1_CURR_ADDR),
|
||||
STAT_MAC_REG(DMA_TXQ2_ADDR), STAT_MAC_REG(DMA_TXQ2_CURR_ADDR),
|
||||
STAT_MAC_REG(DMA_TXQ3_ADDR), STAT_MAC_REG(DMA_TXQ3_CURR_ADDR),
|
||||
STAT_MAC_REG(DMA_RXQ_ADDR), STAT_MAC_REG(DMA_RXQ_CURR_ADDR),
|
||||
};
|
||||
|
||||
static const struct hw_stat_reg_entry hw_ampdu_info_regs[] = {
|
||||
STAT_MAC_REG(AMPDU_DENSITY), STAT_MAC_REG(AMPDU_FACTOR),
|
||||
};
|
||||
|
||||
static const struct hw_stat_reg_entry hw_pta_queue_regs[] = {
|
||||
STAT_PTA_REG(DN_CURR_ADDRH), STAT_PTA_REG(DN_CURR_ADDRL),
|
||||
STAT_PTA_REG(UP_CURR_ADDRH), STAT_PTA_REG(UP_CURR_ADDRL),
|
||||
STAT_PTA_REG(DMA_STATUS), STAT_PTA_REG(DMA_MODE_CTRL),
|
||||
};
|
||||
|
||||
#define DEFINE_TALLY(name) \
|
||||
u32 name##_sum[ARRAY_SIZE(name##_regs)], \
|
||||
name##_counter[ARRAY_SIZE(name##_regs)] \
|
||||
|
||||
#define DEFINE_STAT(name) \
|
||||
u32 name##_counter[ARRAY_SIZE(name##_regs)] \
|
||||
|
||||
struct ath_stats {
|
||||
DEFINE_TALLY(hw_tx_tally);
|
||||
DEFINE_TALLY(hw_rx_tally);
|
||||
DEFINE_TALLY(hw_phy_errors);
|
||||
DEFINE_STAT(hw_wlan_queue);
|
||||
DEFINE_STAT(hw_pta_queue);
|
||||
DEFINE_STAT(hw_ampdu_info);
|
||||
};
|
||||
|
||||
struct carl9170_debug_mem_rbe {
|
||||
u32 reg;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
#define CARL9170_DEBUG_RING_SIZE 64
|
||||
|
||||
struct carl9170_debug {
|
||||
struct ath_stats stats;
|
||||
struct carl9170_debug_mem_rbe ring[CARL9170_DEBUG_RING_SIZE];
|
||||
struct mutex ring_lock;
|
||||
unsigned int ring_head, ring_tail;
|
||||
struct delayed_work update_tally;
|
||||
};
|
||||
|
||||
struct ar9170;
|
||||
|
||||
void carl9170_debugfs_register(struct ar9170 *ar);
|
||||
void carl9170_debugfs_unregister(struct ar9170 *ar);
|
||||
#endif /* __DEBUG_H */
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Shared Atheros AR9170 Header
|
||||
*
|
||||
* EEPROM layout
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
#ifndef __CARL9170_SHARED_EEPROM_H
|
||||
#define __CARL9170_SHARED_EEPROM_H
|
||||
|
||||
#define AR9170_EEPROM_START 0x1600
|
||||
|
||||
#define AR5416_MAX_CHAINS 2
|
||||
#define AR5416_MODAL_SPURS 5
|
||||
|
||||
struct ar9170_eeprom_modal {
|
||||
__le32 antCtrlChain[AR5416_MAX_CHAINS];
|
||||
__le32 antCtrlCommon;
|
||||
s8 antennaGainCh[AR5416_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR5416_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR5416_MAX_CHAINS];
|
||||
s8 adcDesiredSize;
|
||||
s8 pgaDesiredSize;
|
||||
u8 xlnaGainCh[AR5416_MAX_CHAINS];
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
s8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
s8 iqCalICh[AR5416_MAX_CHAINS];
|
||||
s8 iqCalQCh[AR5416_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
u8 ob;
|
||||
u8 db;
|
||||
u8 xpaBiasLvl;
|
||||
u8 pwrDecreaseFor2Chain;
|
||||
u8 pwrDecreaseFor3Chain;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR5416_MAX_CHAINS];
|
||||
u8 bswMargin[AR5416_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 reserved[22];
|
||||
struct spur_channel {
|
||||
__le16 spurChan;
|
||||
u8 spurRangeLow;
|
||||
u8 spurRangeHigh;
|
||||
} __packed spur_channels[AR5416_MODAL_SPURS];
|
||||
} __packed;
|
||||
|
||||
#define AR5416_NUM_PD_GAINS 4
|
||||
#define AR5416_PD_GAIN_ICEPTS 5
|
||||
|
||||
struct ar9170_calibration_data_per_freq {
|
||||
u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
} __packed;
|
||||
|
||||
#define AR5416_NUM_5G_CAL_PIERS 8
|
||||
#define AR5416_NUM_2G_CAL_PIERS 4
|
||||
|
||||
#define AR5416_NUM_5G_TARGET_PWRS 8
|
||||
#define AR5416_NUM_2G_CCK_TARGET_PWRS 3
|
||||
#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4
|
||||
#define AR5416_MAX_NUM_TGT_PWRS 8
|
||||
|
||||
struct ar9170_calibration_target_power_legacy {
|
||||
u8 freq;
|
||||
u8 power[4];
|
||||
} __packed;
|
||||
|
||||
struct ar9170_calibration_target_power_ht {
|
||||
u8 freq;
|
||||
u8 power[8];
|
||||
} __packed;
|
||||
|
||||
#define AR5416_NUM_CTLS 24
|
||||
|
||||
struct ar9170_calctl_edges {
|
||||
u8 channel;
|
||||
#define AR9170_CALCTL_EDGE_FLAGS 0xC0
|
||||
u8 power_flags;
|
||||
} __packed;
|
||||
|
||||
#define AR5416_NUM_BAND_EDGES 8
|
||||
|
||||
struct ar9170_calctl_data {
|
||||
struct ar9170_calctl_edges
|
||||
control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
|
||||
} __packed;
|
||||
|
||||
struct ar9170_eeprom {
|
||||
__le16 length;
|
||||
__le16 checksum;
|
||||
__le16 version;
|
||||
u8 operating_flags;
|
||||
#define AR9170_OPFLAG_5GHZ 1
|
||||
#define AR9170_OPFLAG_2GHZ 2
|
||||
u8 misc;
|
||||
__le16 reg_domain[2];
|
||||
u8 mac_address[6];
|
||||
u8 rx_mask;
|
||||
u8 tx_mask;
|
||||
__le16 rf_silent;
|
||||
__le16 bluetooth_options;
|
||||
__le16 device_capabilities;
|
||||
__le32 build_number;
|
||||
u8 deviceType;
|
||||
u8 reserved[33];
|
||||
|
||||
u8 customer_data[64];
|
||||
|
||||
struct ar9170_eeprom_modal
|
||||
modal_header[2];
|
||||
|
||||
u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS];
|
||||
u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS];
|
||||
|
||||
struct ar9170_calibration_data_per_freq
|
||||
cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS],
|
||||
cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
|
||||
|
||||
/* power calibration data */
|
||||
struct ar9170_calibration_target_power_legacy
|
||||
cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS];
|
||||
struct ar9170_calibration_target_power_ht
|
||||
cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS],
|
||||
cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS];
|
||||
|
||||
struct ar9170_calibration_target_power_legacy
|
||||
cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS],
|
||||
cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS];
|
||||
struct ar9170_calibration_target_power_ht
|
||||
cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS],
|
||||
cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS];
|
||||
|
||||
/* conformance testing limits */
|
||||
u8 ctl_index[AR5416_NUM_CTLS];
|
||||
struct ar9170_calctl_data
|
||||
ctl_data[AR5416_NUM_CTLS];
|
||||
|
||||
u8 pad;
|
||||
__le16 subsystem_id;
|
||||
} __packed;
|
||||
|
||||
#define AR9170_LED_MODE_POWER_ON 0x0001
|
||||
#define AR9170_LED_MODE_RESERVED 0x0002
|
||||
#define AR9170_LED_MODE_DISABLE_STATE 0x0004
|
||||
#define AR9170_LED_MODE_OFF_IN_PSM 0x0008
|
||||
|
||||
/* AR9170_LED_MODE BIT is set */
|
||||
#define AR9170_LED_MODE_FREQUENCY_S 4
|
||||
#define AR9170_LED_MODE_FREQUENCY 0x0030
|
||||
#define AR9170_LED_MODE_FREQUENCY_1HZ 0x0000
|
||||
#define AR9170_LED_MODE_FREQUENCY_0_5HZ 0x0010
|
||||
#define AR9170_LED_MODE_FREQUENCY_0_25HZ 0x0020
|
||||
#define AR9170_LED_MODE_FREQUENCY_0_125HZ 0x0030
|
||||
|
||||
/* AR9170_LED_MODE BIT is not set */
|
||||
#define AR9170_LED_MODE_CONN_STATE_S 4
|
||||
#define AR9170_LED_MODE_CONN_STATE 0x0030
|
||||
#define AR9170_LED_MODE_CONN_STATE_FORCE_OFF 0x0000
|
||||
#define AR9170_LED_MODE_CONN_STATE_FORCE_ON 0x0010
|
||||
/* Idle off / Active on */
|
||||
#define AR9170_LED_MODE_CONN_STATE_IOFF_AON 0x0020
|
||||
/* Idle on / Active off */
|
||||
#define AR9170_LED_MODE_CONN_STATE_ION_AOFF 0x0010
|
||||
|
||||
#define AR9170_LED_MODE_MODE 0x0040
|
||||
#define AR9170_LED_MODE_RESERVED2 0x0080
|
||||
|
||||
#define AR9170_LED_MODE_TON_SCAN_S 8
|
||||
#define AR9170_LED_MODE_TON_SCAN 0x0f00
|
||||
|
||||
#define AR9170_LED_MODE_TOFF_SCAN_S 12
|
||||
#define AR9170_LED_MODE_TOFF_SCAN 0xf000
|
||||
|
||||
struct ar9170_led_mode {
|
||||
__le16 led;
|
||||
};
|
||||
|
||||
#endif /* __CARL9170_SHARED_EEPROM_H */
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* firmware parser
|
||||
*
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/crc32.h>
|
||||
#include "carl9170.h"
|
||||
#include "fwcmd.h"
|
||||
#include "version.h"
|
||||
|
||||
#define MAKE_STR(symbol) #symbol
|
||||
#define TO_STR(symbol) MAKE_STR(symbol)
|
||||
#define CARL9170FW_API_VER_STR TO_STR(CARL9170FW_API_MAX_VER)
|
||||
MODULE_VERSION(CARL9170FW_API_VER_STR ":" CARL9170FW_VERSION_GIT);
|
||||
|
||||
static const u8 otus_magic[4] = { OTUS_MAGIC };
|
||||
|
||||
static const void *carl9170_fw_find_desc(struct ar9170 *ar, const u8 descid[4],
|
||||
const unsigned int len, const u8 compatible_revision)
|
||||
{
|
||||
const struct carl9170fw_desc_head *iter;
|
||||
|
||||
carl9170fw_for_each_hdr(iter, ar->fw.desc) {
|
||||
if (carl9170fw_desc_cmp(iter, descid, len,
|
||||
compatible_revision))
|
||||
return (void *)iter;
|
||||
}
|
||||
|
||||
/* needed to find the LAST desc */
|
||||
if (carl9170fw_desc_cmp(iter, descid, len,
|
||||
compatible_revision))
|
||||
return (void *)iter;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int carl9170_fw_verify_descs(struct ar9170 *ar,
|
||||
const struct carl9170fw_desc_head *head, unsigned int max_len)
|
||||
{
|
||||
const struct carl9170fw_desc_head *pos;
|
||||
unsigned long pos_addr, end_addr;
|
||||
unsigned int pos_length;
|
||||
|
||||
if (max_len < sizeof(*pos))
|
||||
return -ENODATA;
|
||||
|
||||
max_len = min_t(unsigned int, CARL9170FW_DESC_MAX_LENGTH, max_len);
|
||||
|
||||
pos = head;
|
||||
pos_addr = (unsigned long) pos;
|
||||
end_addr = pos_addr + max_len;
|
||||
|
||||
while (pos_addr < end_addr) {
|
||||
if (pos_addr + sizeof(*head) > end_addr)
|
||||
return -E2BIG;
|
||||
|
||||
pos_length = le16_to_cpu(pos->length);
|
||||
|
||||
if (pos_length < sizeof(*head))
|
||||
return -EBADMSG;
|
||||
|
||||
if (pos_length > max_len)
|
||||
return -EOVERFLOW;
|
||||
|
||||
if (pos_addr + pos_length > end_addr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (carl9170fw_desc_cmp(pos, LAST_MAGIC,
|
||||
CARL9170FW_LAST_DESC_SIZE,
|
||||
CARL9170FW_LAST_DESC_CUR_VER))
|
||||
return 0;
|
||||
|
||||
pos_addr += pos_length;
|
||||
pos = (void *)pos_addr;
|
||||
max_len -= pos_length;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void carl9170_fw_info(struct ar9170 *ar)
|
||||
{
|
||||
const struct carl9170fw_motd_desc *motd_desc;
|
||||
unsigned int str_ver_len;
|
||||
u32 fw_date;
|
||||
|
||||
dev_info(&ar->udev->dev, "driver API: %s 2%03d-%02d-%02d [%d-%d]\n",
|
||||
CARL9170FW_VERSION_GIT, CARL9170FW_VERSION_YEAR,
|
||||
CARL9170FW_VERSION_MONTH, CARL9170FW_VERSION_DAY,
|
||||
CARL9170FW_API_MIN_VER, CARL9170FW_API_MAX_VER);
|
||||
|
||||
motd_desc = carl9170_fw_find_desc(ar, MOTD_MAGIC,
|
||||
sizeof(*motd_desc), CARL9170FW_MOTD_DESC_CUR_VER);
|
||||
|
||||
if (motd_desc) {
|
||||
str_ver_len = strnlen(motd_desc->release,
|
||||
CARL9170FW_MOTD_RELEASE_LEN);
|
||||
|
||||
fw_date = le32_to_cpu(motd_desc->fw_year_month_day);
|
||||
|
||||
dev_info(&ar->udev->dev, "firmware API: %.*s 2%03d-%02d-%02d\n",
|
||||
str_ver_len, motd_desc->release,
|
||||
CARL9170FW_GET_YEAR(fw_date),
|
||||
CARL9170FW_GET_MONTH(fw_date),
|
||||
CARL9170FW_GET_DAY(fw_date));
|
||||
|
||||
strlcpy(ar->hw->wiphy->fw_version, motd_desc->release,
|
||||
sizeof(ar->hw->wiphy->fw_version));
|
||||
}
|
||||
}
|
||||
|
||||
static bool valid_dma_addr(const u32 address)
|
||||
{
|
||||
if (address >= AR9170_SRAM_OFFSET &&
|
||||
address < (AR9170_SRAM_OFFSET + AR9170_SRAM_SIZE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool valid_cpu_addr(const u32 address)
|
||||
{
|
||||
if (valid_dma_addr(address) || (address >= AR9170_PRAM_OFFSET &&
|
||||
address < (AR9170_PRAM_OFFSET + AR9170_PRAM_SIZE)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
{
|
||||
const struct carl9170fw_otus_desc *otus_desc;
|
||||
const struct carl9170fw_chk_desc *chk_desc;
|
||||
const struct carl9170fw_last_desc *last_desc;
|
||||
|
||||
last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
|
||||
sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
|
||||
if (!last_desc)
|
||||
return -EINVAL;
|
||||
|
||||
otus_desc = carl9170_fw_find_desc(ar, OTUS_MAGIC,
|
||||
sizeof(*otus_desc), CARL9170FW_OTUS_DESC_CUR_VER);
|
||||
if (!otus_desc) {
|
||||
dev_err(&ar->udev->dev, "failed to find compatible firmware "
|
||||
"descriptor.\n");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
chk_desc = carl9170_fw_find_desc(ar, CHK_MAGIC,
|
||||
sizeof(*chk_desc), CARL9170FW_CHK_DESC_CUR_VER);
|
||||
|
||||
if (chk_desc) {
|
||||
unsigned long fin, diff;
|
||||
unsigned int dsc_len;
|
||||
u32 crc32;
|
||||
|
||||
dsc_len = min_t(unsigned int, len,
|
||||
(unsigned long)chk_desc - (unsigned long)otus_desc);
|
||||
|
||||
fin = (unsigned long) last_desc + sizeof(*last_desc);
|
||||
diff = fin - (unsigned long) otus_desc;
|
||||
|
||||
if (diff < len)
|
||||
len -= diff;
|
||||
|
||||
if (len < 256)
|
||||
return -EIO;
|
||||
|
||||
crc32 = crc32_le(~0, data, len);
|
||||
if (cpu_to_le32(crc32) != chk_desc->fw_crc32) {
|
||||
dev_err(&ar->udev->dev, "fw checksum test failed.\n");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
crc32 = crc32_le(crc32, (void *)otus_desc, dsc_len);
|
||||
if (cpu_to_le32(crc32) != chk_desc->hdr_crc32) {
|
||||
dev_err(&ar->udev->dev, "descriptor check failed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
dev_warn(&ar->udev->dev, "Unprotected firmware image.\n");
|
||||
}
|
||||
|
||||
#define SUPP(feat) \
|
||||
(carl9170fw_supports(otus_desc->feature_set, feat))
|
||||
|
||||
if (!SUPP(CARL9170FW_DUMMY_FEATURE)) {
|
||||
dev_err(&ar->udev->dev, "invalid firmware descriptor "
|
||||
"format detected.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->fw.api_version = otus_desc->api_ver;
|
||||
|
||||
if (ar->fw.api_version < CARL9170FW_API_MIN_VER ||
|
||||
ar->fw.api_version > CARL9170FW_API_MAX_VER) {
|
||||
dev_err(&ar->udev->dev, "unsupported firmware api version.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!SUPP(CARL9170FW_COMMAND_PHY) || SUPP(CARL9170FW_UNUSABLE) ||
|
||||
!SUPP(CARL9170FW_HANDLE_BACK_REQ)) {
|
||||
dev_err(&ar->udev->dev, "firmware does support "
|
||||
"mandatory features.\n");
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
if (ilog2(le32_to_cpu(otus_desc->feature_set)) >=
|
||||
__CARL9170FW_FEATURE_NUM) {
|
||||
dev_warn(&ar->udev->dev, "driver does not support all "
|
||||
"firmware features.\n");
|
||||
}
|
||||
|
||||
if (!SUPP(CARL9170FW_COMMAND_CAM)) {
|
||||
dev_info(&ar->udev->dev, "crypto offloading is disabled "
|
||||
"by firmware.\n");
|
||||
ar->disable_offload = true;
|
||||
}
|
||||
|
||||
if (SUPP(CARL9170FW_PSM))
|
||||
ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
|
||||
|
||||
if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {
|
||||
dev_err(&ar->udev->dev, "firmware does not provide "
|
||||
"mandatory interfaces.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (SUPP(CARL9170FW_MINIBOOT))
|
||||
ar->fw.offset = le16_to_cpu(otus_desc->miniboot_size);
|
||||
else
|
||||
ar->fw.offset = 0;
|
||||
|
||||
if (SUPP(CARL9170FW_USB_DOWN_STREAM)) {
|
||||
ar->hw->extra_tx_headroom += sizeof(struct ar9170_stream);
|
||||
ar->fw.tx_stream = true;
|
||||
}
|
||||
|
||||
if (SUPP(CARL9170FW_USB_UP_STREAM))
|
||||
ar->fw.rx_stream = true;
|
||||
|
||||
ar->fw.vif_num = otus_desc->vif_num;
|
||||
ar->fw.cmd_bufs = otus_desc->cmd_bufs;
|
||||
ar->fw.address = le32_to_cpu(otus_desc->fw_address);
|
||||
ar->fw.rx_size = le16_to_cpu(otus_desc->rx_max_frame_len);
|
||||
ar->fw.mem_blocks = min_t(unsigned int, otus_desc->tx_descs, 0xfe);
|
||||
atomic_set(&ar->mem_free_blocks, ar->fw.mem_blocks);
|
||||
ar->fw.mem_block_size = le16_to_cpu(otus_desc->tx_frag_len);
|
||||
|
||||
if (ar->fw.vif_num >= AR9170_MAX_VIRTUAL_MAC || !ar->fw.vif_num ||
|
||||
ar->fw.mem_blocks < 16 || !ar->fw.cmd_bufs ||
|
||||
ar->fw.mem_block_size < 64 || ar->fw.mem_block_size > 512 ||
|
||||
ar->fw.rx_size > 32768 || ar->fw.rx_size < 4096 ||
|
||||
!valid_cpu_addr(ar->fw.address)) {
|
||||
dev_err(&ar->udev->dev, "firmware shows obvious signs of "
|
||||
"malicious tampering.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->fw.beacon_addr = le32_to_cpu(otus_desc->bcn_addr);
|
||||
ar->fw.beacon_max_len = le16_to_cpu(otus_desc->bcn_len);
|
||||
|
||||
if (valid_dma_addr(ar->fw.beacon_addr) && ar->fw.beacon_max_len >=
|
||||
AR9170_MAC_BCN_LENGTH_MAX) {
|
||||
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
if (SUPP(CARL9170FW_WLANTX_CAB)) {
|
||||
ar->hw->wiphy->interface_modes |=
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
}
|
||||
}
|
||||
|
||||
#undef SUPPORTED
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct carl9170fw_desc_head *
|
||||
carl9170_find_fw_desc(struct ar9170 *ar, const __u8 *fw_data, const size_t len)
|
||||
|
||||
{
|
||||
int scan = 0, found = 0;
|
||||
|
||||
if (!carl9170fw_size_check(len)) {
|
||||
dev_err(&ar->udev->dev, "firmware size is out of bound.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (scan < len - sizeof(struct carl9170fw_desc_head)) {
|
||||
if (fw_data[scan++] == otus_magic[found])
|
||||
found++;
|
||||
else
|
||||
found = 0;
|
||||
|
||||
if (scan >= len)
|
||||
break;
|
||||
|
||||
if (found == sizeof(otus_magic))
|
||||
break;
|
||||
}
|
||||
|
||||
if (found != sizeof(otus_magic))
|
||||
return NULL;
|
||||
|
||||
return (void *)&fw_data[scan - found];
|
||||
}
|
||||
|
||||
int carl9170_fw_fix_eeprom(struct ar9170 *ar)
|
||||
{
|
||||
const struct carl9170fw_fix_desc *fix_desc = NULL;
|
||||
unsigned int i, n, off;
|
||||
u32 *data = (void *)&ar->eeprom;
|
||||
|
||||
fix_desc = carl9170_fw_find_desc(ar, FIX_MAGIC,
|
||||
sizeof(*fix_desc), CARL9170FW_FIX_DESC_CUR_VER);
|
||||
|
||||
if (!fix_desc)
|
||||
return 0;
|
||||
|
||||
n = (le16_to_cpu(fix_desc->head.length) - sizeof(*fix_desc)) /
|
||||
sizeof(struct carl9170fw_fix_entry);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
off = le32_to_cpu(fix_desc->data[i].address) -
|
||||
AR9170_EEPROM_START;
|
||||
|
||||
if (off >= sizeof(struct ar9170_eeprom) || (off & 3)) {
|
||||
dev_err(&ar->udev->dev, "Skip invalid entry %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
data[off / sizeof(*data)] &=
|
||||
le32_to_cpu(fix_desc->data[i].mask);
|
||||
data[off / sizeof(*data)] |=
|
||||
le32_to_cpu(fix_desc->data[i].value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int carl9170_parse_firmware(struct ar9170 *ar)
|
||||
{
|
||||
const struct carl9170fw_desc_head *fw_desc = NULL;
|
||||
const struct firmware *fw = ar->fw.fw;
|
||||
unsigned long header_offset = 0;
|
||||
int err;
|
||||
|
||||
if (WARN_ON(!fw))
|
||||
return -EINVAL;
|
||||
|
||||
fw_desc = carl9170_find_fw_desc(ar, fw->data, fw->size);
|
||||
|
||||
if (!fw_desc) {
|
||||
dev_err(&ar->udev->dev, "unsupported firmware.\n");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
header_offset = (unsigned long)fw_desc - (unsigned long)fw->data;
|
||||
|
||||
err = carl9170_fw_verify_descs(ar, fw_desc, fw->size - header_offset);
|
||||
if (err) {
|
||||
dev_err(&ar->udev->dev, "damaged firmware (%d).\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ar->fw.desc = fw_desc;
|
||||
|
||||
carl9170_fw_info(ar);
|
||||
|
||||
err = carl9170_fw(ar, fw->data, fw->size);
|
||||
if (err) {
|
||||
dev_err(&ar->udev->dev, "failed to parse firmware (%d).\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Shared Atheros AR9170 Header
|
||||
*
|
||||
* Firmware command interface definitions
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
|
||||
#ifndef __CARL9170_SHARED_FWCMD_H
|
||||
#define __CARL9170_SHARED_FWCMD_H
|
||||
|
||||
#define CARL9170_MAX_CMD_LEN 64
|
||||
#define CARL9170_MAX_CMD_PAYLOAD_LEN 60
|
||||
|
||||
#define CARL9170FW_API_MIN_VER 1
|
||||
#define CARL9170FW_API_MAX_VER 1
|
||||
|
||||
enum carl9170_cmd_oids {
|
||||
CARL9170_CMD_RREG = 0x00,
|
||||
CARL9170_CMD_WREG = 0x01,
|
||||
CARL9170_CMD_ECHO = 0x02,
|
||||
CARL9170_CMD_SWRST = 0x03,
|
||||
CARL9170_CMD_REBOOT = 0x04,
|
||||
CARL9170_CMD_BCN_CTRL = 0x05,
|
||||
CARL9170_CMD_READ_TSF = 0x06,
|
||||
|
||||
/* CAM */
|
||||
CARL9170_CMD_EKEY = 0x10,
|
||||
CARL9170_CMD_DKEY = 0x11,
|
||||
|
||||
/* RF / PHY */
|
||||
CARL9170_CMD_FREQUENCY = 0x20,
|
||||
CARL9170_CMD_RF_INIT = 0x21,
|
||||
CARL9170_CMD_SYNTH = 0x22,
|
||||
CARL9170_CMD_FREQ_START = 0x23,
|
||||
CARL9170_CMD_PSM = 0x24,
|
||||
|
||||
/* Asychronous command flag */
|
||||
CARL9170_CMD_ASYNC_FLAG = 0x40,
|
||||
CARL9170_CMD_WREG_ASYNC = (CARL9170_CMD_WREG |
|
||||
CARL9170_CMD_ASYNC_FLAG),
|
||||
CARL9170_CMD_REBOOT_ASYNC = (CARL9170_CMD_REBOOT |
|
||||
CARL9170_CMD_ASYNC_FLAG),
|
||||
CARL9170_CMD_BCN_CTRL_ASYNC = (CARL9170_CMD_BCN_CTRL |
|
||||
CARL9170_CMD_ASYNC_FLAG),
|
||||
CARL9170_CMD_PSM_ASYNC = (CARL9170_CMD_PSM |
|
||||
CARL9170_CMD_ASYNC_FLAG),
|
||||
|
||||
/* responses and traps */
|
||||
CARL9170_RSP_FLAG = 0xc0,
|
||||
CARL9170_RSP_PRETBTT = 0xc0,
|
||||
CARL9170_RSP_TXCOMP = 0xc1,
|
||||
CARL9170_RSP_BEACON_CONFIG = 0xc2,
|
||||
CARL9170_RSP_ATIM = 0xc3,
|
||||
CARL9170_RSP_WATCHDOG = 0xc6,
|
||||
CARL9170_RSP_TEXT = 0xca,
|
||||
CARL9170_RSP_HEXDUMP = 0xcc,
|
||||
CARL9170_RSP_RADAR = 0xcd,
|
||||
CARL9170_RSP_GPIO = 0xce,
|
||||
CARL9170_RSP_BOOT = 0xcf,
|
||||
};
|
||||
|
||||
struct carl9170_set_key_cmd {
|
||||
__le16 user;
|
||||
__le16 keyId;
|
||||
__le16 type;
|
||||
u8 macAddr[6];
|
||||
u32 key[4];
|
||||
} __packed;
|
||||
#define CARL9170_SET_KEY_CMD_SIZE 28
|
||||
|
||||
struct carl9170_disable_key_cmd {
|
||||
__le16 user;
|
||||
__le16 padding;
|
||||
} __packed;
|
||||
#define CARL9170_DISABLE_KEY_CMD_SIZE 4
|
||||
|
||||
struct carl9170_u32_list {
|
||||
u32 vals[0];
|
||||
} __packed;
|
||||
|
||||
struct carl9170_reg_list {
|
||||
__le32 regs[0];
|
||||
} __packed;
|
||||
|
||||
struct carl9170_write_reg {
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 val;
|
||||
} regs[0] __packed;
|
||||
} __packed;
|
||||
|
||||
#define CARL9170FW_PHY_HT_ENABLE 0x4
|
||||
#define CARL9170FW_PHY_HT_DYN2040 0x8
|
||||
#define CARL9170FW_PHY_HT_EXT_CHAN_OFF 0x3
|
||||
#define CARL9170FW_PHY_HT_EXT_CHAN_OFF_S 2
|
||||
|
||||
struct carl9170_rf_init {
|
||||
__le32 freq;
|
||||
u8 ht_settings;
|
||||
u8 padding2[3];
|
||||
__le32 delta_slope_coeff_exp;
|
||||
__le32 delta_slope_coeff_man;
|
||||
__le32 delta_slope_coeff_exp_shgi;
|
||||
__le32 delta_slope_coeff_man_shgi;
|
||||
__le32 finiteLoopCount;
|
||||
} __packed;
|
||||
#define CARL9170_RF_INIT_SIZE 28
|
||||
|
||||
struct carl9170_rf_init_result {
|
||||
__le32 ret; /* AR9170_PHY_REG_AGC_CONTROL */
|
||||
} __packed;
|
||||
#define CARL9170_RF_INIT_RESULT_SIZE 4
|
||||
|
||||
#define CARL9170_PSM_SLEEP 0x1000
|
||||
#define CARL9170_PSM_SOFTWARE 0
|
||||
#define CARL9170_PSM_WAKE 0 /* internally used. */
|
||||
#define CARL9170_PSM_COUNTER 0xfff
|
||||
#define CARL9170_PSM_COUNTER_S 0
|
||||
|
||||
struct carl9170_psm {
|
||||
__le32 state;
|
||||
} __packed;
|
||||
#define CARL9170_PSM_SIZE 4
|
||||
|
||||
struct carl9170_bcn_ctrl_cmd {
|
||||
__le32 vif_id;
|
||||
__le32 mode;
|
||||
__le32 bcn_addr;
|
||||
__le32 bcn_len;
|
||||
} __packed;
|
||||
#define CARL9170_BCN_CTRL_CMD_SIZE 16
|
||||
|
||||
#define CARL9170_BCN_CTRL_DRAIN 0
|
||||
#define CARL9170_BCN_CTRL_CAB_TRIGGER 1
|
||||
|
||||
struct carl9170_cmd_head {
|
||||
union {
|
||||
struct {
|
||||
u8 len;
|
||||
u8 cmd;
|
||||
u8 seq;
|
||||
u8 ext;
|
||||
} __packed;
|
||||
|
||||
u32 hdr_data;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
struct carl9170_cmd {
|
||||
struct carl9170_cmd_head hdr;
|
||||
union {
|
||||
struct carl9170_set_key_cmd setkey;
|
||||
struct carl9170_disable_key_cmd disablekey;
|
||||
struct carl9170_u32_list echo;
|
||||
struct carl9170_reg_list rreg;
|
||||
struct carl9170_write_reg wreg;
|
||||
struct carl9170_rf_init rf_init;
|
||||
struct carl9170_psm psm;
|
||||
struct carl9170_bcn_ctrl_cmd bcn_ctrl;
|
||||
u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
#define CARL9170_TX_STATUS_QUEUE 3
|
||||
#define CARL9170_TX_STATUS_QUEUE_S 0
|
||||
#define CARL9170_TX_STATUS_RIX_S 2
|
||||
#define CARL9170_TX_STATUS_RIX (3 << CARL9170_TX_STATUS_RIX_S)
|
||||
#define CARL9170_TX_STATUS_TRIES_S 4
|
||||
#define CARL9170_TX_STATUS_TRIES (7 << CARL9170_TX_STATUS_TRIES_S)
|
||||
#define CARL9170_TX_STATUS_SUCCESS 0x80
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* Both structs [carl9170_tx_status and _carl9170_tx_status]
|
||||
* need to be "bit for bit" in sync.
|
||||
*/
|
||||
struct carl9170_tx_status {
|
||||
/*
|
||||
* Beware of compiler bugs in all gcc pre 4.4!
|
||||
*/
|
||||
|
||||
u8 cookie;
|
||||
u8 queue:2;
|
||||
u8 rix:2;
|
||||
u8 tries:3;
|
||||
u8 success:1;
|
||||
} __packed;
|
||||
struct _carl9170_tx_status {
|
||||
/*
|
||||
* This version should be immune to all alignment bugs.
|
||||
*/
|
||||
|
||||
u8 cookie;
|
||||
u8 info;
|
||||
} __packed;
|
||||
#define CARL9170_TX_STATUS_SIZE 2
|
||||
|
||||
#define CARL9170_RSP_TX_STATUS_NUM (CARL9170_MAX_CMD_PAYLOAD_LEN / \
|
||||
sizeof(struct _carl9170_tx_status))
|
||||
|
||||
#define CARL9170_TX_MAX_RATE_TRIES 7
|
||||
|
||||
#define CARL9170_TX_MAX_RATES 4
|
||||
#define CARL9170_TX_MAX_RETRY_RATES (CARL9170_TX_MAX_RATES - 1)
|
||||
#define CARL9170_ERR_MAGIC "ERR:"
|
||||
#define CARL9170_BUG_MAGIC "BUG:"
|
||||
|
||||
struct carl9170_gpio {
|
||||
__le32 gpio;
|
||||
} __packed;
|
||||
#define CARL9170_GPIO_SIZE 4
|
||||
|
||||
struct carl9170_tsf_rsp {
|
||||
union {
|
||||
__le32 tsf[2];
|
||||
__le64 tsf_64;
|
||||
} __packed;
|
||||
} __packed;
|
||||
#define CARL9170_TSF_RSP_SIZE 8
|
||||
|
||||
struct carl9170_rsp {
|
||||
struct carl9170_cmd_head hdr;
|
||||
|
||||
union {
|
||||
struct carl9170_rf_init_result rf_init_res;
|
||||
struct carl9170_u32_list rreg_res;
|
||||
struct carl9170_u32_list echo;
|
||||
struct carl9170_tx_status tx_status[0];
|
||||
struct _carl9170_tx_status _tx_status[0];
|
||||
struct carl9170_gpio gpio;
|
||||
struct carl9170_tsf_rsp tsf;
|
||||
struct carl9170_psm psm;
|
||||
u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
#endif /* __CARL9170_SHARED_FWCMD_H */
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Shared CARL9170 Header
|
||||
*
|
||||
* Firmware descriptor format
|
||||
*
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef __CARL9170_SHARED_FWDESC_H
|
||||
#define __CARL9170_SHARED_FWDESC_H
|
||||
|
||||
/* NOTE: Don't mess with the order of the flags! */
|
||||
enum carl9170fw_feature_list {
|
||||
/* Always set */
|
||||
CARL9170FW_DUMMY_FEATURE,
|
||||
|
||||
/*
|
||||
* Indicates that this image has special boot block which prevents
|
||||
* legacy drivers to drive the firmware.
|
||||
*/
|
||||
CARL9170FW_MINIBOOT,
|
||||
|
||||
/* usb registers are initialized by the firmware */
|
||||
CARL9170FW_USB_INIT_FIRMWARE,
|
||||
|
||||
/* command traps & notifications are send through EP2 */
|
||||
CARL9170FW_USB_RESP_EP2,
|
||||
|
||||
/* usb download (app -> fw) stream */
|
||||
CARL9170FW_USB_DOWN_STREAM,
|
||||
|
||||
/* usb upload (fw -> app) stream */
|
||||
CARL9170FW_USB_UP_STREAM,
|
||||
|
||||
/* unusable - reserved to flag non-functional debug firmwares */
|
||||
CARL9170FW_UNUSABLE,
|
||||
|
||||
/* AR9170_CMD_RF_INIT, AR9170_CMD_FREQ_START, AR9170_CMD_FREQUENCY */
|
||||
CARL9170FW_COMMAND_PHY,
|
||||
|
||||
/* AR9170_CMD_EKEY, AR9170_CMD_DKEY */
|
||||
CARL9170FW_COMMAND_CAM,
|
||||
|
||||
/* Firmware has a software Content After Beacon Queueing mechanism */
|
||||
CARL9170FW_WLANTX_CAB,
|
||||
|
||||
/* The firmware is capable of responding to incoming BAR frames */
|
||||
CARL9170FW_HANDLE_BACK_REQ,
|
||||
|
||||
/* GPIO Interrupt | CARL9170_RSP_GPIO */
|
||||
CARL9170FW_GPIO_INTERRUPT,
|
||||
|
||||
/* Firmware PSM support | CARL9170_CMD_PSM */
|
||||
CARL9170FW_PSM,
|
||||
|
||||
/* KEEP LAST */
|
||||
__CARL9170FW_FEATURE_NUM
|
||||
};
|
||||
|
||||
#define OTUS_MAGIC "OTAR"
|
||||
#define MOTD_MAGIC "MOTD"
|
||||
#define FIX_MAGIC "FIX\0"
|
||||
#define DBG_MAGIC "DBG\0"
|
||||
#define CHK_MAGIC "CHK\0"
|
||||
#define LAST_MAGIC "LAST"
|
||||
|
||||
#define CARL9170FW_SET_DAY(d) (((d) - 1) % 31)
|
||||
#define CARL9170FW_SET_MONTH(m) ((((m) - 1) % 12) * 31)
|
||||
#define CARL9170FW_SET_YEAR(y) (((y) - 10) * 372)
|
||||
|
||||
#define CARL9170FW_GET_DAY(d) (((d) % 31) + 1)
|
||||
#define CARL9170FW_GET_MONTH(m) ((((m) / 31) % 12) + 1)
|
||||
#define CARL9170FW_GET_YEAR(y) ((y) / 372 + 10)
|
||||
|
||||
struct carl9170fw_desc_head {
|
||||
u8 magic[4];
|
||||
__le16 length;
|
||||
u8 min_ver;
|
||||
u8 cur_ver;
|
||||
} __packed;
|
||||
#define CARL9170FW_DESC_HEAD_SIZE \
|
||||
(sizeof(struct carl9170fw_desc_head))
|
||||
|
||||
#define CARL9170FW_OTUS_DESC_MIN_VER 6
|
||||
#define CARL9170FW_OTUS_DESC_CUR_VER 6
|
||||
struct carl9170fw_otus_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
__le32 feature_set;
|
||||
__le32 fw_address;
|
||||
__le32 bcn_addr;
|
||||
__le16 bcn_len;
|
||||
__le16 miniboot_size;
|
||||
__le16 tx_frag_len;
|
||||
__le16 rx_max_frame_len;
|
||||
u8 tx_descs;
|
||||
u8 cmd_bufs;
|
||||
u8 api_ver;
|
||||
u8 vif_num;
|
||||
} __packed;
|
||||
#define CARL9170FW_OTUS_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_otus_desc))
|
||||
|
||||
#define CARL9170FW_MOTD_STRING_LEN 24
|
||||
#define CARL9170FW_MOTD_RELEASE_LEN 20
|
||||
#define CARL9170FW_MOTD_DESC_MIN_VER 1
|
||||
#define CARL9170FW_MOTD_DESC_CUR_VER 2
|
||||
struct carl9170fw_motd_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
__le32 fw_year_month_day;
|
||||
char desc[CARL9170FW_MOTD_STRING_LEN];
|
||||
char release[CARL9170FW_MOTD_RELEASE_LEN];
|
||||
} __packed;
|
||||
#define CARL9170FW_MOTD_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_motd_desc))
|
||||
|
||||
#define CARL9170FW_FIX_DESC_MIN_VER 1
|
||||
#define CARL9170FW_FIX_DESC_CUR_VER 2
|
||||
struct carl9170fw_fix_entry {
|
||||
__le32 address;
|
||||
__le32 mask;
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
struct carl9170fw_fix_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
struct carl9170fw_fix_entry data[0];
|
||||
} __packed;
|
||||
#define CARL9170FW_FIX_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_fix_desc))
|
||||
|
||||
#define CARL9170FW_DBG_DESC_MIN_VER 1
|
||||
#define CARL9170FW_DBG_DESC_CUR_VER 2
|
||||
struct carl9170fw_dbg_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
|
||||
__le32 bogoclock_addr;
|
||||
__le32 counter_addr;
|
||||
__le32 rx_total_addr;
|
||||
__le32 rx_overrun_addr;
|
||||
|
||||
/* Put your debugging definitions here */
|
||||
} __packed;
|
||||
#define CARL9170FW_DBG_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_dbg_desc))
|
||||
|
||||
#define CARL9170FW_CHK_DESC_MIN_VER 1
|
||||
#define CARL9170FW_CHK_DESC_CUR_VER 2
|
||||
struct carl9170fw_chk_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
__le32 fw_crc32;
|
||||
__le32 hdr_crc32;
|
||||
} __packed;
|
||||
#define CARL9170FW_CHK_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_chk_desc))
|
||||
|
||||
#define CARL9170FW_LAST_DESC_MIN_VER 1
|
||||
#define CARL9170FW_LAST_DESC_CUR_VER 2
|
||||
struct carl9170fw_last_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
} __packed;
|
||||
#define CARL9170FW_LAST_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_fix_desc))
|
||||
|
||||
#define CARL9170FW_DESC_MAX_LENGTH 8192
|
||||
|
||||
#define CARL9170FW_FILL_DESC(_magic, _length, _min_ver, _cur_ver) \
|
||||
.head = { \
|
||||
.magic = _magic, \
|
||||
.length = cpu_to_le16(_length), \
|
||||
.min_ver = _min_ver, \
|
||||
.cur_ver = _cur_ver, \
|
||||
}
|
||||
|
||||
static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head,
|
||||
u8 magic[4], __le16 length,
|
||||
u8 min_ver, u8 cur_ver)
|
||||
{
|
||||
head->magic[0] = magic[0];
|
||||
head->magic[1] = magic[1];
|
||||
head->magic[2] = magic[2];
|
||||
head->magic[3] = magic[3];
|
||||
|
||||
head->length = length;
|
||||
head->min_ver = min_ver;
|
||||
head->cur_ver = cur_ver;
|
||||
}
|
||||
|
||||
#define carl9170fw_for_each_hdr(desc, fw_desc) \
|
||||
for (desc = fw_desc; \
|
||||
memcmp(desc->magic, LAST_MAGIC, 4) && \
|
||||
le16_to_cpu(desc->length) >= CARL9170FW_DESC_HEAD_SIZE && \
|
||||
le16_to_cpu(desc->length) < CARL9170FW_DESC_MAX_LENGTH; \
|
||||
desc = (void *)((unsigned long)desc + le16_to_cpu(desc->length)))
|
||||
|
||||
#define CHECK_HDR_VERSION(head, _min_ver) \
|
||||
(((head)->cur_ver < _min_ver) || ((head)->min_ver > _min_ver)) \
|
||||
|
||||
static inline bool carl9170fw_supports(__le32 list, u8 feature)
|
||||
{
|
||||
return le32_to_cpu(list) & BIT(feature);
|
||||
}
|
||||
|
||||
static inline bool carl9170fw_desc_cmp(const struct carl9170fw_desc_head *head,
|
||||
const u8 descid[4], u16 min_len,
|
||||
u8 compatible_revision)
|
||||
{
|
||||
if (descid[0] == head->magic[0] && descid[1] == head->magic[1] &&
|
||||
descid[2] == head->magic[2] && descid[3] == head->magic[3] &&
|
||||
!CHECK_HDR_VERSION(head, compatible_revision) &&
|
||||
(le16_to_cpu(head->length) >= min_len))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CARL9170FW_MIN_SIZE 32
|
||||
#define CARL9170FW_MAX_SIZE 16384
|
||||
|
||||
static inline bool carl9170fw_size_check(unsigned int len)
|
||||
{
|
||||
return (len <= CARL9170FW_MAX_SIZE && len >= CARL9170FW_MIN_SIZE);
|
||||
}
|
||||
|
||||
#endif /* __CARL9170_SHARED_FWDESC_H */
|
|
@ -0,0 +1,736 @@
|
|||
/*
|
||||
* Shared Atheros AR9170 Header
|
||||
*
|
||||
* Register map, hardware-specific definitions
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
|
||||
#ifndef __CARL9170_SHARED_HW_H
|
||||
#define __CARL9170_SHARED_HW_H
|
||||
|
||||
/* High Speed UART */
|
||||
#define AR9170_UART_REG_BASE 0x1c0000
|
||||
|
||||
/* Definitions of interrupt registers */
|
||||
#define AR9170_UART_REG_RX_BUFFER (AR9170_UART_REG_BASE + 0x000)
|
||||
#define AR9170_UART_REG_TX_HOLDING (AR9170_UART_REG_BASE + 0x004)
|
||||
#define AR9170_UART_REG_FIFO_CONTROL (AR9170_UART_REG_BASE + 0x010)
|
||||
#define AR9170_UART_FIFO_CTRL_RESET_RX_FIFO 0x02
|
||||
#define AR9170_UART_FIFO_CTRL_RESET_TX_FIFO 0x04
|
||||
|
||||
#define AR9170_UART_REG_LINE_CONTROL (AR9170_UART_REG_BASE + 0x014)
|
||||
#define AR9170_UART_REG_MODEM_CONTROL (AR9170_UART_REG_BASE + 0x018)
|
||||
#define AR9170_UART_MODEM_CTRL_DTR_BIT 0x01
|
||||
#define AR9170_UART_MODEM_CTRL_RTS_BIT 0x02
|
||||
#define AR9170_UART_MODEM_CTRL_INTERNAL_LOOP_BACK 0x10
|
||||
#define AR9170_UART_MODEM_CTRL_AUTO_RTS 0x20
|
||||
#define AR9170_UART_MODEM_CTRL_AUTO_CTR 0x40
|
||||
|
||||
#define AR9170_UART_REG_LINE_STATUS (AR9170_UART_REG_BASE + 0x01c)
|
||||
#define AR9170_UART_LINE_STS_RX_DATA_READY 0x01
|
||||
#define AR9170_UART_LINE_STS_RX_BUFFER_OVERRUN 0x02
|
||||
#define AR9170_UART_LINE_STS_RX_BREAK_IND 0x10
|
||||
#define AR9170_UART_LINE_STS_TX_FIFO_NEAR_EMPTY 0x20
|
||||
#define AR9170_UART_LINE_STS_TRANSMITTER_EMPTY 0x40
|
||||
|
||||
#define AR9170_UART_REG_MODEM_STATUS (AR9170_UART_REG_BASE + 0x020)
|
||||
#define AR9170_UART_MODEM_STS_CTS_CHANGE 0x01
|
||||
#define AR9170_UART_MODEM_STS_DSR_CHANGE 0x02
|
||||
#define AR9170_UART_MODEM_STS_DCD_CHANGE 0x08
|
||||
#define AR9170_UART_MODEM_STS_CTS_COMPL 0x10
|
||||
#define AR9170_UART_MODEM_STS_DSR_COMPL 0x20
|
||||
#define AR9170_UART_MODEM_STS_DCD_COMPL 0x80
|
||||
|
||||
#define AR9170_UART_REG_SCRATCH (AR9170_UART_REG_BASE + 0x024)
|
||||
#define AR9170_UART_REG_DIVISOR_LSB (AR9170_UART_REG_BASE + 0x028)
|
||||
#define AR9170_UART_REG_DIVISOR_MSB (AR9170_UART_REG_BASE + 0x02c)
|
||||
#define AR9170_UART_REG_WORD_RX_BUFFER (AR9170_UART_REG_BASE + 0x034)
|
||||
#define AR9170_UART_REG_WORD_TX_HOLDING (AR9170_UART_REG_BASE + 0x038)
|
||||
#define AR9170_UART_REG_FIFO_COUNT (AR9170_UART_REG_BASE + 0x03c)
|
||||
#define AR9170_UART_REG_REMAINDER (AR9170_UART_REG_BASE + 0x04c)
|
||||
|
||||
/* Timer */
|
||||
#define AR9170_TIMER_REG_BASE 0x1c1000
|
||||
|
||||
#define AR9170_TIMER_REG_WATCH_DOG (AR9170_TIMER_REG_BASE + 0x000)
|
||||
#define AR9170_TIMER_REG_TIMER0 (AR9170_TIMER_REG_BASE + 0x010)
|
||||
#define AR9170_TIMER_REG_TIMER1 (AR9170_TIMER_REG_BASE + 0x014)
|
||||
#define AR9170_TIMER_REG_TIMER2 (AR9170_TIMER_REG_BASE + 0x018)
|
||||
#define AR9170_TIMER_REG_TIMER3 (AR9170_TIMER_REG_BASE + 0x01c)
|
||||
#define AR9170_TIMER_REG_TIMER4 (AR9170_TIMER_REG_BASE + 0x020)
|
||||
#define AR9170_TIMER_REG_CONTROL (AR9170_TIMER_REG_BASE + 0x024)
|
||||
#define AR9170_TIMER_CTRL_DISABLE_CLOCK 0x100
|
||||
|
||||
#define AR9170_TIMER_REG_INTERRUPT (AR9170_TIMER_REG_BASE + 0x028)
|
||||
#define AR9170_TIMER_INT_TIMER0 0x001
|
||||
#define AR9170_TIMER_INT_TIMER1 0x002
|
||||
#define AR9170_TIMER_INT_TIMER2 0x004
|
||||
#define AR9170_TIMER_INT_TIMER3 0x008
|
||||
#define AR9170_TIMER_INT_TIMER4 0x010
|
||||
#define AR9170_TIMER_INT_TICK_TIMER 0x100
|
||||
|
||||
#define AR9170_TIMER_REG_TICK_TIMER (AR9170_TIMER_REG_BASE + 0x030)
|
||||
#define AR9170_TIMER_REG_CLOCK_LOW (AR9170_TIMER_REG_BASE + 0x040)
|
||||
#define AR9170_TIMER_REG_CLOCK_HIGH (AR9170_TIMER_REG_BASE + 0x044)
|
||||
|
||||
#define AR9170_MAC_REG_BASE 0x1c3000
|
||||
|
||||
#define AR9170_MAC_REG_POWER_STATE_CTRL (AR9170_MAC_REG_BASE + 0x500)
|
||||
#define AR9170_MAC_POWER_STATE_CTRL_RESET 0x20
|
||||
|
||||
#define AR9170_MAC_REG_MAC_POWER_STATE_CTRL (AR9170_MAC_REG_BASE + 0x50c)
|
||||
|
||||
#define AR9170_MAC_REG_INT_CTRL (AR9170_MAC_REG_BASE + 0x510)
|
||||
#define AR9170_MAC_INT_TXC BIT(0)
|
||||
#define AR9170_MAC_INT_RXC BIT(1)
|
||||
#define AR9170_MAC_INT_RETRY_FAIL BIT(2)
|
||||
#define AR9170_MAC_INT_WAKEUP BIT(3)
|
||||
#define AR9170_MAC_INT_ATIM BIT(4)
|
||||
#define AR9170_MAC_INT_DTIM BIT(5)
|
||||
#define AR9170_MAC_INT_CFG_BCN BIT(6)
|
||||
#define AR9170_MAC_INT_ABORT BIT(7)
|
||||
#define AR9170_MAC_INT_QOS BIT(8)
|
||||
#define AR9170_MAC_INT_MIMO_PS BIT(9)
|
||||
#define AR9170_MAC_INT_KEY_GEN BIT(10)
|
||||
#define AR9170_MAC_INT_DECRY_NOUSER BIT(11)
|
||||
#define AR9170_MAC_INT_RADAR BIT(12)
|
||||
#define AR9170_MAC_INT_QUIET_FRAME BIT(13)
|
||||
#define AR9170_MAC_INT_PRETBTT BIT(14)
|
||||
|
||||
#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514)
|
||||
#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518)
|
||||
|
||||
#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51c)
|
||||
#define AR9170_MAC_ATIM_PERIOD_S 0
|
||||
#define AR9170_MAC_ATIM_PERIOD 0x0000ffff
|
||||
|
||||
#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520)
|
||||
#define AR9170_MAC_BCN_PERIOD_S 0
|
||||
#define AR9170_MAC_BCN_PERIOD 0x0000ffff
|
||||
#define AR9170_MAC_BCN_DTIM_S 16
|
||||
#define AR9170_MAC_BCN_DTIM 0x00ff0000
|
||||
#define AR9170_MAC_BCN_AP_MODE BIT(24)
|
||||
#define AR9170_MAC_BCN_IBSS_MODE BIT(25)
|
||||
#define AR9170_MAC_BCN_PWR_MGT BIT(26)
|
||||
#define AR9170_MAC_BCN_STA_PS BIT(27)
|
||||
|
||||
#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524)
|
||||
#define AR9170_MAC_PRETBTT_S 0
|
||||
#define AR9170_MAC_PRETBTT 0x0000ffff
|
||||
#define AR9170_MAC_PRETBTT2_S 16
|
||||
#define AR9170_MAC_PRETBTT2 0xffff0000
|
||||
|
||||
#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610)
|
||||
#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614)
|
||||
#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618)
|
||||
#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c)
|
||||
|
||||
#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624)
|
||||
#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628)
|
||||
|
||||
#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62c)
|
||||
|
||||
#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630)
|
||||
#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634)
|
||||
#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638)
|
||||
#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c)
|
||||
#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640)
|
||||
#define AR9170_MAC_REG_AFTER_PNP (AR9170_MAC_REG_BASE + 0x648)
|
||||
#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64c)
|
||||
|
||||
#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658)
|
||||
#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674)
|
||||
#define AR9170_MAC_SNIFFER_ENABLE_PROMISC BIT(0)
|
||||
#define AR9170_MAC_SNIFFER_DEFAULTS 0x02000000
|
||||
#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678)
|
||||
#define AR9170_MAC_ENCRYPTION_RX_SOFTWARE BIT(3)
|
||||
#define AR9170_MAC_ENCRYPTION_DEFAULTS 0x70
|
||||
|
||||
#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680)
|
||||
#define AR9170_MAC_REG_MISC_684 (AR9170_MAC_REG_BASE + 0x684)
|
||||
#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688)
|
||||
|
||||
#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c)
|
||||
#define AR9170_MAC_FTF_ASSOC_REQ BIT(0)
|
||||
#define AR9170_MAC_FTF_ASSOC_RESP BIT(1)
|
||||
#define AR9170_MAC_FTF_REASSOC_REQ BIT(2)
|
||||
#define AR9170_MAC_FTF_REASSOC_RESP BIT(3)
|
||||
#define AR9170_MAC_FTF_PRB_REQ BIT(4)
|
||||
#define AR9170_MAC_FTF_PRB_RESP BIT(5)
|
||||
#define AR9170_MAC_FTF_BIT6 BIT(6)
|
||||
#define AR9170_MAC_FTF_BIT7 BIT(7)
|
||||
#define AR9170_MAC_FTF_BEACON BIT(8)
|
||||
#define AR9170_MAC_FTF_ATIM BIT(9)
|
||||
#define AR9170_MAC_FTF_DEASSOC BIT(10)
|
||||
#define AR9170_MAC_FTF_AUTH BIT(11)
|
||||
#define AR9170_MAC_FTF_DEAUTH BIT(12)
|
||||
#define AR9170_MAC_FTF_BIT13 BIT(13)
|
||||
#define AR9170_MAC_FTF_BIT14 BIT(14)
|
||||
#define AR9170_MAC_FTF_BIT15 BIT(15)
|
||||
#define AR9170_MAC_FTF_BAR BIT(24)
|
||||
#define AR9170_MAC_FTF_BA BIT(25)
|
||||
#define AR9170_MAC_FTF_PSPOLL BIT(26)
|
||||
#define AR9170_MAC_FTF_RTS BIT(27)
|
||||
#define AR9170_MAC_FTF_CTS BIT(28)
|
||||
#define AR9170_MAC_FTF_ACK BIT(29)
|
||||
#define AR9170_MAC_FTF_CFE BIT(30)
|
||||
#define AR9170_MAC_FTF_CFE_ACK BIT(31)
|
||||
#define AR9170_MAC_FTF_DEFAULTS 0x0500ffff
|
||||
#define AR9170_MAC_FTF_MONITOR 0xff00ffff
|
||||
|
||||
#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690)
|
||||
#define AR9170_MAC_REG_ACK_TPC (AR9170_MAC_REG_BASE + 0x694)
|
||||
#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698)
|
||||
#define AR9170_MAC_REG_RX_TIMEOUT_COUNT (AR9170_MAC_REG_BASE + 0x69c)
|
||||
#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6a0)
|
||||
#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6a4)
|
||||
#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6a8)
|
||||
#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6ac)
|
||||
#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6b0)
|
||||
#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6bc)
|
||||
#define AR9170_MAC_REG_TX_BLOCKACKS (AR9170_MAC_REG_BASE + 0x6c0)
|
||||
#define AR9170_MAC_REG_NAV_COUNT (AR9170_MAC_REG_BASE + 0x6c4)
|
||||
#define AR9170_MAC_REG_BACKOFF_STATUS (AR9170_MAC_REG_BASE + 0x6c8)
|
||||
#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6cc)
|
||||
|
||||
#define AR9170_MAC_REG_TX_COMPLETE (AR9170_MAC_REG_BASE + 0x6d4)
|
||||
|
||||
#define AR9170_MAC_REG_CHANNEL_BUSY (AR9170_MAC_REG_BASE + 0x6e8)
|
||||
#define AR9170_MAC_REG_EXT_BUSY (AR9170_MAC_REG_BASE + 0x6ec)
|
||||
|
||||
#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6f0)
|
||||
#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6f4)
|
||||
#define AR9170_MAC_REG_ACK_FC (AR9170_MAC_REG_BASE + 0x6f8)
|
||||
|
||||
#define AR9170_MAC_REG_CAM_MODE (AR9170_MAC_REG_BASE + 0x700)
|
||||
#define AR9170_MAC_CAM_IBSS 0xe0
|
||||
#define AR9170_MAC_CAM_AP 0xa1
|
||||
#define AR9170_MAC_CAM_STA 0x2
|
||||
#define AR9170_MAC_CAM_AP_WDS 0x3
|
||||
#define AR9170_MAC_CAM_DEFAULTS (0xf << 24)
|
||||
#define AR9170_MAC_CAM_HOST_PENDING 0x80000000
|
||||
|
||||
#define AR9170_MAC_REG_CAM_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704)
|
||||
#define AR9170_MAC_REG_CAM_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708)
|
||||
|
||||
#define AR9170_MAC_REG_CAM_ADDR (AR9170_MAC_REG_BASE + 0x70c)
|
||||
#define AR9170_MAC_CAM_ADDR_WRITE 0x80000000
|
||||
#define AR9170_MAC_REG_CAM_DATA0 (AR9170_MAC_REG_BASE + 0x720)
|
||||
#define AR9170_MAC_REG_CAM_DATA1 (AR9170_MAC_REG_BASE + 0x724)
|
||||
#define AR9170_MAC_REG_CAM_DATA2 (AR9170_MAC_REG_BASE + 0x728)
|
||||
#define AR9170_MAC_REG_CAM_DATA3 (AR9170_MAC_REG_BASE + 0x72c)
|
||||
|
||||
#define AR9170_MAC_REG_CAM_DBG0 (AR9170_MAC_REG_BASE + 0x730)
|
||||
#define AR9170_MAC_REG_CAM_DBG1 (AR9170_MAC_REG_BASE + 0x734)
|
||||
#define AR9170_MAC_REG_CAM_DBG2 (AR9170_MAC_REG_BASE + 0x738)
|
||||
#define AR9170_MAC_REG_CAM_STATE (AR9170_MAC_REG_BASE + 0x73c)
|
||||
#define AR9170_MAC_CAM_STATE_READ_PENDING 0x40000000
|
||||
#define AR9170_MAC_CAM_STATE_WRITE_PENDING 0x80000000
|
||||
|
||||
#define AR9170_MAC_REG_CAM_TXKEY (AR9170_MAC_REG_BASE + 0x740)
|
||||
#define AR9170_MAC_REG_CAM_RXKEY (AR9170_MAC_REG_BASE + 0x750)
|
||||
|
||||
#define AR9170_MAC_REG_CAM_TX_ENC_TYPE (AR9170_MAC_REG_BASE + 0x760)
|
||||
#define AR9170_MAC_REG_CAM_RX_ENC_TYPE (AR9170_MAC_REG_BASE + 0x770)
|
||||
#define AR9170_MAC_REG_CAM_TX_SERACH_HIT (AR9170_MAC_REG_BASE + 0x780)
|
||||
#define AR9170_MAC_REG_CAM_RX_SERACH_HIT (AR9170_MAC_REG_BASE + 0x790)
|
||||
|
||||
#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xb00)
|
||||
#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xb04)
|
||||
#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xb08)
|
||||
#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xb0c)
|
||||
#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xb10)
|
||||
#define AR9170_MAC_REG_AC2_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xb14)
|
||||
#define AR9170_MAC_REG_AC4_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xb18)
|
||||
#define AR9170_MAC_REG_TXOP_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0xb1c)
|
||||
#define AR9170_MAC_REG_TXOP_ACK_INTERVAL (AR9170_MAC_REG_BASE + 0xb20)
|
||||
#define AR9170_MAC_REG_CONTENTION_POINT (AR9170_MAC_REG_BASE + 0xb24)
|
||||
#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xb28)
|
||||
#define AR9170_MAC_REG_TID_CFACK_CFEND_RATE (AR9170_MAC_REG_BASE + 0xb2c)
|
||||
#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xb30)
|
||||
#define AR9170_MAC_REG_TKIP_TSC (AR9170_MAC_REG_BASE + 0xb34)
|
||||
#define AR9170_MAC_REG_TXOP_DURATION (AR9170_MAC_REG_BASE + 0xb38)
|
||||
#define AR9170_MAC_REG_TX_QOS_THRESHOLD (AR9170_MAC_REG_BASE + 0xb3c)
|
||||
#define AR9170_MAC_REG_QOS_PRIORITY_VIRTUAL_CCA (AR9170_MAC_REG_BASE + 0xb40)
|
||||
#define AR9170_MAC_VIRTUAL_CCA_Q0 BIT(15)
|
||||
#define AR9170_MAC_VIRTUAL_CCA_Q1 BIT(16)
|
||||
#define AR9170_MAC_VIRTUAL_CCA_Q2 BIT(17)
|
||||
#define AR9170_MAC_VIRTUAL_CCA_Q3 BIT(18)
|
||||
#define AR9170_MAC_VIRTUAL_CCA_Q4 BIT(19)
|
||||
#define AR9170_MAC_VIRTUAL_CCA_ALL (0xf8000)
|
||||
|
||||
#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xb44)
|
||||
#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xb48)
|
||||
|
||||
#define AR9170_MAC_REG_AMPDU_COUNT (AR9170_MAC_REG_BASE + 0xb88)
|
||||
#define AR9170_MAC_REG_MPDU_COUNT (AR9170_MAC_REG_BASE + 0xb8c)
|
||||
|
||||
#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xb9c)
|
||||
#define AR9170_MAC_AMPDU_FACTOR 0x7f0000
|
||||
#define AR9170_MAC_AMPDU_FACTOR_S 16
|
||||
#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xba0)
|
||||
#define AR9170_MAC_AMPDU_DENSITY 0x7
|
||||
#define AR9170_MAC_AMPDU_DENSITY_S 0
|
||||
|
||||
#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xbb0)
|
||||
#define AR9170_MAC_FCS_SWFCS 0x1
|
||||
#define AR9170_MAC_FCS_FIFO_PROT 0x4
|
||||
|
||||
#define AR9170_MAC_REG_RTS_CTS_TPC (AR9170_MAC_REG_BASE + 0xbb4)
|
||||
#define AR9170_MAC_REG_CFEND_QOSNULL_TPC (AR9170_MAC_REG_BASE + 0xbb8)
|
||||
|
||||
#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xc00)
|
||||
#define AR9170_MAC_REG_RX_CONTROL (AR9170_MAC_REG_BASE + 0xc40)
|
||||
#define AR9170_MAC_RX_CTRL_DEAGG 0x1
|
||||
#define AR9170_MAC_RX_CTRL_SHORT_FILTER 0x2
|
||||
#define AR9170_MAC_RX_CTRL_SA_DA_SEARCH 0x20
|
||||
#define AR9170_MAC_RX_CTRL_PASS_TO_HOST BIT(28)
|
||||
#define AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER BIT(30)
|
||||
|
||||
#define AR9170_MAC_REG_RX_CONTROL_1 (AR9170_MAC_REG_BASE + 0xc44)
|
||||
|
||||
#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xc50)
|
||||
|
||||
#define AR9170_MAC_REG_RX_MPDU (AR9170_MAC_REG_BASE + 0xca0)
|
||||
#define AR9170_MAC_REG_RX_DROPPED_MPDU (AR9170_MAC_REG_BASE + 0xca4)
|
||||
#define AR9170_MAC_REG_RX_DEL_MPDU (AR9170_MAC_REG_BASE + 0xca8)
|
||||
#define AR9170_MAC_REG_RX_PHY_MISC_ERROR (AR9170_MAC_REG_BASE + 0xcac)
|
||||
#define AR9170_MAC_REG_RX_PHY_XR_ERROR (AR9170_MAC_REG_BASE + 0xcb0)
|
||||
#define AR9170_MAC_REG_RX_PHY_OFDM_ERROR (AR9170_MAC_REG_BASE + 0xcb4)
|
||||
#define AR9170_MAC_REG_RX_PHY_CCK_ERROR (AR9170_MAC_REG_BASE + 0xcb8)
|
||||
#define AR9170_MAC_REG_RX_PHY_HT_ERROR (AR9170_MAC_REG_BASE + 0xcbc)
|
||||
#define AR9170_MAC_REG_RX_PHY_TOTAL (AR9170_MAC_REG_BASE + 0xcc0)
|
||||
|
||||
#define AR9170_MAC_REG_DMA_TXQ_ADDR (AR9170_MAC_REG_BASE + 0xd00)
|
||||
#define AR9170_MAC_REG_DMA_TXQ_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd04)
|
||||
#define AR9170_MAC_REG_DMA_TXQ0_ADDR (AR9170_MAC_REG_BASE + 0xd00)
|
||||
#define AR9170_MAC_REG_DMA_TXQ0_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd04)
|
||||
#define AR9170_MAC_REG_DMA_TXQ1_ADDR (AR9170_MAC_REG_BASE + 0xd08)
|
||||
#define AR9170_MAC_REG_DMA_TXQ1_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd0c)
|
||||
#define AR9170_MAC_REG_DMA_TXQ2_ADDR (AR9170_MAC_REG_BASE + 0xd10)
|
||||
#define AR9170_MAC_REG_DMA_TXQ2_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd14)
|
||||
#define AR9170_MAC_REG_DMA_TXQ3_ADDR (AR9170_MAC_REG_BASE + 0xd18)
|
||||
#define AR9170_MAC_REG_DMA_TXQ3_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd1c)
|
||||
#define AR9170_MAC_REG_DMA_TXQ4_ADDR (AR9170_MAC_REG_BASE + 0xd20)
|
||||
#define AR9170_MAC_REG_DMA_TXQ4_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd24)
|
||||
#define AR9170_MAC_REG_DMA_RXQ_ADDR (AR9170_MAC_REG_BASE + 0xd28)
|
||||
#define AR9170_MAC_REG_DMA_RXQ_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd2c)
|
||||
|
||||
#define AR9170_MAC_REG_DMA_TRIGGER (AR9170_MAC_REG_BASE + 0xd30)
|
||||
#define AR9170_DMA_TRIGGER_TXQ0 BIT(0)
|
||||
#define AR9170_DMA_TRIGGER_TXQ1 BIT(1)
|
||||
#define AR9170_DMA_TRIGGER_TXQ2 BIT(2)
|
||||
#define AR9170_DMA_TRIGGER_TXQ3 BIT(3)
|
||||
#define AR9170_DMA_TRIGGER_TXQ4 BIT(4)
|
||||
#define AR9170_DMA_TRIGGER_RXQ BIT(8)
|
||||
|
||||
#define AR9170_MAC_REG_DMA_WLAN_STATUS (AR9170_MAC_REG_BASE + 0xd38)
|
||||
#define AR9170_MAC_REG_DMA_STATUS (AR9170_MAC_REG_BASE + 0xd3c)
|
||||
|
||||
#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xd7c)
|
||||
#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f
|
||||
#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0
|
||||
#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000
|
||||
#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000
|
||||
|
||||
#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xd84)
|
||||
#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xd88)
|
||||
#define AR9170_MAC_BCN_LENGTH_MAX 256
|
||||
|
||||
#define AR9170_MAC_REG_BCN_STATUS (AR9170_MAC_REG_BASE + 0xd8c)
|
||||
|
||||
#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xd90)
|
||||
#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xd94)
|
||||
#define AR9170_BCN_CTRL_READY 0x01
|
||||
#define AR9170_BCN_CTRL_LOCK 0x02
|
||||
|
||||
#define AR9170_MAC_REG_BCN_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd98)
|
||||
#define AR9170_MAC_REG_BCN_COUNT (AR9170_MAC_REG_BASE + 0xd9c)
|
||||
|
||||
|
||||
#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xda0)
|
||||
#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xda4)
|
||||
|
||||
#define AR9170_MAC_REG_DMA_TXQX_ADDR_CURR (AR9170_MAC_REG_BASE + 0xdc0)
|
||||
|
||||
/* Random number generator */
|
||||
#define AR9170_RAND_REG_BASE 0x1d0000
|
||||
|
||||
#define AR9170_RAND_REG_NUM (AR9170_RAND_REG_BASE + 0x000)
|
||||
#define AR9170_RAND_REG_MODE (AR9170_RAND_REG_BASE + 0x004)
|
||||
#define AR9170_RAND_MODE_MANUAL 0x000
|
||||
#define AR9170_RAND_MODE_FREE 0x001
|
||||
|
||||
/* GPIO */
|
||||
#define AR9170_GPIO_REG_BASE 0x1d0100
|
||||
#define AR9170_GPIO_REG_PORT_TYPE (AR9170_GPIO_REG_BASE + 0x000)
|
||||
#define AR9170_GPIO_REG_PORT_DATA (AR9170_GPIO_REG_BASE + 0x004)
|
||||
#define AR9170_GPIO_PORT_LED_0 1
|
||||
#define AR9170_GPIO_PORT_LED_1 2
|
||||
/* WPS Button GPIO for TP-Link TL-WN821N */
|
||||
#define AR9170_GPIO_PORT_WPS_BUTTON_PRESSED 4
|
||||
|
||||
/* Memory Controller */
|
||||
#define AR9170_MC_REG_BASE 0x1d1000
|
||||
|
||||
#define AR9170_MC_REG_FLASH_WAIT_STATE (AR9170_MC_REG_BASE + 0x000)
|
||||
#define AR9170_MC_REG_SEEPROM_WP0 (AR9170_MC_REG_BASE + 0x400)
|
||||
#define AR9170_MC_REG_SEEPROM_WP1 (AR9170_MC_REG_BASE + 0x404)
|
||||
#define AR9170_MC_REG_SEEPROM_WP2 (AR9170_MC_REG_BASE + 0x408)
|
||||
|
||||
/* Interrupt Controller */
|
||||
#define AR9170_MAX_INT_SRC 9
|
||||
#define AR9170_INT_REG_BASE 0x1d2000
|
||||
|
||||
#define AR9170_INT_REG_FLAG (AR9170_INT_REG_BASE + 0x000)
|
||||
#define AR9170_INT_REG_FIQ_MASK (AR9170_INT_REG_BASE + 0x004)
|
||||
#define AR9170_INT_REG_IRQ_MASK (AR9170_INT_REG_BASE + 0x008)
|
||||
/* INT_REG_FLAG, INT_REG_FIQ_MASK and INT_REG_IRQ_MASK */
|
||||
#define AR9170_INT_FLAG_WLAN 0x001
|
||||
#define AR9170_INT_FLAG_PTAB_BIT 0x002
|
||||
#define AR9170_INT_FLAG_SE_BIT 0x004
|
||||
#define AR9170_INT_FLAG_UART_BIT 0x008
|
||||
#define AR9170_INT_FLAG_TIMER_BIT 0x010
|
||||
#define AR9170_INT_FLAG_EXT_BIT 0x020
|
||||
#define AR9170_INT_FLAG_SW_BIT 0x040
|
||||
#define AR9170_INT_FLAG_USB_BIT 0x080
|
||||
#define AR9170_INT_FLAG_ETHERNET_BIT 0x100
|
||||
|
||||
#define AR9170_INT_REG_PRIORITY1 (AR9170_INT_REG_BASE + 0x00c)
|
||||
#define AR9170_INT_REG_PRIORITY2 (AR9170_INT_REG_BASE + 0x010)
|
||||
#define AR9170_INT_REG_PRIORITY3 (AR9170_INT_REG_BASE + 0x014)
|
||||
#define AR9170_INT_REG_EXT_INT_CONTROL (AR9170_INT_REG_BASE + 0x018)
|
||||
#define AR9170_INT_REG_SW_INT_CONTROL (AR9170_INT_REG_BASE + 0x01c)
|
||||
#define AR9170_INT_SW_INT_ENABLE 0x1
|
||||
|
||||
#define AR9170_INT_REG_FIQ_ENCODE (AR9170_INT_REG_BASE + 0x020)
|
||||
#define AR9170_INT_INT_IRQ_ENCODE (AR9170_INT_REG_BASE + 0x024)
|
||||
|
||||
/* Power Management */
|
||||
#define AR9170_PWR_REG_BASE 0x1d4000
|
||||
|
||||
#define AR9170_PWR_REG_POWER_STATE (AR9170_PWR_REG_BASE + 0x000)
|
||||
|
||||
#define AR9170_PWR_REG_RESET (AR9170_PWR_REG_BASE + 0x004)
|
||||
#define AR9170_PWR_RESET_COMMIT_RESET_MASK BIT(0)
|
||||
#define AR9170_PWR_RESET_WLAN_MASK BIT(1)
|
||||
#define AR9170_PWR_RESET_DMA_MASK BIT(2)
|
||||
#define AR9170_PWR_RESET_BRIDGE_MASK BIT(3)
|
||||
#define AR9170_PWR_RESET_AHB_MASK BIT(9)
|
||||
#define AR9170_PWR_RESET_BB_WARM_RESET BIT(10)
|
||||
#define AR9170_PWR_RESET_BB_COLD_RESET BIT(11)
|
||||
#define AR9170_PWR_RESET_ADDA_CLK_COLD_RESET BIT(12)
|
||||
#define AR9170_PWR_RESET_PLL BIT(13)
|
||||
#define AR9170_PWR_RESET_USB_PLL BIT(14)
|
||||
|
||||
#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008)
|
||||
#define AR9170_PWR_CLK_AHB_40MHZ 0
|
||||
#define AR9170_PWR_CLK_AHB_20_22MHZ 1
|
||||
#define AR9170_PWR_CLK_AHB_40_44MHZ 2
|
||||
#define AR9170_PWR_CLK_AHB_80_88MHZ 3
|
||||
#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70
|
||||
|
||||
#define AR9170_PWR_REG_CHIP_REVISION (AR9170_PWR_REG_BASE + 0x010)
|
||||
#define AR9170_PWR_REG_PLL_ADDAC (AR9170_PWR_REG_BASE + 0x014)
|
||||
#define AR9170_PWR_REG_WATCH_DOG_MAGIC (AR9170_PWR_REG_BASE + 0x020)
|
||||
|
||||
/* Faraday USB Controller */
|
||||
#define AR9170_USB_REG_BASE 0x1e1000
|
||||
|
||||
#define AR9170_USB_REG_MAIN_CTRL (AR9170_USB_REG_BASE + 0x000)
|
||||
#define AR9170_USB_MAIN_CTRL_REMOTE_WAKEUP BIT(0)
|
||||
#define AR9170_USB_MAIN_CTRL_ENABLE_GLOBAL_INT BIT(2)
|
||||
#define AR9170_USB_MAIN_CTRL_HIGHSPEED BIT(6)
|
||||
|
||||
#define AR9170_USB_REG_DEVICE_ADDRESS (AR9170_USB_REG_BASE + 0x001)
|
||||
#define AR9170_USB_DEVICE_ADDRESS_CONFIGURE BIT(7)
|
||||
|
||||
#define AR9170_USB_REG_TEST (AR9170_USB_REG_BASE + 0x002)
|
||||
#define AR9170_USB_REG_PHY_TEST_SELECT (AR9170_USB_REG_BASE + 0x008)
|
||||
#define AR9170_USB_REG_CX_CONFIG_STATUS (AR9170_USB_REG_BASE + 0x00b)
|
||||
#define AR9170_USB_REG_EP0_DATA (AR9170_USB_REG_BASE + 0x00c)
|
||||
#define AR9170_USB_REG_EP0_DATA1 (AR9170_USB_REG_BASE + 0x00c)
|
||||
#define AR9170_USB_REG_EP0_DATA2 (AR9170_USB_REG_BASE + 0x00d)
|
||||
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_0 (AR9170_USB_REG_BASE + 0x011)
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_1 (AR9170_USB_REG_BASE + 0x012)
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_2 (AR9170_USB_REG_BASE + 0x013)
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_3 (AR9170_USB_REG_BASE + 0x014)
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_4 (AR9170_USB_REG_BASE + 0x015)
|
||||
#define AR9170_USB_INTR_DISABLE_OUT_INT (BIT(7) | BIT(6))
|
||||
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_5 (AR9170_USB_REG_BASE + 0x016)
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_6 (AR9170_USB_REG_BASE + 0x017)
|
||||
#define AR9170_USB_INTR_DISABLE_IN_INT BIT(6)
|
||||
|
||||
#define AR9170_USB_REG_INTR_MASK_BYTE_7 (AR9170_USB_REG_BASE + 0x018)
|
||||
|
||||
#define AR9170_USB_REG_INTR_GROUP (AR9170_USB_REG_BASE + 0x020)
|
||||
|
||||
#define AR9170_USB_REG_INTR_SOURCE_0 (AR9170_USB_REG_BASE + 0x021)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_1 (AR9170_USB_REG_BASE + 0x022)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_2 (AR9170_USB_REG_BASE + 0x023)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_3 (AR9170_USB_REG_BASE + 0x024)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_4 (AR9170_USB_REG_BASE + 0x025)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_5 (AR9170_USB_REG_BASE + 0x026)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_6 (AR9170_USB_REG_BASE + 0x027)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_7 (AR9170_USB_REG_BASE + 0x028)
|
||||
|
||||
#define AR9170_USB_REG_EP_MAP (AR9170_USB_REG_BASE + 0x030)
|
||||
#define AR9170_USB_REG_EP1_MAP (AR9170_USB_REG_BASE + 0x030)
|
||||
#define AR9170_USB_REG_EP2_MAP (AR9170_USB_REG_BASE + 0x031)
|
||||
#define AR9170_USB_REG_EP3_MAP (AR9170_USB_REG_BASE + 0x032)
|
||||
#define AR9170_USB_REG_EP4_MAP (AR9170_USB_REG_BASE + 0x033)
|
||||
#define AR9170_USB_REG_EP5_MAP (AR9170_USB_REG_BASE + 0x034)
|
||||
#define AR9170_USB_REG_EP6_MAP (AR9170_USB_REG_BASE + 0x035)
|
||||
#define AR9170_USB_REG_EP7_MAP (AR9170_USB_REG_BASE + 0x036)
|
||||
#define AR9170_USB_REG_EP8_MAP (AR9170_USB_REG_BASE + 0x037)
|
||||
#define AR9170_USB_REG_EP9_MAP (AR9170_USB_REG_BASE + 0x038)
|
||||
#define AR9170_USB_REG_EP10_MAP (AR9170_USB_REG_BASE + 0x039)
|
||||
|
||||
#define AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x03f)
|
||||
#define AR9170_USB_EP_IN_TOGGLE 0x10
|
||||
|
||||
#define AR9170_USB_REG_EP_IN_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x03e)
|
||||
|
||||
#define AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x05f)
|
||||
#define AR9170_USB_EP_OUT_TOGGLE 0x10
|
||||
|
||||
#define AR9170_USB_REG_EP_OUT_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x05e)
|
||||
|
||||
#define AR9170_USB_REG_EP3_BYTE_COUNT_HIGH (AR9170_USB_REG_BASE + 0x0ae)
|
||||
#define AR9170_USB_REG_EP3_BYTE_COUNT_LOW (AR9170_USB_REG_BASE + 0x0be)
|
||||
#define AR9170_USB_REG_EP4_BYTE_COUNT_HIGH (AR9170_USB_REG_BASE + 0x0af)
|
||||
#define AR9170_USB_REG_EP4_BYTE_COUNT_LOW (AR9170_USB_REG_BASE + 0x0bf)
|
||||
|
||||
#define AR9170_USB_REG_FIFO_MAP (AR9170_USB_REG_BASE + 0x080)
|
||||
#define AR9170_USB_REG_FIFO0_MAP (AR9170_USB_REG_BASE + 0x080)
|
||||
#define AR9170_USB_REG_FIFO1_MAP (AR9170_USB_REG_BASE + 0x081)
|
||||
#define AR9170_USB_REG_FIFO2_MAP (AR9170_USB_REG_BASE + 0x082)
|
||||
#define AR9170_USB_REG_FIFO3_MAP (AR9170_USB_REG_BASE + 0x083)
|
||||
#define AR9170_USB_REG_FIFO4_MAP (AR9170_USB_REG_BASE + 0x084)
|
||||
#define AR9170_USB_REG_FIFO5_MAP (AR9170_USB_REG_BASE + 0x085)
|
||||
#define AR9170_USB_REG_FIFO6_MAP (AR9170_USB_REG_BASE + 0x086)
|
||||
#define AR9170_USB_REG_FIFO7_MAP (AR9170_USB_REG_BASE + 0x087)
|
||||
#define AR9170_USB_REG_FIFO8_MAP (AR9170_USB_REG_BASE + 0x088)
|
||||
#define AR9170_USB_REG_FIFO9_MAP (AR9170_USB_REG_BASE + 0x089)
|
||||
|
||||
#define AR9170_USB_REG_FIFO_CONFIG (AR9170_USB_REG_BASE + 0x090)
|
||||
#define AR9170_USB_REG_FIFO0_CONFIG (AR9170_USB_REG_BASE + 0x090)
|
||||
#define AR9170_USB_REG_FIFO1_CONFIG (AR9170_USB_REG_BASE + 0x091)
|
||||
#define AR9170_USB_REG_FIFO2_CONFIG (AR9170_USB_REG_BASE + 0x092)
|
||||
#define AR9170_USB_REG_FIFO3_CONFIG (AR9170_USB_REG_BASE + 0x093)
|
||||
#define AR9170_USB_REG_FIFO4_CONFIG (AR9170_USB_REG_BASE + 0x094)
|
||||
#define AR9170_USB_REG_FIFO5_CONFIG (AR9170_USB_REG_BASE + 0x095)
|
||||
#define AR9170_USB_REG_FIFO6_CONFIG (AR9170_USB_REG_BASE + 0x096)
|
||||
#define AR9170_USB_REG_FIFO7_CONFIG (AR9170_USB_REG_BASE + 0x097)
|
||||
#define AR9170_USB_REG_FIFO8_CONFIG (AR9170_USB_REG_BASE + 0x098)
|
||||
#define AR9170_USB_REG_FIFO9_CONFIG (AR9170_USB_REG_BASE + 0x099)
|
||||
|
||||
#define AR9170_USB_REG_EP3_DATA (AR9170_USB_REG_BASE + 0x0f8)
|
||||
#define AR9170_USB_REG_EP4_DATA (AR9170_USB_REG_BASE + 0x0fc)
|
||||
|
||||
#define AR9170_USB_REG_FIFO_SIZE (AR9170_USB_REG_BASE + 0x100)
|
||||
#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108)
|
||||
#define AR9170_USB_DMA_CTL_ENABLE_TO_DEVICE BIT(0)
|
||||
#define AR9170_USB_DMA_CTL_ENABLE_FROM_DEVICE BIT(1)
|
||||
#define AR9170_USB_DMA_CTL_HIGH_SPEED BIT(2)
|
||||
#define AR9170_USB_DMA_CTL_UP_PACKET_MODE BIT(3)
|
||||
#define AR9170_USB_DMA_CTL_UP_STREAM_S 4
|
||||
#define AR9170_USB_DMA_CTL_UP_STREAM (BIT(4) | BIT(5))
|
||||
#define AR9170_USB_DMA_CTL_UP_STREAM_4K (0)
|
||||
#define AR9170_USB_DMA_CTL_UP_STREAM_8K BIT(4)
|
||||
#define AR9170_USB_DMA_CTL_UP_STREAM_16K BIT(5)
|
||||
#define AR9170_USB_DMA_CTL_UP_STREAM_32K (BIT(4) | BIT(5))
|
||||
#define AR9170_USB_DMA_CTL_DOWN_STREAM BIT(6)
|
||||
|
||||
#define AR9170_USB_REG_DMA_STATUS (AR9170_USB_REG_BASE + 0x10c)
|
||||
#define AR9170_USB_DMA_STATUS_UP_IDLE BIT(8)
|
||||
#define AR9170_USB_DMA_STATUS_DN_IDLE BIT(16)
|
||||
|
||||
#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110)
|
||||
#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114)
|
||||
#define AR9170_USB_REG_CBUS_CTRL (AR9170_USB_REG_BASE + 0x1f0)
|
||||
#define AR9170_USB_CBUS_CTRL_BUFFER_END (BIT(1))
|
||||
|
||||
/* PCI/USB to AHB Bridge */
|
||||
#define AR9170_PTA_REG_BASE 0x1e2000
|
||||
|
||||
#define AR9170_PTA_REG_CMD (AR9170_PTA_REG_BASE + 0x000)
|
||||
#define AR9170_PTA_REG_PARAM1 (AR9170_PTA_REG_BASE + 0x004)
|
||||
#define AR9170_PTA_REG_PARAM2 (AR9170_PTA_REG_BASE + 0x008)
|
||||
#define AR9170_PTA_REG_PARAM3 (AR9170_PTA_REG_BASE + 0x00c)
|
||||
#define AR9170_PTA_REG_RSP (AR9170_PTA_REG_BASE + 0x010)
|
||||
#define AR9170_PTA_REG_STATUS1 (AR9170_PTA_REG_BASE + 0x014)
|
||||
#define AR9170_PTA_REG_STATUS2 (AR9170_PTA_REG_BASE + 0x018)
|
||||
#define AR9170_PTA_REG_STATUS3 (AR9170_PTA_REG_BASE + 0x01c)
|
||||
#define AR9170_PTA_REG_AHB_INT_FLAG (AR9170_PTA_REG_BASE + 0x020)
|
||||
#define AR9170_PTA_REG_AHB_INT_MASK (AR9170_PTA_REG_BASE + 0x024)
|
||||
#define AR9170_PTA_REG_AHB_INT_ACK (AR9170_PTA_REG_BASE + 0x028)
|
||||
#define AR9170_PTA_REG_AHB_SCRATCH1 (AR9170_PTA_REG_BASE + 0x030)
|
||||
#define AR9170_PTA_REG_AHB_SCRATCH2 (AR9170_PTA_REG_BASE + 0x034)
|
||||
#define AR9170_PTA_REG_AHB_SCRATCH3 (AR9170_PTA_REG_BASE + 0x038)
|
||||
#define AR9170_PTA_REG_AHB_SCRATCH4 (AR9170_PTA_REG_BASE + 0x03c)
|
||||
|
||||
#define AR9170_PTA_REG_SHARE_MEM_CTRL (AR9170_PTA_REG_BASE + 0x124)
|
||||
|
||||
/*
|
||||
* PCI to AHB Bridge
|
||||
*/
|
||||
|
||||
#define AR9170_PTA_REG_INT_FLAG (AR9170_PTA_REG_BASE + 0x100)
|
||||
#define AR9170_PTA_INT_FLAG_DN 0x01
|
||||
#define AR9170_PTA_INT_FLAG_UP 0x02
|
||||
#define AR9170_PTA_INT_FLAG_CMD 0x04
|
||||
|
||||
#define AR9170_PTA_REG_INT_MASK (AR9170_PTA_REG_BASE + 0x104)
|
||||
#define AR9170_PTA_REG_DN_DMA_ADDRL (AR9170_PTA_REG_BASE + 0x108)
|
||||
#define AR9170_PTA_REG_DN_DMA_ADDRH (AR9170_PTA_REG_BASE + 0x10c)
|
||||
#define AR9170_PTA_REG_UP_DMA_ADDRL (AR9170_PTA_REG_BASE + 0x110)
|
||||
#define AR9170_PTA_REG_UP_DMA_ADDRH (AR9170_PTA_REG_BASE + 0x114)
|
||||
#define AR9170_PTA_REG_DN_PEND_TIME (AR9170_PTA_REG_BASE + 0x118)
|
||||
#define AR9170_PTA_REG_UP_PEND_TIME (AR9170_PTA_REG_BASE + 0x11c)
|
||||
#define AR9170_PTA_REG_CONTROL (AR9170_PTA_REG_BASE + 0x120)
|
||||
#define AR9170_PTA_CTRL_4_BEAT_BURST 0x00
|
||||
#define AR9170_PTA_CTRL_8_BEAT_BURST 0x01
|
||||
#define AR9170_PTA_CTRL_16_BEAT_BURST 0x02
|
||||
#define AR9170_PTA_CTRL_LOOPBACK_MODE 0x10
|
||||
|
||||
#define AR9170_PTA_REG_MEM_CTRL (AR9170_PTA_REG_BASE + 0x124)
|
||||
#define AR9170_PTA_REG_MEM_ADDR (AR9170_PTA_REG_BASE + 0x128)
|
||||
#define AR9170_PTA_REG_DN_DMA_TRIGGER (AR9170_PTA_REG_BASE + 0x12c)
|
||||
#define AR9170_PTA_REG_UP_DMA_TRIGGER (AR9170_PTA_REG_BASE + 0x130)
|
||||
#define AR9170_PTA_REG_DMA_STATUS (AR9170_PTA_REG_BASE + 0x134)
|
||||
#define AR9170_PTA_REG_DN_CURR_ADDRL (AR9170_PTA_REG_BASE + 0x138)
|
||||
#define AR9170_PTA_REG_DN_CURR_ADDRH (AR9170_PTA_REG_BASE + 0x13c)
|
||||
#define AR9170_PTA_REG_UP_CURR_ADDRL (AR9170_PTA_REG_BASE + 0x140)
|
||||
#define AR9170_PTA_REG_UP_CURR_ADDRH (AR9170_PTA_REG_BASE + 0x144)
|
||||
#define AR9170_PTA_REG_DMA_MODE_CTRL (AR9170_PTA_REG_BASE + 0x148)
|
||||
#define AR9170_PTA_DMA_MODE_CTRL_RESET BIT(0)
|
||||
#define AR9170_PTA_DMA_MODE_CTRL_DISABLE_USB BIT(1)
|
||||
|
||||
/* Protocol Controller Module */
|
||||
#define AR9170_MAC_REG_PC_REG_BASE (AR9170_MAC_REG_BASE + 0xe00)
|
||||
|
||||
|
||||
#define AR9170_NUM_LEDS 2
|
||||
|
||||
/* CAM */
|
||||
#define AR9170_CAM_MAX_USER 64
|
||||
#define AR9170_CAM_MAX_KEY_LENGTH 16
|
||||
|
||||
#define AR9170_SRAM_OFFSET 0x100000
|
||||
#define AR9170_SRAM_SIZE 0x18000
|
||||
|
||||
#define AR9170_PRAM_OFFSET 0x200000
|
||||
#define AR9170_PRAM_SIZE 0x8000
|
||||
|
||||
enum cpu_clock {
|
||||
AHB_STATIC_40MHZ = 0,
|
||||
AHB_GMODE_22MHZ = 1,
|
||||
AHB_AMODE_20MHZ = 1,
|
||||
AHB_GMODE_44MHZ = 2,
|
||||
AHB_AMODE_40MHZ = 2,
|
||||
AHB_GMODE_88MHZ = 3,
|
||||
AHB_AMODE_80MHZ = 3
|
||||
};
|
||||
|
||||
/* USB endpoints */
|
||||
enum ar9170_usb_ep {
|
||||
/*
|
||||
* Control EP is always EP 0 (USB SPEC)
|
||||
*
|
||||
* The weird thing is: the original firmware has a few
|
||||
* comments that suggest that the actual EP numbers
|
||||
* are in the 1 to 10 range?!
|
||||
*/
|
||||
AR9170_USB_EP_CTRL = 0,
|
||||
|
||||
AR9170_USB_EP_TX,
|
||||
AR9170_USB_EP_RX,
|
||||
AR9170_USB_EP_IRQ,
|
||||
AR9170_USB_EP_CMD,
|
||||
AR9170_USB_NUM_EXTRA_EP = 4,
|
||||
|
||||
__AR9170_USB_NUM_EP,
|
||||
|
||||
__AR9170_USB_NUM_MAX_EP = 10
|
||||
};
|
||||
|
||||
enum ar9170_usb_fifo {
|
||||
__AR9170_USB_NUM_MAX_FIFO = 10
|
||||
};
|
||||
|
||||
enum ar9170_tx_queues {
|
||||
AR9170_TXQ0 = 0,
|
||||
AR9170_TXQ1,
|
||||
AR9170_TXQ2,
|
||||
AR9170_TXQ3,
|
||||
AR9170_TXQ_SPECIAL,
|
||||
|
||||
/* keep last */
|
||||
__AR9170_NUM_TX_QUEUES = 5
|
||||
};
|
||||
|
||||
#define AR9170_TX_STREAM_TAG 0x697e
|
||||
#define AR9170_RX_STREAM_TAG 0x4e00
|
||||
#define AR9170_RX_STREAM_MAX_SIZE 0xffff
|
||||
|
||||
struct ar9170_stream {
|
||||
__le16 length;
|
||||
__le16 tag;
|
||||
|
||||
u8 payload[0];
|
||||
};
|
||||
|
||||
#define AR9170_MAX_ACKTABLE_ENTRIES 8
|
||||
#define AR9170_MAX_VIRTUAL_MAC 7
|
||||
|
||||
#define AR9170_USB_EP_CTRL_MAX 64
|
||||
#define AR9170_USB_EP_TX_MAX 512
|
||||
#define AR9170_USB_EP_RX_MAX 512
|
||||
#define AR9170_USB_EP_IRQ_MAX 64
|
||||
#define AR9170_USB_EP_CMD_MAX 64
|
||||
|
||||
/* Trigger PRETBTT interrupt 6 Kus earlier */
|
||||
#define CARL9170_PRETBTT_KUS 6
|
||||
|
||||
#define AR5416_MAX_RATE_POWER 63
|
||||
|
||||
#define SET_VAL(reg, value, newvalue) \
|
||||
(value = ((value) & ~reg) | (((newvalue) << reg##_S) & reg))
|
||||
|
||||
#define MOD_VAL(reg, value, newvalue) \
|
||||
(((value) & ~reg) | (((newvalue) << reg##_S) & reg))
|
||||
#endif /* __CARL9170_SHARED_HW_H */
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* LED handling
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparer <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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 "carl9170.h"
|
||||
#include "cmd.h"
|
||||
|
||||
int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state)
|
||||
{
|
||||
return carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_DATA, led_state);
|
||||
}
|
||||
|
||||
int carl9170_led_init(struct ar9170 *ar)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* disable LEDs */
|
||||
/* GPIO [0/1 mode: output, 2/3: input] */
|
||||
err = carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* GPIO 0/1 value: off */
|
||||
err = carl9170_led_set_state(ar, 0);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CARL9170_LEDS
|
||||
static void carl9170_led_update(struct work_struct *work)
|
||||
{
|
||||
struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
|
||||
int i, tmp = 300, blink_delay = 1000;
|
||||
u32 led_val = 0;
|
||||
bool rerun = false;
|
||||
|
||||
if (!IS_ACCEPTING_CMD(ar))
|
||||
return;
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
for (i = 0; i < AR9170_NUM_LEDS; i++) {
|
||||
if (ar->leds[i].registered) {
|
||||
if (ar->leds[i].last_state ||
|
||||
ar->leds[i].toggled) {
|
||||
|
||||
if (ar->leds[i].toggled)
|
||||
tmp = 70 + 200 / (ar->leds[i].toggled);
|
||||
|
||||
if (tmp < blink_delay)
|
||||
blink_delay = tmp;
|
||||
|
||||
led_val |= 1 << i;
|
||||
ar->leds[i].toggled = 0;
|
||||
rerun = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
carl9170_led_set_state(ar, led_val);
|
||||
mutex_unlock(&ar->mutex);
|
||||
|
||||
if (!rerun)
|
||||
return;
|
||||
|
||||
ieee80211_queue_delayed_work(ar->hw,
|
||||
&ar->led_work,
|
||||
msecs_to_jiffies(blink_delay));
|
||||
}
|
||||
|
||||
static void carl9170_led_set_brightness(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct carl9170_led *arl = container_of(led, struct carl9170_led, l);
|
||||
struct ar9170 *ar = arl->ar;
|
||||
|
||||
if (!arl->registered)
|
||||
return;
|
||||
|
||||
if (arl->last_state != !!brightness) {
|
||||
arl->toggled++;
|
||||
arl->last_state = !!brightness;
|
||||
}
|
||||
|
||||
if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
|
||||
ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
|
||||
}
|
||||
|
||||
static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
|
||||
char *trigger)
|
||||
{
|
||||
int err;
|
||||
|
||||
snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
|
||||
"carl9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
|
||||
|
||||
ar->leds[i].ar = ar;
|
||||
ar->leds[i].l.name = ar->leds[i].name;
|
||||
ar->leds[i].l.brightness_set = carl9170_led_set_brightness;
|
||||
ar->leds[i].l.brightness = 0;
|
||||
ar->leds[i].l.default_trigger = trigger;
|
||||
|
||||
err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
|
||||
&ar->leds[i].l);
|
||||
if (err) {
|
||||
wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
|
||||
ar->leds[i].name, err);
|
||||
} else {
|
||||
ar->leds[i].registered = true;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void carl9170_led_unregister(struct ar9170 *ar)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AR9170_NUM_LEDS; i++)
|
||||
if (ar->leds[i].registered) {
|
||||
led_classdev_unregister(&ar->leds[i].l);
|
||||
ar->leds[i].registered = false;
|
||||
ar->leds[i].toggled = 0;
|
||||
}
|
||||
|
||||
cancel_delayed_work_sync(&ar->led_work);
|
||||
}
|
||||
|
||||
int carl9170_led_register(struct ar9170 *ar)
|
||||
{
|
||||
int err;
|
||||
|
||||
INIT_DELAYED_WORK(&ar->led_work, carl9170_led_update);
|
||||
|
||||
err = carl9170_led_register_led(ar, 0, "tx",
|
||||
ieee80211_get_tx_led_name(ar->hw));
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
if (ar->features & CARL9170_ONE_LED)
|
||||
return 0;
|
||||
|
||||
err = carl9170_led_register_led(ar, 1, "assoc",
|
||||
ieee80211_get_assoc_led_name(ar->hw));
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
carl9170_led_unregister(ar);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CARL9170_LEDS */
|
|
@ -0,0 +1,604 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* MAC programming
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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 <asm/unaligned.h>
|
||||
|
||||
#include "carl9170.h"
|
||||
#include "cmd.h"
|
||||
|
||||
int carl9170_set_dyn_sifs_ack(struct ar9170 *ar)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (conf_is_ht40(&ar->hw->conf))
|
||||
val = 0x010a;
|
||||
else {
|
||||
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
|
||||
val = 0x105;
|
||||
else
|
||||
val = 0x104;
|
||||
}
|
||||
|
||||
return carl9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val);
|
||||
}
|
||||
|
||||
int carl9170_set_rts_cts_rate(struct ar9170 *ar)
|
||||
{
|
||||
u32 rts_rate, cts_rate;
|
||||
|
||||
if (conf_is_ht(&ar->hw->conf)) {
|
||||
/* 12 mbit OFDM */
|
||||
rts_rate = 0x1da;
|
||||
cts_rate = 0x10a;
|
||||
} else {
|
||||
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
|
||||
/* 11 mbit CCK */
|
||||
rts_rate = 033;
|
||||
cts_rate = 003;
|
||||
} else {
|
||||
/* 6 mbit OFDM */
|
||||
rts_rate = 0x1bb;
|
||||
cts_rate = 0x10b;
|
||||
}
|
||||
}
|
||||
|
||||
return carl9170_write_reg(ar, AR9170_MAC_REG_RTS_CTS_RATE,
|
||||
rts_rate | (cts_rate) << 16);
|
||||
}
|
||||
|
||||
int carl9170_set_slot_time(struct ar9170 *ar)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
u32 slottime = 20;
|
||||
|
||||
rcu_read_lock();
|
||||
vif = carl9170_get_main_vif(ar);
|
||||
if (!vif) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
|
||||
vif->bss_conf.use_short_slot)
|
||||
slottime = 9;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return carl9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME,
|
||||
slottime << 10);
|
||||
}
|
||||
|
||||
int carl9170_set_mac_rates(struct ar9170 *ar)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
u32 basic, mandatory;
|
||||
|
||||
rcu_read_lock();
|
||||
vif = carl9170_get_main_vif(ar);
|
||||
|
||||
if (!vif) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
basic = (vif->bss_conf.basic_rates & 0xf);
|
||||
basic |= (vif->bss_conf.basic_rates & 0xff0) << 4;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
|
||||
mandatory = 0xff00; /* OFDM 6/9/12/18/24/36/48/54 */
|
||||
else
|
||||
mandatory = 0xff0f; /* OFDM (6/9../54) + CCK (1/2/5.5/11) */
|
||||
|
||||
carl9170_regwrite_begin(ar);
|
||||
carl9170_regwrite(AR9170_MAC_REG_BASIC_RATE, basic);
|
||||
carl9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, mandatory);
|
||||
carl9170_regwrite_finish();
|
||||
|
||||
return carl9170_regwrite_result();
|
||||
}
|
||||
|
||||
int carl9170_set_qos(struct ar9170 *ar)
|
||||
{
|
||||
carl9170_regwrite_begin(ar);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min |
|
||||
(ar->edcf[0].cw_max << 16));
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min |
|
||||
(ar->edcf[1].cw_max << 16));
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min |
|
||||
(ar->edcf[2].cw_max << 16));
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min |
|
||||
(ar->edcf[3].cw_max << 16));
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min |
|
||||
(ar->edcf[4].cw_max << 16));
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC2_AC1_AC0_AIFS,
|
||||
((ar->edcf[0].aifs * 9 + 10)) |
|
||||
((ar->edcf[1].aifs * 9 + 10) << 12) |
|
||||
((ar->edcf[2].aifs * 9 + 10) << 24));
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC4_AC3_AC2_AIFS,
|
||||
((ar->edcf[2].aifs * 9 + 10) >> 8) |
|
||||
((ar->edcf[3].aifs * 9 + 10) << 4) |
|
||||
((ar->edcf[4].aifs * 9 + 10) << 16));
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
|
||||
ar->edcf[0].txop | ar->edcf[1].txop << 16);
|
||||
carl9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
|
||||
ar->edcf[2].txop | ar->edcf[3].txop << 16 |
|
||||
ar->edcf[4].txop << 24);
|
||||
|
||||
carl9170_regwrite_finish();
|
||||
|
||||
return carl9170_regwrite_result();
|
||||
}
|
||||
|
||||
int carl9170_init_mac(struct ar9170 *ar)
|
||||
{
|
||||
carl9170_regwrite_begin(ar);
|
||||
|
||||
/* switch MAC to OTUS interface */
|
||||
carl9170_regwrite(0x1c3600, 0x3);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0x0);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
|
||||
AR9170_MAC_FTF_MONITOR);
|
||||
|
||||
/* enable MMIC */
|
||||
carl9170_regwrite(AR9170_MAC_REG_SNIFFER,
|
||||
AR9170_MAC_SNIFFER_DEFAULTS);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70);
|
||||
carl9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000);
|
||||
carl9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10);
|
||||
|
||||
/* CF-END & CF-ACK rate => 24M OFDM */
|
||||
carl9170_regwrite(AR9170_MAC_REG_TID_CFACK_CFEND_RATE, 0x59900000);
|
||||
|
||||
/* NAV protects ACK only (in TXOP) */
|
||||
carl9170_regwrite(AR9170_MAC_REG_TXOP_DURATION, 0x201);
|
||||
|
||||
/* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */
|
||||
/* OTUS set AM to 0x1 */
|
||||
carl9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105);
|
||||
|
||||
/* Aggregation MAX number and timeout */
|
||||
carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0xa);
|
||||
carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a00);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
|
||||
AR9170_MAC_FTF_DEFAULTS);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_RX_CONTROL,
|
||||
AR9170_MAC_RX_CTRL_DEAGG |
|
||||
AR9170_MAC_RX_CTRL_SHORT_FILTER);
|
||||
|
||||
/* rate sets */
|
||||
carl9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f);
|
||||
carl9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f);
|
||||
carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x0030033);
|
||||
|
||||
/* MIMO response control */
|
||||
carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, 0x4003c1e);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff);
|
||||
|
||||
/* set PHY register read timeout (??) */
|
||||
carl9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008);
|
||||
|
||||
/* Disable Rx TimeOut, workaround for BB. */
|
||||
carl9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0);
|
||||
|
||||
/* Set WLAN DMA interrupt mode: generate int per packet */
|
||||
carl9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011);
|
||||
|
||||
carl9170_regwrite(AR9170_MAC_REG_FCS_SELECT,
|
||||
AR9170_MAC_FCS_FIFO_PROT);
|
||||
|
||||
/* Disables the CF_END frame, undocumented register */
|
||||
carl9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND,
|
||||
0x141e0f48);
|
||||
|
||||
/* reset group hash table */
|
||||
carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, 0xffffffff);
|
||||
carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, 0xffffffff);
|
||||
|
||||
/* disable PRETBTT interrupt */
|
||||
carl9170_regwrite(AR9170_MAC_REG_PRETBTT, 0x0);
|
||||
carl9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, 0x0);
|
||||
|
||||
carl9170_regwrite_finish();
|
||||
|
||||
return carl9170_regwrite_result();
|
||||
}
|
||||
|
||||
static int carl9170_set_mac_reg(struct ar9170 *ar,
|
||||
const u32 reg, const u8 *mac)
|
||||
{
|
||||
static const u8 zero[ETH_ALEN] = { 0 };
|
||||
|
||||
if (!mac)
|
||||
mac = zero;
|
||||
|
||||
carl9170_regwrite_begin(ar);
|
||||
|
||||
carl9170_regwrite(reg, get_unaligned_le32(mac));
|
||||
carl9170_regwrite(reg + 4, get_unaligned_le16(mac + 4));
|
||||
|
||||
carl9170_regwrite_finish();
|
||||
|
||||
return carl9170_regwrite_result();
|
||||
}
|
||||
|
||||
int carl9170_mod_virtual_mac(struct ar9170 *ar, const unsigned int id,
|
||||
const u8 *mac)
|
||||
{
|
||||
if (WARN_ON(id >= ar->fw.vif_num))
|
||||
return -EINVAL;
|
||||
|
||||
return carl9170_set_mac_reg(ar,
|
||||
AR9170_MAC_REG_ACK_TABLE + (id - 1) * 8, mac);
|
||||
}
|
||||
|
||||
int carl9170_update_multicast(struct ar9170 *ar, const u64 mc_hash)
|
||||
{
|
||||
int err;
|
||||
|
||||
carl9170_regwrite_begin(ar);
|
||||
carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32);
|
||||
carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash);
|
||||
carl9170_regwrite_finish();
|
||||
err = carl9170_regwrite_result();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ar->cur_mc_hash = mc_hash;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int carl9170_set_operating_mode(struct ar9170 *ar)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_common *common = &ar->common;
|
||||
u8 *mac_addr, *bssid;
|
||||
u32 cam_mode = AR9170_MAC_CAM_DEFAULTS;
|
||||
u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS;
|
||||
u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG |
|
||||
AR9170_MAC_RX_CTRL_SHORT_FILTER;
|
||||
u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
vif = carl9170_get_main_vif(ar);
|
||||
|
||||
if (vif) {
|
||||
mac_addr = common->macaddr;
|
||||
bssid = common->curbssid;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
cam_mode |= AR9170_MAC_CAM_IBSS;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
cam_mode |= AR9170_MAC_CAM_AP;
|
||||
|
||||
/* iwlagn 802.11n STA Workaround */
|
||||
rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
cam_mode |= AR9170_MAC_CAM_AP_WDS;
|
||||
rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
cam_mode |= AR9170_MAC_CAM_STA;
|
||||
rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Unsupported operation mode %x\n", vif->type);
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mac_addr = NULL;
|
||||
bssid = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ar->rx_software_decryption)
|
||||
enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
|
||||
|
||||
if (ar->sniffer_enabled) {
|
||||
rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER;
|
||||
sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC;
|
||||
enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
|
||||
}
|
||||
|
||||
err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
carl9170_regwrite_begin(ar);
|
||||
carl9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer);
|
||||
carl9170_regwrite(AR9170_MAC_REG_CAM_MODE, cam_mode);
|
||||
carl9170_regwrite(AR9170_MAC_REG_ENCRYPTION, enc_mode);
|
||||
carl9170_regwrite(AR9170_MAC_REG_RX_CONTROL, rx_ctrl);
|
||||
carl9170_regwrite_finish();
|
||||
|
||||
return carl9170_regwrite_result();
|
||||
}
|
||||
|
||||
int carl9170_set_hwretry_limit(struct ar9170 *ar, const unsigned int max_retry)
|
||||
{
|
||||
u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111);
|
||||
|
||||
return carl9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp);
|
||||
}
|
||||
|
||||
int carl9170_set_beacon_timers(struct ar9170 *ar)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
u32 v = 0;
|
||||
u32 pretbtt = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
vif = carl9170_get_main_vif(ar);
|
||||
|
||||
if (vif) {
|
||||
struct carl9170_vif_info *mvif;
|
||||
mvif = (void *) vif->drv_priv;
|
||||
|
||||
if (mvif->enable_beacon && !WARN_ON(!ar->beacon_enabled)) {
|
||||
ar->global_beacon_int = vif->bss_conf.beacon_int /
|
||||
ar->beacon_enabled;
|
||||
|
||||
SET_VAL(AR9170_MAC_BCN_DTIM, v,
|
||||
vif->bss_conf.dtim_period);
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
v |= AR9170_MAC_BCN_IBSS_MODE;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
v |= AR9170_MAC_BCN_AP_MODE;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
} else if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
ar->global_beacon_int = vif->bss_conf.beacon_int;
|
||||
|
||||
SET_VAL(AR9170_MAC_BCN_DTIM, v,
|
||||
ar->hw->conf.ps_dtim_period);
|
||||
|
||||
v |= AR9170_MAC_BCN_STA_PS |
|
||||
AR9170_MAC_BCN_PWR_MGT;
|
||||
}
|
||||
|
||||
if (ar->global_beacon_int) {
|
||||
if (ar->global_beacon_int < 15) {
|
||||
rcu_read_unlock();
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
ar->global_pretbtt = ar->global_beacon_int -
|
||||
CARL9170_PRETBTT_KUS;
|
||||
} else {
|
||||
ar->global_pretbtt = 0;
|
||||
}
|
||||
} else {
|
||||
ar->global_beacon_int = 0;
|
||||
ar->global_pretbtt = 0;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
SET_VAL(AR9170_MAC_BCN_PERIOD, v, ar->global_beacon_int);
|
||||
SET_VAL(AR9170_MAC_PRETBTT, pretbtt, ar->global_pretbtt);
|
||||
SET_VAL(AR9170_MAC_PRETBTT2, pretbtt, ar->global_pretbtt);
|
||||
|
||||
carl9170_regwrite_begin(ar);
|
||||
carl9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
|
||||
carl9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
|
||||
carl9170_regwrite_finish();
|
||||
return carl9170_regwrite_result();
|
||||
}
|
||||
|
||||
int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct carl9170_vif_info *cvif;
|
||||
__le32 *data, *old = NULL;
|
||||
u32 word, off, addr, len;
|
||||
int i = 0, err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
cvif = rcu_dereference(ar->beacon_iter);
|
||||
retry:
|
||||
if (ar->vifs == 0 || !cvif)
|
||||
goto out_unlock;
|
||||
|
||||
list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
|
||||
if (cvif->active && cvif->enable_beacon)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (!ar->beacon_enabled || i++)
|
||||
goto out_unlock;
|
||||
|
||||
goto retry;
|
||||
|
||||
found:
|
||||
rcu_assign_pointer(ar->beacon_iter, cvif);
|
||||
|
||||
skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
|
||||
NULL, NULL);
|
||||
|
||||
if (!skb) {
|
||||
err = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->beacon_lock);
|
||||
data = (__le32 *)skb->data;
|
||||
if (cvif->beacon)
|
||||
old = (__le32 *)cvif->beacon->data;
|
||||
|
||||
off = cvif->id * AR9170_MAC_BCN_LENGTH_MAX;
|
||||
addr = ar->fw.beacon_addr + off;
|
||||
len = roundup(skb->len + FCS_LEN, 4);
|
||||
|
||||
if ((off + len) > ar->fw.beacon_max_len) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "beacon does not "
|
||||
"fit into device memory!\n");
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar->beacon_lock);
|
||||
dev_kfree_skb_any(skb);
|
||||
err = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (len > AR9170_MAC_BCN_LENGTH_MAX) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "no support for beacons "
|
||||
"bigger than %d (yours:%d).\n",
|
||||
AR9170_MAC_BCN_LENGTH_MAX, len);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar->beacon_lock);
|
||||
dev_kfree_skb_any(skb);
|
||||
err = -EMSGSIZE;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
carl9170_async_regwrite_begin(ar);
|
||||
|
||||
/* XXX: use skb->cb info */
|
||||
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
|
||||
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP,
|
||||
((skb->len + FCS_LEN) << (3 + 16)) + 0x0400);
|
||||
} else {
|
||||
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP,
|
||||
((skb->len + FCS_LEN) << 16) + 0x001b);
|
||||
}
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
|
||||
/*
|
||||
* XXX: This accesses beyond skb data for up
|
||||
* to the last 3 bytes!!
|
||||
*/
|
||||
|
||||
if (old && (data[i] == old[i]))
|
||||
continue;
|
||||
|
||||
word = le32_to_cpu(data[i]);
|
||||
carl9170_async_regwrite(addr + 4 * i, word);
|
||||
}
|
||||
carl9170_async_regwrite_finish();
|
||||
|
||||
dev_kfree_skb_any(cvif->beacon);
|
||||
cvif->beacon = NULL;
|
||||
|
||||
err = carl9170_async_regwrite_result();
|
||||
if (!err)
|
||||
cvif->beacon = skb;
|
||||
spin_unlock_bh(&ar->beacon_lock);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
if (submit) {
|
||||
err = carl9170_bcn_ctrl(ar, cvif->id,
|
||||
CARL9170_BCN_CTRL_CAB_TRIGGER,
|
||||
addr, skb->len + FCS_LEN);
|
||||
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
}
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
|
||||
const u8 ktype, const u8 keyidx, const u8 *keydata,
|
||||
const int keylen)
|
||||
{
|
||||
struct carl9170_set_key_cmd key = { };
|
||||
static const u8 bcast[ETH_ALEN] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
mac = mac ? : bcast;
|
||||
|
||||
key.user = cpu_to_le16(id);
|
||||
key.keyId = cpu_to_le16(keyidx);
|
||||
key.type = cpu_to_le16(ktype);
|
||||
memcpy(&key.macAddr, mac, ETH_ALEN);
|
||||
if (keydata)
|
||||
memcpy(&key.key, keydata, keylen);
|
||||
|
||||
return carl9170_exec_cmd(ar, CARL9170_CMD_EKEY,
|
||||
sizeof(key), (u8 *)&key, 0, NULL);
|
||||
}
|
||||
|
||||
int carl9170_disable_key(struct ar9170 *ar, const u8 id)
|
||||
{
|
||||
struct carl9170_disable_key_cmd key = { };
|
||||
|
||||
key.user = cpu_to_le16(id);
|
||||
|
||||
return carl9170_exec_cmd(ar, CARL9170_CMD_DKEY,
|
||||
sizeof(key), (u8 *)&key, 0, NULL);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,567 @@
|
|||
/*
|
||||
* Shared Atheros AR9170 Header
|
||||
*
|
||||
* PHY register map
|
||||
*
|
||||
* Copyright (c) 2008-2009 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __CARL9170_SHARED_PHY_H
|
||||
#define __CARL9170_SHARED_PHY_H
|
||||
|
||||
#define AR9170_PHY_REG_BASE (0x1bc000 + 0x9800)
|
||||
#define AR9170_PHY_REG(_n) (AR9170_PHY_REG_BASE + \
|
||||
((_n) << 2))
|
||||
|
||||
#define AR9170_PHY_REG_TEST (AR9170_PHY_REG_BASE + 0x0000)
|
||||
#define AR9170_PHY_TEST_AGC_CLR 0x10000000
|
||||
#define AR9170_PHY_TEST_RFSILENT_BB 0x00002000
|
||||
|
||||
#define AR9170_PHY_REG_TURBO (AR9170_PHY_REG_BASE + 0x0004)
|
||||
#define AR9170_PHY_TURBO_FC_TURBO_MODE 0x00000001
|
||||
#define AR9170_PHY_TURBO_FC_TURBO_SHORT 0x00000002
|
||||
#define AR9170_PHY_TURBO_FC_DYN2040_EN 0x00000004
|
||||
#define AR9170_PHY_TURBO_FC_DYN2040_PRI_ONLY 0x00000008
|
||||
#define AR9170_PHY_TURBO_FC_DYN2040_PRI_CH 0x00000010
|
||||
/* For 25 MHz channel spacing -- not used but supported by hw */
|
||||
#define AR9170_PHY_TURBO_FC_DYN2040_EXT_CH 0x00000020
|
||||
#define AR9170_PHY_TURBO_FC_HT_EN 0x00000040
|
||||
#define AR9170_PHY_TURBO_FC_SHORT_GI_40 0x00000080
|
||||
#define AR9170_PHY_TURBO_FC_WALSH 0x00000100
|
||||
#define AR9170_PHY_TURBO_FC_SINGLE_HT_LTF1 0x00000200
|
||||
#define AR9170_PHY_TURBO_FC_ENABLE_DAC_FIFO 0x00000800
|
||||
|
||||
#define AR9170_PHY_REG_TEST2 (AR9170_PHY_REG_BASE + 0x0008)
|
||||
|
||||
#define AR9170_PHY_REG_TIMING2 (AR9170_PHY_REG_BASE + 0x0010)
|
||||
#define AR9170_PHY_TIMING2_USE_FORCE 0x00001000
|
||||
#define AR9170_PHY_TIMING2_FORCE 0x00000fff
|
||||
#define AR9170_PHY_TIMING2_FORCE_S 0
|
||||
|
||||
#define AR9170_PHY_REG_TIMING3 (AR9170_PHY_REG_BASE + 0x0014)
|
||||
#define AR9170_PHY_TIMING3_DSC_EXP 0x0001e000
|
||||
#define AR9170_PHY_TIMING3_DSC_EXP_S 13
|
||||
#define AR9170_PHY_TIMING3_DSC_MAN 0xfffe0000
|
||||
#define AR9170_PHY_TIMING3_DSC_MAN_S 17
|
||||
|
||||
#define AR9170_PHY_REG_CHIP_ID (AR9170_PHY_REG_BASE + 0x0018)
|
||||
#define AR9170_PHY_CHIP_ID_REV_0 0x80
|
||||
#define AR9170_PHY_CHIP_ID_REV_1 0x81
|
||||
#define AR9170_PHY_CHIP_ID_9160_REV_0 0xb0
|
||||
|
||||
#define AR9170_PHY_REG_ACTIVE (AR9170_PHY_REG_BASE + 0x001c)
|
||||
#define AR9170_PHY_ACTIVE_EN 0x00000001
|
||||
#define AR9170_PHY_ACTIVE_DIS 0x00000000
|
||||
|
||||
#define AR9170_PHY_REG_RF_CTL2 (AR9170_PHY_REG_BASE + 0x0024)
|
||||
#define AR9170_PHY_RF_CTL2_TX_END_DATA_START 0x000000ff
|
||||
#define AR9170_PHY_RF_CTL2_TX_END_DATA_START_S 0
|
||||
#define AR9170_PHY_RF_CTL2_TX_END_PA_ON 0x0000ff00
|
||||
#define AR9170_PHY_RF_CTL2_TX_END_PA_ON_S 8
|
||||
|
||||
#define AR9170_PHY_REG_RF_CTL3 (AR9170_PHY_REG_BASE + 0x0028)
|
||||
#define AR9170_PHY_RF_CTL3_TX_END_TO_A2_RX_ON 0x00ff0000
|
||||
#define AR9170_PHY_RF_CTL3_TX_END_TO_A2_RX_ON_S 16
|
||||
|
||||
#define AR9170_PHY_REG_ADC_CTL (AR9170_PHY_REG_BASE + 0x002c)
|
||||
#define AR9170_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003
|
||||
#define AR9170_PHY_ADC_CTL_OFF_INBUFGAIN_S 0
|
||||
#define AR9170_PHY_ADC_CTL_OFF_PWDDAC 0x00002000
|
||||
#define AR9170_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000
|
||||
#define AR9170_PHY_ADC_CTL_OFF_PWDADC 0x00008000
|
||||
#define AR9170_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000
|
||||
#define AR9170_PHY_ADC_CTL_ON_INBUFGAIN_S 16
|
||||
|
||||
#define AR9170_PHY_REG_ADC_SERIAL_CTL (AR9170_PHY_REG_BASE + 0x0030)
|
||||
#define AR9170_PHY_ADC_SCTL_SEL_INTERNAL_ADDAC 0x00000000
|
||||
#define AR9170_PHY_ADC_SCTL_SEL_EXTERNAL_RADIO 0x00000001
|
||||
|
||||
#define AR9170_PHY_REG_RF_CTL4 (AR9170_PHY_REG_BASE + 0x0034)
|
||||
#define AR9170_PHY_RF_CTL4_TX_END_XPAB_OFF 0xff000000
|
||||
#define AR9170_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24
|
||||
#define AR9170_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00ff0000
|
||||
#define AR9170_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16
|
||||
#define AR9170_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000ff00
|
||||
#define AR9170_PHY_RF_CTL4_FRAME_XPAB_ON_S 8
|
||||
#define AR9170_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000ff
|
||||
#define AR9170_PHY_RF_CTL4_FRAME_XPAA_ON_S 0
|
||||
|
||||
#define AR9170_PHY_REG_TSTDAC_CONST (AR9170_PHY_REG_BASE + 0x003c)
|
||||
|
||||
#define AR9170_PHY_REG_SETTLING (AR9170_PHY_REG_BASE + 0x0044)
|
||||
#define AR9170_PHY_SETTLING_SWITCH 0x00003f80
|
||||
#define AR9170_PHY_SETTLING_SWITCH_S 7
|
||||
|
||||
#define AR9170_PHY_REG_RXGAIN (AR9170_PHY_REG_BASE + 0x0048)
|
||||
#define AR9170_PHY_REG_RXGAIN_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2048)
|
||||
#define AR9170_PHY_RXGAIN_TXRX_ATTEN 0x0003f000
|
||||
#define AR9170_PHY_RXGAIN_TXRX_ATTEN_S 12
|
||||
#define AR9170_PHY_RXGAIN_TXRX_RF_MAX 0x007c0000
|
||||
#define AR9170_PHY_RXGAIN_TXRX_RF_MAX_S 18
|
||||
|
||||
#define AR9170_PHY_REG_DESIRED_SZ (AR9170_PHY_REG_BASE + 0x0050)
|
||||
#define AR9170_PHY_DESIRED_SZ_ADC 0x000000ff
|
||||
#define AR9170_PHY_DESIRED_SZ_ADC_S 0
|
||||
#define AR9170_PHY_DESIRED_SZ_PGA 0x0000ff00
|
||||
#define AR9170_PHY_DESIRED_SZ_PGA_S 8
|
||||
#define AR9170_PHY_DESIRED_SZ_TOT_DES 0x0ff00000
|
||||
#define AR9170_PHY_DESIRED_SZ_TOT_DES_S 20
|
||||
|
||||
#define AR9170_PHY_REG_FIND_SIG (AR9170_PHY_REG_BASE + 0x0058)
|
||||
#define AR9170_PHY_FIND_SIG_FIRSTEP 0x0003f000
|
||||
#define AR9170_PHY_FIND_SIG_FIRSTEP_S 12
|
||||
#define AR9170_PHY_FIND_SIG_FIRPWR 0x03fc0000
|
||||
#define AR9170_PHY_FIND_SIG_FIRPWR_S 18
|
||||
|
||||
#define AR9170_PHY_REG_AGC_CTL1 (AR9170_PHY_REG_BASE + 0x005c)
|
||||
#define AR9170_PHY_AGC_CTL1_COARSE_LOW 0x00007f80
|
||||
#define AR9170_PHY_AGC_CTL1_COARSE_LOW_S 7
|
||||
#define AR9170_PHY_AGC_CTL1_COARSE_HIGH 0x003f8000
|
||||
#define AR9170_PHY_AGC_CTL1_COARSE_HIGH_S 15
|
||||
|
||||
#define AR9170_PHY_REG_AGC_CONTROL (AR9170_PHY_REG_BASE + 0x0060)
|
||||
#define AR9170_PHY_AGC_CONTROL_CAL 0x00000001
|
||||
#define AR9170_PHY_AGC_CONTROL_NF 0x00000002
|
||||
#define AR9170_PHY_AGC_CONTROL_ENABLE_NF 0x00008000
|
||||
#define AR9170_PHY_AGC_CONTROL_FLTR_CAL 0x00010000
|
||||
#define AR9170_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000
|
||||
|
||||
#define AR9170_PHY_REG_CCA (AR9170_PHY_REG_BASE + 0x0064)
|
||||
#define AR9170_PHY_CCA_MINCCA_PWR 0x0ff80000
|
||||
#define AR9170_PHY_CCA_MINCCA_PWR_S 19
|
||||
#define AR9170_PHY_CCA_THRESH62 0x0007f000
|
||||
#define AR9170_PHY_CCA_THRESH62_S 12
|
||||
|
||||
#define AR9170_PHY_REG_SFCORR (AR9170_PHY_REG_BASE + 0x0068)
|
||||
#define AR9170_PHY_SFCORR_M2COUNT_THR 0x0000001f
|
||||
#define AR9170_PHY_SFCORR_M2COUNT_THR_S 0
|
||||
#define AR9170_PHY_SFCORR_M1_THRESH 0x00fe0000
|
||||
#define AR9170_PHY_SFCORR_M1_THRESH_S 17
|
||||
#define AR9170_PHY_SFCORR_M2_THRESH 0x7f000000
|
||||
#define AR9170_PHY_SFCORR_M2_THRESH_S 24
|
||||
|
||||
#define AR9170_PHY_REG_SFCORR_LOW (AR9170_PHY_REG_BASE + 0x006c)
|
||||
#define AR9170_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001
|
||||
#define AR9170_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003f00
|
||||
#define AR9170_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8
|
||||
#define AR9170_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001fc000
|
||||
#define AR9170_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14
|
||||
#define AR9170_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0fe00000
|
||||
#define AR9170_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21
|
||||
|
||||
#define AR9170_PHY_REG_SLEEP_CTR_CONTROL (AR9170_PHY_REG_BASE + 0x0070)
|
||||
#define AR9170_PHY_REG_SLEEP_CTR_LIMIT (AR9170_PHY_REG_BASE + 0x0074)
|
||||
#define AR9170_PHY_REG_SLEEP_SCAL (AR9170_PHY_REG_BASE + 0x0078)
|
||||
|
||||
#define AR9170_PHY_REG_PLL_CTL (AR9170_PHY_REG_BASE + 0x007c)
|
||||
#define AR9170_PHY_PLL_CTL_40 0xaa
|
||||
#define AR9170_PHY_PLL_CTL_40_5413 0x04
|
||||
#define AR9170_PHY_PLL_CTL_44 0xab
|
||||
#define AR9170_PHY_PLL_CTL_44_2133 0xeb
|
||||
#define AR9170_PHY_PLL_CTL_40_2133 0xea
|
||||
|
||||
#define AR9170_PHY_REG_BIN_MASK_1 (AR9170_PHY_REG_BASE + 0x0100)
|
||||
#define AR9170_PHY_REG_BIN_MASK_2 (AR9170_PHY_REG_BASE + 0x0104)
|
||||
#define AR9170_PHY_REG_BIN_MASK_3 (AR9170_PHY_REG_BASE + 0x0108)
|
||||
#define AR9170_PHY_REG_MASK_CTL (AR9170_PHY_REG_BASE + 0x010c)
|
||||
|
||||
/* analogue power on time (100ns) */
|
||||
#define AR9170_PHY_REG_RX_DELAY (AR9170_PHY_REG_BASE + 0x0114)
|
||||
#define AR9170_PHY_REG_SEARCH_START_DELAY (AR9170_PHY_REG_BASE + 0x0118)
|
||||
#define AR9170_PHY_RX_DELAY_DELAY 0x00003fff
|
||||
|
||||
#define AR9170_PHY_REG_TIMING_CTRL4(_i) (AR9170_PHY_REG_BASE + \
|
||||
(0x0120 + ((_i) << 12)))
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01f
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7e0
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xf000
|
||||
#define AR9170_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12
|
||||
#define AR9170_PHY_TIMING_CTRL4_DO_IQCAL 0x10000
|
||||
#define AR9170_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000
|
||||
#define AR9170_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000
|
||||
#define AR9170_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000
|
||||
#define AR9170_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000
|
||||
|
||||
#define AR9170_PHY_REG_TIMING5 (AR9170_PHY_REG_BASE + 0x0124)
|
||||
#define AR9170_PHY_TIMING5_CYCPWR_THR1 0x000000fe
|
||||
#define AR9170_PHY_TIMING5_CYCPWR_THR1_S 1
|
||||
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE1 (AR9170_PHY_REG_BASE + 0x0134)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE2 (AR9170_PHY_REG_BASE + 0x0138)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE_MAX (AR9170_PHY_REG_BASE + 0x013c)
|
||||
#define AR9170_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
|
||||
|
||||
#define AR9170_PHY_REG_FRAME_CTL (AR9170_PHY_REG_BASE + 0x0144)
|
||||
#define AR9170_PHY_FRAME_CTL_TX_CLIP 0x00000038
|
||||
#define AR9170_PHY_FRAME_CTL_TX_CLIP_S 3
|
||||
|
||||
#define AR9170_PHY_REG_SPUR_REG (AR9170_PHY_REG_BASE + 0x014c)
|
||||
#define AR9170_PHY_SPUR_REG_MASK_RATE_CNTL (0xff << 18)
|
||||
#define AR9170_PHY_SPUR_REG_MASK_RATE_CNTL_S 18
|
||||
#define AR9170_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000
|
||||
#define AR9170_PHY_SPUR_REG_MASK_RATE_SELECT (0xff << 9)
|
||||
#define AR9170_PHY_SPUR_REG_MASK_RATE_SELECT_S 9
|
||||
#define AR9170_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100
|
||||
#define AR9170_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7f
|
||||
#define AR9170_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0
|
||||
|
||||
#define AR9170_PHY_REG_RADAR_EXT (AR9170_PHY_REG_BASE + 0x0140)
|
||||
#define AR9170_PHY_RADAR_EXT_ENA 0x00004000
|
||||
|
||||
#define AR9170_PHY_REG_RADAR_0 (AR9170_PHY_REG_BASE + 0x0154)
|
||||
#define AR9170_PHY_RADAR_0_ENA 0x00000001
|
||||
#define AR9170_PHY_RADAR_0_FFT_ENA 0x80000000
|
||||
/* inband pulse threshold */
|
||||
#define AR9170_PHY_RADAR_0_INBAND 0x0000003e
|
||||
#define AR9170_PHY_RADAR_0_INBAND_S 1
|
||||
/* pulse RSSI threshold */
|
||||
#define AR9170_PHY_RADAR_0_PRSSI 0x00000fc0
|
||||
#define AR9170_PHY_RADAR_0_PRSSI_S 6
|
||||
/* pulse height threshold */
|
||||
#define AR9170_PHY_RADAR_0_HEIGHT 0x0003f000
|
||||
#define AR9170_PHY_RADAR_0_HEIGHT_S 12
|
||||
/* radar RSSI threshold */
|
||||
#define AR9170_PHY_RADAR_0_RRSSI 0x00fc0000
|
||||
#define AR9170_PHY_RADAR_0_RRSSI_S 18
|
||||
/* radar firepower threshold */
|
||||
#define AR9170_PHY_RADAR_0_FIRPWR 0x7f000000
|
||||
#define AR9170_PHY_RADAR_0_FIRPWR_S 24
|
||||
|
||||
#define AR9170_PHY_REG_RADAR_1 (AR9170_PHY_REG_BASE + 0x0158)
|
||||
#define AR9170_PHY_RADAR_1_RELPWR_ENA 0x00800000
|
||||
#define AR9170_PHY_RADAR_1_USE_FIR128 0x00400000
|
||||
#define AR9170_PHY_RADAR_1_RELPWR_THRESH 0x003f0000
|
||||
#define AR9170_PHY_RADAR_1_RELPWR_THRESH_S 16
|
||||
#define AR9170_PHY_RADAR_1_BLOCK_CHECK 0x00008000
|
||||
#define AR9170_PHY_RADAR_1_MAX_RRSSI 0x00004000
|
||||
#define AR9170_PHY_RADAR_1_RELSTEP_CHECK 0x00002000
|
||||
#define AR9170_PHY_RADAR_1_RELSTEP_THRESH 0x00001f00
|
||||
#define AR9170_PHY_RADAR_1_RELSTEP_THRESH_S 8
|
||||
#define AR9170_PHY_RADAR_1_MAXLEN 0x000000ff
|
||||
#define AR9170_PHY_RADAR_1_MAXLEN_S 0
|
||||
|
||||
#define AR9170_PHY_REG_SWITCH_CHAIN_0 (AR9170_PHY_REG_BASE + 0x0160)
|
||||
#define AR9170_PHY_REG_SWITCH_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2160)
|
||||
|
||||
#define AR9170_PHY_REG_SWITCH_COM (AR9170_PHY_REG_BASE + 0x0164)
|
||||
|
||||
#define AR9170_PHY_REG_CCA_THRESHOLD (AR9170_PHY_REG_BASE + 0x0168)
|
||||
|
||||
#define AR9170_PHY_REG_SIGMA_DELTA (AR9170_PHY_REG_BASE + 0x016c)
|
||||
#define AR9170_PHY_SIGMA_DELTA_ADC_SEL 0x00000003
|
||||
#define AR9170_PHY_SIGMA_DELTA_ADC_SEL_S 0
|
||||
#define AR9170_PHY_SIGMA_DELTA_FILT2 0x000000f8
|
||||
#define AR9170_PHY_SIGMA_DELTA_FILT2_S 3
|
||||
#define AR9170_PHY_SIGMA_DELTA_FILT1 0x00001f00
|
||||
#define AR9170_PHY_SIGMA_DELTA_FILT1_S 8
|
||||
#define AR9170_PHY_SIGMA_DELTA_ADC_CLIP 0x01ffe000
|
||||
#define AR9170_PHY_SIGMA_DELTA_ADC_CLIP_S 13
|
||||
|
||||
#define AR9170_PHY_REG_RESTART (AR9170_PHY_REG_BASE + 0x0170)
|
||||
#define AR9170_PHY_RESTART_DIV_GC 0x001c0000
|
||||
#define AR9170_PHY_RESTART_DIV_GC_S 18
|
||||
|
||||
#define AR9170_PHY_REG_RFBUS_REQ (AR9170_PHY_REG_BASE + 0x017c)
|
||||
#define AR9170_PHY_RFBUS_REQ_EN 0x00000001
|
||||
|
||||
#define AR9170_PHY_REG_TIMING7 (AR9170_PHY_REG_BASE + 0x0180)
|
||||
#define AR9170_PHY_REG_TIMING8 (AR9170_PHY_REG_BASE + 0x0184)
|
||||
#define AR9170_PHY_TIMING8_PILOT_MASK_2 0x000fffff
|
||||
#define AR9170_PHY_TIMING8_PILOT_MASK_2_S 0
|
||||
|
||||
#define AR9170_PHY_REG_BIN_MASK2_1 (AR9170_PHY_REG_BASE + 0x0188)
|
||||
#define AR9170_PHY_REG_BIN_MASK2_2 (AR9170_PHY_REG_BASE + 0x018c)
|
||||
#define AR9170_PHY_REG_BIN_MASK2_3 (AR9170_PHY_REG_BASE + 0x0190)
|
||||
#define AR9170_PHY_REG_BIN_MASK2_4 (AR9170_PHY_REG_BASE + 0x0194)
|
||||
#define AR9170_PHY_BIN_MASK2_4_MASK_4 0x00003fff
|
||||
#define AR9170_PHY_BIN_MASK2_4_MASK_4_S 0
|
||||
|
||||
#define AR9170_PHY_REG_TIMING9 (AR9170_PHY_REG_BASE + 0x0198)
|
||||
#define AR9170_PHY_REG_TIMING10 (AR9170_PHY_REG_BASE + 0x019c)
|
||||
#define AR9170_PHY_TIMING10_PILOT_MASK_2 0x000fffff
|
||||
#define AR9170_PHY_TIMING10_PILOT_MASK_2_S 0
|
||||
|
||||
#define AR9170_PHY_REG_TIMING11 (AR9170_PHY_REG_BASE + 0x01a0)
|
||||
#define AR9170_PHY_TIMING11_SPUR_DELTA_PHASE 0x000fffff
|
||||
#define AR9170_PHY_TIMING11_SPUR_DELTA_PHASE_S 0
|
||||
#define AR9170_PHY_TIMING11_SPUR_FREQ_SD 0x3ff00000
|
||||
#define AR9170_PHY_TIMING11_SPUR_FREQ_SD_S 20
|
||||
#define AR9170_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000
|
||||
#define AR9170_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000
|
||||
|
||||
#define AR9170_PHY_REG_RX_CHAINMASK (AR9170_PHY_REG_BASE + 0x01a4)
|
||||
#define AR9170_PHY_REG_NEW_ADC_DC_GAIN_CORR(_i) (AR9170_PHY_REG_BASE + \
|
||||
0x01b4 + ((_i) << 12))
|
||||
#define AR9170_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
|
||||
#define AR9170_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
|
||||
|
||||
#define AR9170_PHY_REG_MULTICHAIN_GAIN_CTL (AR9170_PHY_REG_BASE + 0x01ac)
|
||||
#define AR9170_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
|
||||
#define AR9170_PHY_9285_ANT_DIV_CTL 0x01000000
|
||||
#define AR9170_PHY_9285_ANT_DIV_CTL_S 24
|
||||
#define AR9170_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000
|
||||
#define AR9170_PHY_9285_ANT_DIV_ALT_LNACONF_S 25
|
||||
#define AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000
|
||||
#define AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27
|
||||
#define AR9170_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000
|
||||
#define AR9170_PHY_9285_ANT_DIV_ALT_GAINTB_S 29
|
||||
#define AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000
|
||||
#define AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30
|
||||
#define AR9170_PHY_9285_ANT_DIV_LNA1 2
|
||||
#define AR9170_PHY_9285_ANT_DIV_LNA2 1
|
||||
#define AR9170_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3
|
||||
#define AR9170_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
|
||||
#define AR9170_PHY_9285_ANT_DIV_GAINTB_0 0
|
||||
#define AR9170_PHY_9285_ANT_DIV_GAINTB_1 1
|
||||
|
||||
#define AR9170_PHY_REG_EXT_CCA0 (AR9170_PHY_REG_BASE + 0x01b8)
|
||||
#define AR9170_PHY_REG_EXT_CCA0_THRESH62 0x000000ff
|
||||
#define AR9170_PHY_REG_EXT_CCA0_THRESH62_S 0
|
||||
|
||||
#define AR9170_PHY_REG_EXT_CCA (AR9170_PHY_REG_BASE + 0x01bc)
|
||||
#define AR9170_PHY_EXT_CCA_CYCPWR_THR1 0x0000fe00
|
||||
#define AR9170_PHY_EXT_CCA_CYCPWR_THR1_S 9
|
||||
#define AR9170_PHY_EXT_CCA_THRESH62 0x007f0000
|
||||
#define AR9170_PHY_EXT_CCA_THRESH62_S 16
|
||||
#define AR9170_PHY_EXT_MINCCA_PWR 0xff800000
|
||||
#define AR9170_PHY_EXT_MINCCA_PWR_S 23
|
||||
|
||||
#define AR9170_PHY_REG_SFCORR_EXT (AR9170_PHY_REG_BASE + 0x01c0)
|
||||
#define AR9170_PHY_SFCORR_EXT_M1_THRESH 0x0000007f
|
||||
#define AR9170_PHY_SFCORR_EXT_M1_THRESH_S 0
|
||||
#define AR9170_PHY_SFCORR_EXT_M2_THRESH 0x00003f80
|
||||
#define AR9170_PHY_SFCORR_EXT_M2_THRESH_S 7
|
||||
#define AR9170_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001fc000
|
||||
#define AR9170_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
|
||||
#define AR9170_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0fe00000
|
||||
#define AR9170_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
|
||||
#define AR9170_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28
|
||||
|
||||
#define AR9170_PHY_REG_HALFGI (AR9170_PHY_REG_BASE + 0x01d0)
|
||||
#define AR9170_PHY_HALFGI_DSC_MAN 0x0007fff0
|
||||
#define AR9170_PHY_HALFGI_DSC_MAN_S 4
|
||||
#define AR9170_PHY_HALFGI_DSC_EXP 0x0000000f
|
||||
#define AR9170_PHY_HALFGI_DSC_EXP_S 0
|
||||
|
||||
#define AR9170_PHY_REG_CHANNEL_MASK_01_30 (AR9170_PHY_REG_BASE + 0x01d4)
|
||||
#define AR9170_PHY_REG_CHANNEL_MASK_31_60 (AR9170_PHY_REG_BASE + 0x01d8)
|
||||
|
||||
#define AR9170_PHY_REG_CHAN_INFO_MEMORY (AR9170_PHY_REG_BASE + 0x01dc)
|
||||
#define AR9170_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001
|
||||
|
||||
#define AR9170_PHY_REG_HEAVY_CLIP_ENABLE (AR9170_PHY_REG_BASE + 0x01e0)
|
||||
#define AR9170_PHY_REG_HEAVY_CLIP_FACTOR_RIFS (AR9170_PHY_REG_BASE + 0x01ec)
|
||||
#define AR9170_PHY_RIFS_INIT_DELAY 0x03ff0000
|
||||
|
||||
#define AR9170_PHY_REG_CALMODE (AR9170_PHY_REG_BASE + 0x01f0)
|
||||
#define AR9170_PHY_CALMODE_IQ 0x00000000
|
||||
#define AR9170_PHY_CALMODE_ADC_GAIN 0x00000001
|
||||
#define AR9170_PHY_CALMODE_ADC_DC_PER 0x00000002
|
||||
#define AR9170_PHY_CALMODE_ADC_DC_INIT 0x00000003
|
||||
|
||||
#define AR9170_PHY_REG_REFCLKDLY (AR9170_PHY_REG_BASE + 0x01f4)
|
||||
#define AR9170_PHY_REG_REFCLKPD (AR9170_PHY_REG_BASE + 0x01f8)
|
||||
|
||||
|
||||
#define AR9170_PHY_REG_CAL_MEAS_0(_i) (AR9170_PHY_REG_BASE + \
|
||||
0x0410 + ((_i) << 12))
|
||||
#define AR9170_PHY_REG_CAL_MEAS_1(_i) (AR9170_PHY_REG_BASE + \
|
||||
0x0414 \ + ((_i) << 12))
|
||||
#define AR9170_PHY_REG_CAL_MEAS_2(_i) (AR9170_PHY_REG_BASE + \
|
||||
0x0418 + ((_i) << 12))
|
||||
#define AR9170_PHY_REG_CAL_MEAS_3(_i) (AR9170_PHY_REG_BASE + \
|
||||
0x041c + ((_i) << 12))
|
||||
|
||||
#define AR9170_PHY_REG_CURRENT_RSSI (AR9170_PHY_REG_BASE + 0x041c)
|
||||
|
||||
#define AR9170_PHY_REG_RFBUS_GRANT (AR9170_PHY_REG_BASE + 0x0420)
|
||||
#define AR9170_PHY_RFBUS_GRANT_EN 0x00000001
|
||||
|
||||
#define AR9170_PHY_REG_CHAN_INFO_GAIN_DIFF (AR9170_PHY_REG_BASE + 0x04f4)
|
||||
#define AR9170_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
|
||||
|
||||
#define AR9170_PHY_REG_CHAN_INFO_GAIN (AR9170_PHY_REG_BASE + 0x04fc)
|
||||
|
||||
#define AR9170_PHY_REG_MODE (AR9170_PHY_REG_BASE + 0x0a00)
|
||||
#define AR9170_PHY_MODE_ASYNCFIFO 0x80
|
||||
#define AR9170_PHY_MODE_AR2133 0x08
|
||||
#define AR9170_PHY_MODE_AR5111 0x00
|
||||
#define AR9170_PHY_MODE_AR5112 0x08
|
||||
#define AR9170_PHY_MODE_DYNAMIC 0x04
|
||||
#define AR9170_PHY_MODE_RF2GHZ 0x02
|
||||
#define AR9170_PHY_MODE_RF5GHZ 0x00
|
||||
#define AR9170_PHY_MODE_CCK 0x01
|
||||
#define AR9170_PHY_MODE_OFDM 0x00
|
||||
#define AR9170_PHY_MODE_DYN_CCK_DISABLE 0x100
|
||||
|
||||
#define AR9170_PHY_REG_CCK_TX_CTRL (AR9170_PHY_REG_BASE + 0x0a04)
|
||||
#define AR9170_PHY_CCK_TX_CTRL_JAPAN 0x00000010
|
||||
#define AR9170_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000c
|
||||
#define AR9170_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2
|
||||
|
||||
#define AR9170_PHY_REG_CCK_DETECT (AR9170_PHY_REG_BASE + 0x0a08)
|
||||
#define AR9170_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003f
|
||||
#define AR9170_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0
|
||||
/* [12:6] settling time for antenna switch */
|
||||
#define AR9170_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001fc0
|
||||
#define AR9170_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6
|
||||
#define AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000
|
||||
#define AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13
|
||||
|
||||
#define AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2a0c)
|
||||
#define AR9170_PHY_REG_GAIN_2GHZ (AR9170_PHY_REG_BASE + 0x0a0c)
|
||||
#define AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00fc0000
|
||||
#define AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18
|
||||
#define AR9170_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003c00
|
||||
#define AR9170_PHY_GAIN_2GHZ_BSW_MARGIN_S 10
|
||||
#define AR9170_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001f
|
||||
#define AR9170_PHY_GAIN_2GHZ_BSW_ATTEN_S 0
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003e0000
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001f000
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000fc0
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN2_DB_S 6
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003f
|
||||
#define AR9170_PHY_GAIN_2GHZ_XATTEN1_DB_S 0
|
||||
|
||||
#define AR9170_PHY_REG_CCK_RXCTRL4 (AR9170_PHY_REG_BASE + 0x0a1c)
|
||||
#define AR9170_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01f80000
|
||||
#define AR9170_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19
|
||||
|
||||
#define AR9170_PHY_REG_DAG_CTRLCCK (AR9170_PHY_REG_BASE + 0x0a28)
|
||||
#define AR9170_REG_DAG_CTRLCCK_EN_RSSI_THR 0x00000200
|
||||
#define AR9170_REG_DAG_CTRLCCK_RSSI_THR 0x0001fc00
|
||||
#define AR9170_REG_DAG_CTRLCCK_RSSI_THR_S 10
|
||||
|
||||
#define AR9170_PHY_REG_FORCE_CLKEN_CCK (AR9170_PHY_REG_BASE + 0x0a2c)
|
||||
#define AR9170_FORCE_CLKEN_CCK_MRC_MUX 0x00000040
|
||||
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE3 (AR9170_PHY_REG_BASE + 0x0a34)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE4 (AR9170_PHY_REG_BASE + 0x0a38)
|
||||
|
||||
#define AR9170_PHY_REG_SCRM_SEQ_XR (AR9170_PHY_REG_BASE + 0x0a3c)
|
||||
#define AR9170_PHY_REG_HEADER_DETECT_XR (AR9170_PHY_REG_BASE + 0x0a40)
|
||||
#define AR9170_PHY_REG_CHIRP_DETECTED_XR (AR9170_PHY_REG_BASE + 0x0a44)
|
||||
#define AR9170_PHY_REG_BLUETOOTH (AR9170_PHY_REG_BASE + 0x0a54)
|
||||
|
||||
#define AR9170_PHY_REG_TPCRG1 (AR9170_PHY_REG_BASE + 0x0a58)
|
||||
#define AR9170_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000
|
||||
#define AR9170_PHY_TPCRG1_NUM_PD_GAIN_S 14
|
||||
#define AR9170_PHY_TPCRG1_PD_GAIN_1 0x00030000
|
||||
#define AR9170_PHY_TPCRG1_PD_GAIN_1_S 16
|
||||
#define AR9170_PHY_TPCRG1_PD_GAIN_2 0x000c0000
|
||||
#define AR9170_PHY_TPCRG1_PD_GAIN_2_S 18
|
||||
#define AR9170_PHY_TPCRG1_PD_GAIN_3 0x00300000
|
||||
#define AR9170_PHY_TPCRG1_PD_GAIN_3_S 20
|
||||
#define AR9170_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000
|
||||
#define AR9170_PHY_TPCRG1_PD_CAL_ENABLE_S 22
|
||||
|
||||
#define AR9170_PHY_REG_TX_PWRCTRL4 (AR9170_PHY_REG_BASE + 0x0a64)
|
||||
#define AR9170_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001
|
||||
#define AR9170_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0
|
||||
#define AR9170_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001fe
|
||||
#define AR9170_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1
|
||||
|
||||
#define AR9170_PHY_REG_ANALOG_SWAP (AR9170_PHY_REG_BASE + 0x0a68)
|
||||
#define AR9170_PHY_ANALOG_SWAP_AB 0x0001
|
||||
#define AR9170_PHY_ANALOG_SWAP_ALT_CHAIN 0x00000040
|
||||
|
||||
#define AR9170_PHY_REG_TPCRG5 (AR9170_PHY_REG_BASE + 0x0a6c)
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000f
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003f0
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000fc00
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003f0000
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0fc00000
|
||||
#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22
|
||||
|
||||
#define AR9170_PHY_REG_TX_PWRCTRL6_0 (AR9170_PHY_REG_BASE + 0x0a70)
|
||||
#define AR9170_PHY_REG_TX_PWRCTRL6_1 (AR9170_PHY_REG_BASE + 0x1a70)
|
||||
#define AR9170_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000
|
||||
#define AR9170_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24
|
||||
|
||||
#define AR9170_PHY_REG_TX_PWRCTRL7 (AR9170_PHY_REG_BASE + 0x0a74)
|
||||
#define AR9170_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01f80000
|
||||
#define AR9170_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19
|
||||
|
||||
#define AR9170_PHY_REG_TX_PWRCTRL9 (AR9170_PHY_REG_BASE + 0x0a7c)
|
||||
#define AR9170_PHY_TX_DESIRED_SCALE_CCK 0x00007c00
|
||||
#define AR9170_PHY_TX_DESIRED_SCALE_CCK_S 10
|
||||
#define AR9170_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000
|
||||
#define AR9170_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
|
||||
|
||||
#define AR9170_PHY_REG_TX_GAIN_TBL1 (AR9170_PHY_REG_BASE + 0x0b00)
|
||||
#define AR9170_PHY_TX_GAIN 0x0007f000
|
||||
#define AR9170_PHY_TX_GAIN_S 12
|
||||
|
||||
/* Carrier leak calibration control, do it after AGC calibration */
|
||||
#define AR9170_PHY_REG_CL_CAL_CTL (AR9170_PHY_REG_BASE + 0x0b58)
|
||||
#define AR9170_PHY_CL_CAL_ENABLE 0x00000002
|
||||
#define AR9170_PHY_CL_CAL_PARALLEL_CAL_ENABLE 0x00000001
|
||||
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE5 (AR9170_PHY_REG_BASE + 0x0b8c)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE6 (AR9170_PHY_REG_BASE + 0x0b90)
|
||||
|
||||
#define AR9170_PHY_REG_CH0_TX_PWRCTRL11 (AR9170_PHY_REG_BASE + 0x0b98)
|
||||
#define AR9170_PHY_REG_CH1_TX_PWRCTRL11 (AR9170_PHY_REG_BASE + 0x1b98)
|
||||
#define AR9170_PHY_TX_CHX_PWRCTRL_OLPC_TEMP_COMP 0x0000fc00
|
||||
#define AR9170_PHY_TX_CHX_PWRCTRL_OLPC_TEMP_COMP_S 10
|
||||
|
||||
#define AR9170_PHY_REG_CAL_CHAINMASK (AR9170_PHY_REG_BASE + 0x0b9c)
|
||||
#define AR9170_PHY_REG_VIT_MASK2_M_46_61 (AR9170_PHY_REG_BASE + 0x0ba0)
|
||||
#define AR9170_PHY_REG_MASK2_M_31_45 (AR9170_PHY_REG_BASE + 0x0ba4)
|
||||
#define AR9170_PHY_REG_MASK2_M_16_30 (AR9170_PHY_REG_BASE + 0x0ba8)
|
||||
#define AR9170_PHY_REG_MASK2_M_00_15 (AR9170_PHY_REG_BASE + 0x0bac)
|
||||
#define AR9170_PHY_REG_PILOT_MASK_01_30 (AR9170_PHY_REG_BASE + 0x0bb0)
|
||||
#define AR9170_PHY_REG_PILOT_MASK_31_60 (AR9170_PHY_REG_BASE + 0x0bb4)
|
||||
#define AR9170_PHY_REG_MASK2_P_15_01 (AR9170_PHY_REG_BASE + 0x0bb8)
|
||||
#define AR9170_PHY_REG_MASK2_P_30_16 (AR9170_PHY_REG_BASE + 0x0bbc)
|
||||
#define AR9170_PHY_REG_MASK2_P_45_31 (AR9170_PHY_REG_BASE + 0x0bc0)
|
||||
#define AR9170_PHY_REG_MASK2_P_61_45 (AR9170_PHY_REG_BASE + 0x0bc4)
|
||||
#define AR9170_PHY_REG_POWER_TX_SUB (AR9170_PHY_REG_BASE + 0x0bc8)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE7 (AR9170_PHY_REG_BASE + 0x0bcc)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE8 (AR9170_PHY_REG_BASE + 0x0bd0)
|
||||
#define AR9170_PHY_REG_POWER_TX_RATE9 (AR9170_PHY_REG_BASE + 0x0bd4)
|
||||
#define AR9170_PHY_REG_XPA_CFG (AR9170_PHY_REG_BASE + 0x0bd8)
|
||||
#define AR9170_PHY_FORCE_XPA_CFG 0x000000001
|
||||
#define AR9170_PHY_FORCE_XPA_CFG_S 0
|
||||
|
||||
#define AR9170_PHY_REG_CH1_CCA (AR9170_PHY_REG_BASE + 0x1064)
|
||||
#define AR9170_PHY_CH1_MINCCA_PWR 0x0ff80000
|
||||
#define AR9170_PHY_CH1_MINCCA_PWR_S 19
|
||||
|
||||
#define AR9170_PHY_REG_CH2_CCA (AR9170_PHY_REG_BASE + 0x2064)
|
||||
#define AR9170_PHY_CH2_MINCCA_PWR 0x0ff80000
|
||||
#define AR9170_PHY_CH2_MINCCA_PWR_S 19
|
||||
|
||||
#define AR9170_PHY_REG_CH1_EXT_CCA (AR9170_PHY_REG_BASE + 0x11bc)
|
||||
#define AR9170_PHY_CH1_EXT_MINCCA_PWR 0xff800000
|
||||
#define AR9170_PHY_CH1_EXT_MINCCA_PWR_S 23
|
||||
|
||||
#define AR9170_PHY_REG_CH2_EXT_CCA (AR9170_PHY_REG_BASE + 0x21bc)
|
||||
#define AR9170_PHY_CH2_EXT_MINCCA_PWR 0xff800000
|
||||
#define AR9170_PHY_CH2_EXT_MINCCA_PWR_S 23
|
||||
|
||||
#define REDUCE_CHAIN_0 0x00000050
|
||||
#define REDUCE_CHAIN_1 0x00000051
|
||||
|
||||
#endif /* __CARL9170_SHARED_PHY_H */
|
|
@ -0,0 +1,909 @@
|
|||
/*
|
||||
* Atheros CARL9170 driver
|
||||
*
|
||||
* 802.11 & command trap routines
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "carl9170.h"
|
||||
#include "hw.h"
|
||||
#include "cmd.h"
|
||||
|
||||
static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
|
||||
{
|
||||
bool restart = false;
|
||||
enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON;
|
||||
|
||||
if (len > 3) {
|
||||
if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
|
||||
ar->fw.err_counter++;
|
||||
if (ar->fw.err_counter > 3) {
|
||||
restart = true;
|
||||
reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) {
|
||||
ar->fw.bug_counter++;
|
||||
restart = true;
|
||||
reason = CARL9170_RR_FATAL_FIRMWARE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf);
|
||||
|
||||
if (restart)
|
||||
carl9170_restart(ar, reason);
|
||||
}
|
||||
|
||||
static void carl9170_handle_ps(struct ar9170 *ar, struct carl9170_rsp *rsp)
|
||||
{
|
||||
u32 ps;
|
||||
bool new_ps;
|
||||
|
||||
ps = le32_to_cpu(rsp->psm.state);
|
||||
|
||||
new_ps = (ps & CARL9170_PSM_COUNTER) != CARL9170_PSM_WAKE;
|
||||
if (ar->ps.state != new_ps) {
|
||||
if (!new_ps) {
|
||||
ar->ps.sleep_ms = jiffies_to_msecs(jiffies -
|
||||
ar->ps.last_action);
|
||||
}
|
||||
|
||||
ar->ps.last_action = jiffies;
|
||||
|
||||
ar->ps.state = new_ps;
|
||||
}
|
||||
}
|
||||
|
||||
static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq)
|
||||
{
|
||||
if (ar->cmd_seq < -1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Initialize Counter
|
||||
*/
|
||||
if (ar->cmd_seq < 0)
|
||||
ar->cmd_seq = seq;
|
||||
|
||||
/*
|
||||
* The sequence is strictly monotonic increasing and it never skips!
|
||||
*
|
||||
* Therefore we can safely assume that whenever we received an
|
||||
* unexpected sequence we have lost some valuable data.
|
||||
*/
|
||||
if (seq != ar->cmd_seq) {
|
||||
int count;
|
||||
|
||||
count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs;
|
||||
|
||||
wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! "
|
||||
"w:%d g:%d\n", count, ar->cmd_seq, seq);
|
||||
|
||||
carl9170_restart(ar, CARL9170_RR_LOST_RSP);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
|
||||
{
|
||||
/*
|
||||
* Some commands may have a variable response length
|
||||
* and we cannot predict the correct length in advance.
|
||||
* So we only check if we provided enough space for the data.
|
||||
*/
|
||||
if (unlikely(ar->readlen != (len - 4))) {
|
||||
dev_warn(&ar->udev->dev, "received invalid command response:"
|
||||
"got %d, instead of %d\n", len - 4, ar->readlen);
|
||||
print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET,
|
||||
ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f);
|
||||
print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET,
|
||||
buffer, len);
|
||||
/*
|
||||
* Do not complete. The command times out,
|
||||
* and we get a stack trace from there.
|
||||
*/
|
||||
carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
|
||||
}
|
||||
|
||||
spin_lock(&ar->cmd_lock);
|
||||
if (ar->readbuf) {
|
||||
if (len >= 4)
|
||||
memcpy(ar->readbuf, buffer + 4, len - 4);
|
||||
|
||||
ar->readbuf = NULL;
|
||||
}
|
||||
complete(&ar->cmd_wait);
|
||||
spin_unlock(&ar->cmd_lock);
|
||||
}
|
||||
|
||||
void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
|
||||
{
|
||||
struct carl9170_rsp *cmd = (void *) buf;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
if (carl9170_check_sequence(ar, cmd->hdr.seq))
|
||||
return;
|
||||
|
||||
if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) {
|
||||
if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG))
|
||||
carl9170_cmd_callback(ar, len, buf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->hdr.len != (len - 4))) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "FW: received over-/under"
|
||||
"sized event %x (%d, but should be %d).\n",
|
||||
cmd->hdr.cmd, cmd->hdr.len, len - 4);
|
||||
|
||||
print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE,
|
||||
buf, len);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* hardware event handlers */
|
||||
switch (cmd->hdr.cmd) {
|
||||
case CARL9170_RSP_PRETBTT:
|
||||
/* pre-TBTT event */
|
||||
rcu_read_lock();
|
||||
vif = carl9170_get_main_vif(ar);
|
||||
|
||||
if (!vif) {
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
carl9170_handle_ps(ar, cmd);
|
||||
break;
|
||||
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
carl9170_update_beacon(ar, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case CARL9170_RSP_TXCOMP:
|
||||
/* TX status notification */
|
||||
carl9170_tx_process_status(ar, cmd);
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_BEACON_CONFIG:
|
||||
/*
|
||||
* (IBSS) beacon send notification
|
||||
* bytes: 04 c2 XX YY B4 B3 B2 B1
|
||||
*
|
||||
* XX always 80
|
||||
* YY always 00
|
||||
* B1-B4 "should" be the number of send out beacons.
|
||||
*/
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_ATIM:
|
||||
/* End of Atim Window */
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_WATCHDOG:
|
||||
/* Watchdog Interrupt */
|
||||
carl9170_restart(ar, CARL9170_RR_WATCHDOG);
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_TEXT:
|
||||
/* firmware debug */
|
||||
carl9170_dbg_message(ar, (char *)buf + 4, len - 4);
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_HEXDUMP:
|
||||
wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4);
|
||||
print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE,
|
||||
(char *)buf + 4, len - 4);
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_RADAR:
|
||||
if (!net_ratelimit())
|
||||
break;
|
||||
|
||||
wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
|
||||
"incident to linux-wireless@vger.kernel.org !\n");
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_GPIO:
|
||||
#ifdef CONFIG_CARL9170_WPC
|
||||
if (ar->wps.pbc) {
|
||||
bool state = !!(cmd->gpio.gpio & cpu_to_le32(
|
||||
AR9170_GPIO_PORT_WPS_BUTTON_PRESSED));
|
||||
|
||||
if (state != ar->wps.pbc_state) {
|
||||
ar->wps.pbc_state = state;
|
||||
input_report_key(ar->wps.pbc, KEY_WPS_BUTTON,
|
||||
state);
|
||||
input_sync(ar->wps.pbc);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_CARL9170_WPC */
|
||||
break;
|
||||
|
||||
case CARL9170_RSP_BOOT:
|
||||
complete(&ar->fw_boot_wait);
|
||||
break;
|
||||
|
||||
default:
|
||||
wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n",
|
||||
cmd->hdr.cmd);
|
||||
print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int carl9170_rx_mac_status(struct ar9170 *ar,
|
||||
struct ar9170_rx_head *head, struct ar9170_rx_macstatus *mac,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
u8 error, decrypt;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
|
||||
BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
|
||||
|
||||
error = mac->error;
|
||||
|
||||
if (error & AR9170_RX_ERROR_WRONG_RA) {
|
||||
if (!ar->sniffer_enabled)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (error & AR9170_RX_ERROR_PLCP) {
|
||||
if (!(ar->filter_state & FIF_PLCPFAIL))
|
||||
return -EINVAL;
|
||||
|
||||
status->flag |= RX_FLAG_FAILED_PLCP_CRC;
|
||||
}
|
||||
|
||||
if (error & AR9170_RX_ERROR_FCS) {
|
||||
ar->tx_fcs_errors++;
|
||||
|
||||
if (!(ar->filter_state & FIF_FCSFAIL))
|
||||
return -EINVAL;
|
||||
|
||||
status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
}
|
||||
|
||||
decrypt = ar9170_get_decrypt_type(mac);
|
||||
if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
|
||||
decrypt != AR9170_ENC_ALG_NONE) {
|
||||
if ((decrypt == AR9170_ENC_ALG_TKIP) &&
|
||||
(error & AR9170_RX_ERROR_MMIC))
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
}
|
||||
|
||||
if (error & AR9170_RX_ERROR_DECRYPT && !ar->sniffer_enabled)
|
||||
return -ENODATA;
|
||||
|
||||
error &= ~(AR9170_RX_ERROR_MMIC |
|
||||
AR9170_RX_ERROR_FCS |
|
||||
AR9170_RX_ERROR_WRONG_RA |
|
||||
AR9170_RX_ERROR_DECRYPT |
|
||||
AR9170_RX_ERROR_PLCP);
|
||||
|
||||
/* drop any other error frames */
|
||||
if (unlikely(error)) {
|
||||
/* TODO: update netdevice's RX dropped/errors statistics */
|
||||
|
||||
if (net_ratelimit())
|
||||
wiphy_dbg(ar->hw->wiphy, "received frame with "
|
||||
"suspicious error code (%#x).\n", error);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chan = ar->channel;
|
||||
if (chan) {
|
||||
status->band = chan->band;
|
||||
status->freq = chan->center_freq;
|
||||
}
|
||||
|
||||
switch (mac->status & AR9170_RX_STATUS_MODULATION) {
|
||||
case AR9170_RX_STATUS_MODULATION_CCK:
|
||||
if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
|
||||
status->flag |= RX_FLAG_SHORTPRE;
|
||||
switch (head->plcp[0]) {
|
||||
case AR9170_RX_PHY_RATE_CCK_1M:
|
||||
status->rate_idx = 0;
|
||||
break;
|
||||
case AR9170_RX_PHY_RATE_CCK_2M:
|
||||
status->rate_idx = 1;
|
||||
break;
|
||||
case AR9170_RX_PHY_RATE_CCK_5M:
|
||||
status->rate_idx = 2;
|
||||
break;
|
||||
case AR9170_RX_PHY_RATE_CCK_11M:
|
||||
status->rate_idx = 3;
|
||||
break;
|
||||
default:
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "invalid plcp cck "
|
||||
"rate (%x).\n", head->plcp[0]);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
case AR9170_RX_STATUS_MODULATION_OFDM:
|
||||
switch (head->plcp[0] & 0xf) {
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_6M:
|
||||
status->rate_idx = 0;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_9M:
|
||||
status->rate_idx = 1;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_12M:
|
||||
status->rate_idx = 2;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_18M:
|
||||
status->rate_idx = 3;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_24M:
|
||||
status->rate_idx = 4;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_36M:
|
||||
status->rate_idx = 5;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_48M:
|
||||
status->rate_idx = 6;
|
||||
break;
|
||||
case AR9170_TXRX_PHY_RATE_OFDM_54M:
|
||||
status->rate_idx = 7;
|
||||
break;
|
||||
default:
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "invalid plcp ofdm "
|
||||
"rate (%x).\n", head->plcp[0]);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
if (status->band == IEEE80211_BAND_2GHZ)
|
||||
status->rate_idx += 4;
|
||||
break;
|
||||
|
||||
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[3] & 0x7f);
|
||||
status->flag |= RX_FLAG_HT;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void carl9170_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;
|
||||
}
|
||||
|
||||
static struct sk_buff *carl9170_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;
|
||||
}
|
||||
|
||||
static u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)data;
|
||||
u8 *pos, *end;
|
||||
|
||||
pos = (u8 *)mgmt->u.beacon.variable;
|
||||
end = data + len;
|
||||
while (pos < end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
return NULL;
|
||||
|
||||
if (pos[0] == ie)
|
||||
return pos;
|
||||
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
*
|
||||
* The firmware is in charge of waking up the device just before
|
||||
* the AP is expected to transmit the next beacon.
|
||||
*
|
||||
* This leaves the driver with the important task of deciding when
|
||||
* to set the PHY back to bed again.
|
||||
*/
|
||||
static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *) data;
|
||||
struct ieee80211_tim_ie *tim_ie;
|
||||
u8 *tim;
|
||||
u8 tim_len;
|
||||
bool cam;
|
||||
|
||||
if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
|
||||
return;
|
||||
|
||||
/* check if this really is a beacon */
|
||||
if (!ieee80211_is_beacon(hdr->frame_control))
|
||||
return;
|
||||
|
||||
/* min. beacon length + FCS_LEN */
|
||||
if (len <= 40 + FCS_LEN)
|
||||
return;
|
||||
|
||||
/* and only beacons from the associated BSSID, please */
|
||||
if (compare_ether_addr(hdr->addr3, ar->common.curbssid) ||
|
||||
!ar->common.curaid)
|
||||
return;
|
||||
|
||||
ar->ps.last_beacon = jiffies;
|
||||
|
||||
tim = carl9170_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
|
||||
if (!tim)
|
||||
return;
|
||||
|
||||
if (tim[1] < sizeof(*tim_ie))
|
||||
return;
|
||||
|
||||
tim_len = tim[1];
|
||||
tim_ie = (struct ieee80211_tim_ie *) &tim[2];
|
||||
|
||||
if (!WARN_ON_ONCE(!ar->hw->conf.ps_dtim_period))
|
||||
ar->ps.dtim_counter = (tim_ie->dtim_count - 1) %
|
||||
ar->hw->conf.ps_dtim_period;
|
||||
|
||||
/* Check whenever the PHY can be turned off again. */
|
||||
|
||||
/* 1. What about buffered unicast traffic for our AID? */
|
||||
cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid);
|
||||
|
||||
/* 2. Maybe the AP wants to send multicast/broadcast data? */
|
||||
cam = !!(tim_ie->bitmap_ctrl & 0x01);
|
||||
|
||||
if (!cam) {
|
||||
/* back to low-power land. */
|
||||
ar->ps.off_override &= ~PS_OFF_BCN;
|
||||
carl9170_ps_check(ar);
|
||||
} else {
|
||||
/* force CAM */
|
||||
ar->ps.off_override |= PS_OFF_BCN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 carl9170_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 (!IS_STARTED(ar))
|
||||
return;
|
||||
|
||||
if (unlikely(len < sizeof(*mac))) {
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
mpdu_len = len - sizeof(*mac);
|
||||
|
||||
mac = (void *)(buf + mpdu_len);
|
||||
if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) {
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mac->status & AR9170_RX_STATUS_MPDU) {
|
||||
case AR9170_RX_STATUS_MPDU_FIRST:
|
||||
/* Aggregated MPDUs start with an PLCP header */
|
||||
if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
|
||||
head = (void *) buf;
|
||||
|
||||
/*
|
||||
* The PLCP header needs to be cached for the
|
||||
* following MIDDLE + LAST A-MPDU packets.
|
||||
*
|
||||
* So, if you are wondering why all frames seem
|
||||
* to share a common RX status information,
|
||||
* then you have the answer right here...
|
||||
*/
|
||||
memcpy(&ar->rx_plcp, (void *) buf,
|
||||
sizeof(struct ar9170_rx_head));
|
||||
|
||||
mpdu_len -= sizeof(struct ar9170_rx_head);
|
||||
buf += sizeof(struct ar9170_rx_head);
|
||||
|
||||
ar->rx_has_plcp = true;
|
||||
} else {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "plcp info "
|
||||
"is clipped.\n");
|
||||
}
|
||||
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_LAST:
|
||||
/*
|
||||
* The last frame of an A-MPDU has an extra tail
|
||||
* which does contain the phy status of the whole
|
||||
* aggregate.
|
||||
*/
|
||||
|
||||
if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
|
||||
mpdu_len -= sizeof(struct ar9170_rx_phystatus);
|
||||
phy = (void *)(buf + mpdu_len);
|
||||
} else {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "frame tail "
|
||||
"is clipped.\n");
|
||||
}
|
||||
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_MIDDLE:
|
||||
/* These are just data + mac status */
|
||||
if (unlikely(!ar->rx_has_plcp)) {
|
||||
if (!net_ratelimit())
|
||||
return;
|
||||
|
||||
wiphy_err(ar->hw->wiphy, "rx stream does not start "
|
||||
"with a first_mpdu frame tag.\n");
|
||||
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
head = &ar->rx_plcp;
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_SINGLE:
|
||||
/* single mpdu has both: 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;
|
||||
}
|
||||
|
||||
/* FC + DU + RA + FCS */
|
||||
if (unlikely(mpdu_len < (2 + 2 + 6 + FCS_LEN))) {
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) {
|
||||
ar->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (phy)
|
||||
carl9170_rx_phy_status(ar, phy, &status);
|
||||
|
||||
carl9170_ps_beacon(ar, buf, mpdu_len);
|
||||
|
||||
skb = carl9170_rx_copy_data(buf, mpdu_len);
|
||||
if (likely(skb)) {
|
||||
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
|
||||
ieee80211_rx(ar->hw, skb);
|
||||
} else {
|
||||
ar->rx_dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf,
|
||||
const unsigned int resplen)
|
||||
{
|
||||
struct carl9170_rsp *cmd;
|
||||
int i = 0;
|
||||
|
||||
while (i < resplen) {
|
||||
cmd = (void *) &respbuf[i];
|
||||
|
||||
i += cmd->hdr.len + 4;
|
||||
if (unlikely(i > resplen))
|
||||
break;
|
||||
|
||||
carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4);
|
||||
}
|
||||
|
||||
if (unlikely(i != resplen)) {
|
||||
if (!net_ratelimit())
|
||||
return;
|
||||
|
||||
wiphy_err(ar->hw->wiphy, "malformed firmware trap:\n");
|
||||
print_hex_dump_bytes("rxcmd:", DUMP_PREFIX_OFFSET,
|
||||
respbuf, resplen);
|
||||
}
|
||||
}
|
||||
|
||||
static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
/* weird thing, but this is the same in the original driver */
|
||||
while (len > 2 && i < 12 && buf[0] == 0xff && buf[1] == 0xff) {
|
||||
i += 2;
|
||||
len -= 2;
|
||||
buf += 2;
|
||||
}
|
||||
|
||||
if (unlikely(len < 4))
|
||||
return;
|
||||
|
||||
/* found the 6 * 0xffff marker? */
|
||||
if (i == 12)
|
||||
carl9170_rx_untie_cmds(ar, buf, len);
|
||||
else
|
||||
carl9170_handle_mpdu(ar, buf, len);
|
||||
}
|
||||
|
||||
static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
|
||||
{
|
||||
unsigned int tlen, wlen = 0, clen = 0;
|
||||
struct ar9170_stream *rx_stream;
|
||||
u8 *tbuf;
|
||||
|
||||
tbuf = buf;
|
||||
tlen = len;
|
||||
|
||||
while (tlen >= 4) {
|
||||
rx_stream = (void *) tbuf;
|
||||
clen = le16_to_cpu(rx_stream->length);
|
||||
wlen = ALIGN(clen, 4);
|
||||
|
||||
/* check if this is stream has a valid tag.*/
|
||||
if (rx_stream->tag != cpu_to_le16(AR9170_RX_STREAM_TAG)) {
|
||||
/*
|
||||
* 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 not "short read". */
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy,
|
||||
"missing tag!\n");
|
||||
}
|
||||
|
||||
__carl9170_rx(ar, tbuf, tlen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ar->rx_failover_missing > tlen) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy,
|
||||
"possible multi "
|
||||
"stream corruption!\n");
|
||||
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 carl9170_rx_stream call!
|
||||
*
|
||||
* termination is guranteed, even when the
|
||||
* combined frame also have an element with
|
||||
* a bad tag.
|
||||
*/
|
||||
|
||||
ar->rx_failover_missing = 0;
|
||||
carl9170_rx_stream(ar, ar->rx_failover->data,
|
||||
ar->rx_failover->len);
|
||||
|
||||
skb_reset_tail_pointer(ar->rx_failover);
|
||||
skb_trim(ar->rx_failover, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if stream is clipped */
|
||||
if (wlen > tlen - 4) {
|
||||
if (ar->rx_failover_missing) {
|
||||
/* TODO: handle double stream corruption. */
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "double rx "
|
||||
"stream corruption!\n");
|
||||
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;
|
||||
}
|
||||
__carl9170_rx(ar, rx_stream->payload, clen);
|
||||
|
||||
tbuf += wlen + 4;
|
||||
tlen -= wlen + 4;
|
||||
}
|
||||
|
||||
if (tlen) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed "
|
||||
"data left in rx stream!\n", tlen);
|
||||
}
|
||||
|
||||
goto err_telluser;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_telluser:
|
||||
wiphy_err(ar->hw->wiphy, "damaged RX stream data [want:%d, "
|
||||
"data:%d, rx:%d, pending:%d ]\n", 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,
|
||||
buf, len);
|
||||
|
||||
wiphy_err(ar->hw->wiphy, "please check your hardware and cables, if "
|
||||
"you see this message frequently.\n");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len)
|
||||
{
|
||||
if (ar->fw.rx_stream)
|
||||
carl9170_rx_stream(ar, buf, len);
|
||||
else
|
||||
__carl9170_rx(ar, buf, len);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
#ifndef __CARL9170_SHARED_VERSION_H
|
||||
#define __CARL9170_SHARED_VERSION_H
|
||||
#define CARL9170FW_VERSION_YEAR 10
|
||||
#define CARL9170FW_VERSION_MONTH 8
|
||||
#define CARL9170FW_VERSION_DAY 30
|
||||
#define CARL9170FW_VERSION_GIT "1.8.8.1"
|
||||
#endif /* __CARL9170_SHARED_VERSION_H */
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* Shared Atheros AR9170 Header
|
||||
*
|
||||
* RX/TX meta descriptor format
|
||||
*
|
||||
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* Copyright (c) 2007-2008 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.
|
||||
*/
|
||||
|
||||
#ifndef __CARL9170_SHARED_WLAN_H
|
||||
#define __CARL9170_SHARED_WLAN_H
|
||||
|
||||
#include "fwcmd.h"
|
||||
|
||||
#define AR9170_RX_PHY_RATE_CCK_1M 0x0a
|
||||
#define AR9170_RX_PHY_RATE_CCK_2M 0x14
|
||||
#define AR9170_RX_PHY_RATE_CCK_5M 0x37
|
||||
#define AR9170_RX_PHY_RATE_CCK_11M 0x6e
|
||||
|
||||
#define AR9170_ENC_ALG_NONE 0x0
|
||||
#define AR9170_ENC_ALG_WEP64 0x1
|
||||
#define AR9170_ENC_ALG_TKIP 0x2
|
||||
#define AR9170_ENC_ALG_AESCCMP 0x4
|
||||
#define AR9170_ENC_ALG_WEP128 0x5
|
||||
#define AR9170_ENC_ALG_WEP256 0x6
|
||||
#define AR9170_ENC_ALG_CENC 0x7
|
||||
|
||||
#define AR9170_RX_ENC_SOFTWARE 0x8
|
||||
|
||||
#define AR9170_RX_STATUS_MODULATION 0x03
|
||||
#define AR9170_RX_STATUS_MODULATION_S 0
|
||||
#define AR9170_RX_STATUS_MODULATION_CCK 0x00
|
||||
#define AR9170_RX_STATUS_MODULATION_OFDM 0x01
|
||||
#define AR9170_RX_STATUS_MODULATION_HT 0x02
|
||||
#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03
|
||||
|
||||
/* depends on modulation */
|
||||
#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08
|
||||
#define AR9170_RX_STATUS_GREENFIELD 0x08
|
||||
|
||||
#define AR9170_RX_STATUS_MPDU 0x30
|
||||
#define AR9170_RX_STATUS_MPDU_S 4
|
||||
#define AR9170_RX_STATUS_MPDU_SINGLE 0x00
|
||||
#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
|
||||
#define AR9170_RX_ERROR_DECRYPT 0x04
|
||||
#define AR9170_RX_ERROR_FCS 0x08
|
||||
#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
|
||||
|
||||
/* these are either-or */
|
||||
#define AR9170_TX_MAC_PROT_RTS 0x0001
|
||||
#define AR9170_TX_MAC_PROT_CTS 0x0002
|
||||
#define AR9170_TX_MAC_PROT 0x0003
|
||||
|
||||
#define AR9170_TX_MAC_NO_ACK 0x0004
|
||||
/* if unset, MAC will only do SIFS space before frame */
|
||||
#define AR9170_TX_MAC_BACKOFF 0x0008
|
||||
#define AR9170_TX_MAC_BURST 0x0010
|
||||
#define AR9170_TX_MAC_AGGR 0x0020
|
||||
|
||||
/* encryption is a two-bit field */
|
||||
#define AR9170_TX_MAC_ENCR_NONE 0x0000
|
||||
#define AR9170_TX_MAC_ENCR_RC4 0x0040
|
||||
#define AR9170_TX_MAC_ENCR_CENC 0x0080
|
||||
#define AR9170_TX_MAC_ENCR_AES 0x00c0
|
||||
|
||||
#define AR9170_TX_MAC_MMIC 0x0100
|
||||
#define AR9170_TX_MAC_HW_DURATION 0x0200
|
||||
#define AR9170_TX_MAC_QOS_S 10
|
||||
#define AR9170_TX_MAC_QOS 0x0c00
|
||||
#define AR9170_TX_MAC_DISABLE_TXOP 0x1000
|
||||
#define AR9170_TX_MAC_TXOP_RIFS 0x2000
|
||||
#define AR9170_TX_MAC_IMM_BA 0x4000
|
||||
|
||||
/* either-or */
|
||||
#define AR9170_TX_PHY_MOD_CCK 0x00000000
|
||||
#define AR9170_TX_PHY_MOD_OFDM 0x00000001
|
||||
#define AR9170_TX_PHY_MOD_HT 0x00000002
|
||||
|
||||
/* depends on modulation */
|
||||
#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004
|
||||
#define AR9170_TX_PHY_GREENFIELD 0x00000004
|
||||
|
||||
#define AR9170_TX_PHY_BW_S 3
|
||||
#define AR9170_TX_PHY_BW (3 << AR9170_TX_PHY_BW_SHIFT)
|
||||
#define AR9170_TX_PHY_BW_20MHZ 0
|
||||
#define AR9170_TX_PHY_BW_40MHZ 2
|
||||
#define AR9170_TX_PHY_BW_40MHZ_DUP 3
|
||||
|
||||
#define AR9170_TX_PHY_TX_HEAVY_CLIP_S 6
|
||||
#define AR9170_TX_PHY_TX_HEAVY_CLIP (7 << \
|
||||
AR9170_TX_PHY_TX_HEAVY_CLIP_S)
|
||||
|
||||
#define AR9170_TX_PHY_TX_PWR_S 9
|
||||
#define AR9170_TX_PHY_TX_PWR (0x3f << \
|
||||
AR9170_TX_PHY_TX_PWR_S)
|
||||
|
||||
#define AR9170_TX_PHY_TXCHAIN_S 15
|
||||
#define AR9170_TX_PHY_TXCHAIN (7 << \
|
||||
AR9170_TX_PHY_TXCHAIN_S)
|
||||
#define AR9170_TX_PHY_TXCHAIN_1 1
|
||||
/* use for cck, ofdm 6/9/12/18/24 and HT if capable */
|
||||
#define AR9170_TX_PHY_TXCHAIN_2 5
|
||||
|
||||
#define AR9170_TX_PHY_MCS_S 18
|
||||
#define AR9170_TX_PHY_MCS (0x7f << \
|
||||
AR9170_TX_PHY_MCS_S)
|
||||
|
||||
#define AR9170_TX_PHY_RATE_CCK_1M 0x0
|
||||
#define AR9170_TX_PHY_RATE_CCK_2M 0x1
|
||||
#define AR9170_TX_PHY_RATE_CCK_5M 0x2
|
||||
#define AR9170_TX_PHY_RATE_CCK_11M 0x3
|
||||
|
||||
/* same as AR9170_RX_PHY_RATE */
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_6M 0xb
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_9M 0xf
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_12M 0xa
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_18M 0xe
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_24M 0x9
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_36M 0xd
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_48M 0x8
|
||||
#define AR9170_TXRX_PHY_RATE_OFDM_54M 0xc
|
||||
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS0 0x0
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS1 0x1
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS2 0x2
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS3 0x3
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS4 0x4
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS5 0x5
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS6 0x6
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS7 0x7
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS8 0x8
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS9 0x9
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS10 0xa
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS11 0xb
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS12 0xc
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS13 0xd
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS14 0xe
|
||||
#define AR9170_TXRX_PHY_RATE_HT_MCS15 0xf
|
||||
|
||||
#define AR9170_TX_PHY_SHORT_GI 0x80000000
|
||||
|
||||
#ifdef __CARL9170FW__
|
||||
struct ar9170_tx_hw_mac_control {
|
||||
union {
|
||||
struct {
|
||||
/*
|
||||
* Beware of compiler bugs in all gcc pre 4.4!
|
||||
*/
|
||||
|
||||
u8 erp_prot:2;
|
||||
u8 no_ack:1;
|
||||
u8 backoff:1;
|
||||
u8 burst:1;
|
||||
u8 ampdu:1;
|
||||
|
||||
u8 enc_mode:2;
|
||||
|
||||
u8 hw_mmic:1;
|
||||
u8 hw_duration:1;
|
||||
|
||||
u8 qos_queue:2;
|
||||
|
||||
u8 disable_txop:1;
|
||||
u8 txop_rifs:1;
|
||||
|
||||
u8 ba_end:1;
|
||||
u8 probe:1;
|
||||
} __packed;
|
||||
|
||||
__le16 set;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_tx_hw_phy_control {
|
||||
union {
|
||||
struct {
|
||||
/*
|
||||
* Beware of compiler bugs in all gcc pre 4.4!
|
||||
*/
|
||||
|
||||
u8 modulation:2;
|
||||
u8 preamble:1;
|
||||
u8 bandwidth:2;
|
||||
u8:1;
|
||||
u8 heavy_clip:3;
|
||||
u8 tx_power:6;
|
||||
u8 chains:3;
|
||||
u8 mcs:7;
|
||||
u8:6;
|
||||
u8 short_gi:1;
|
||||
} __packed;
|
||||
|
||||
__le32 set;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_tx_rate_info {
|
||||
u8 tries:3;
|
||||
u8 erp_prot:2;
|
||||
u8 ampdu:1;
|
||||
u8 free:2; /* free for use (e.g.:RIFS/TXOP/AMPDU) */
|
||||
} __packed;
|
||||
|
||||
struct carl9170_tx_superdesc {
|
||||
__le16 len;
|
||||
u8 rix;
|
||||
u8 cnt;
|
||||
u8 cookie;
|
||||
u8 ampdu_density:3;
|
||||
u8 ampdu_factor:2;
|
||||
u8 ampdu_commit_density:1;
|
||||
u8 ampdu_commit_factor:1;
|
||||
u8 ampdu_unused_bit:1;
|
||||
u8 queue:2;
|
||||
u8 reserved:1;
|
||||
u8 vif_id:3;
|
||||
u8 fill_in_tsf:1;
|
||||
u8 cab:1;
|
||||
u8 padding2;
|
||||
struct ar9170_tx_rate_info ri[CARL9170_TX_MAX_RATES];
|
||||
struct ar9170_tx_hw_phy_control rr[CARL9170_TX_MAX_RETRY_RATES];
|
||||
} __packed;
|
||||
|
||||
struct ar9170_tx_hwdesc {
|
||||
__le16 length;
|
||||
struct ar9170_tx_hw_mac_control mac;
|
||||
struct ar9170_tx_hw_phy_control phy;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_tx_frame {
|
||||
struct ar9170_tx_hwdesc hdr;
|
||||
|
||||
union {
|
||||
struct ieee80211_hdr i3e;
|
||||
u8 payload[0];
|
||||
} data;
|
||||
} __packed;
|
||||
|
||||
struct carl9170_tx_superframe {
|
||||
struct carl9170_tx_superdesc s;
|
||||
struct ar9170_tx_frame f;
|
||||
} __packed;
|
||||
|
||||
#endif /* __CARL9170FW__ */
|
||||
|
||||
struct _ar9170_tx_hwdesc {
|
||||
__le16 length;
|
||||
__le16 mac_control;
|
||||
__le32 phy_control;
|
||||
} __packed;
|
||||
|
||||
#define CARL9170_TX_SUPER_AMPDU_DENSITY_S 0
|
||||
#define CARL9170_TX_SUPER_AMPDU_DENSITY 0x7
|
||||
#define CARL9170_TX_SUPER_AMPDU_FACTOR 0x18
|
||||
#define CARL9170_TX_SUPER_AMPDU_FACTOR_S 3
|
||||
#define CARL9170_TX_SUPER_AMPDU_COMMIT_DENSITY 0x20
|
||||
#define CARL9170_TX_SUPER_AMPDU_COMMIT_DENSITY_S 5
|
||||
#define CARL9170_TX_SUPER_AMPDU_COMMIT_FACTOR 0x40
|
||||
#define CARL9170_TX_SUPER_AMPDU_COMMIT_FACTOR_S 6
|
||||
|
||||
#define CARL9170_TX_SUPER_MISC_QUEUE 0x3
|
||||
#define CARL9170_TX_SUPER_MISC_QUEUE_S 0
|
||||
#define CARL9170_TX_SUPER_MISC_VIF_ID 0x38
|
||||
#define CARL9170_TX_SUPER_MISC_VIF_ID_S 3
|
||||
#define CARL9170_TX_SUPER_MISC_FILL_IN_TSF 0x40
|
||||
#define CARL9170_TX_SUPER_MISC_CAB 0x80
|
||||
|
||||
#define CARL9170_TX_SUPER_RI_TRIES 0x7
|
||||
#define CARL9170_TX_SUPER_RI_TRIES_S 0
|
||||
#define CARL9170_TX_SUPER_RI_ERP_PROT 0x18
|
||||
#define CARL9170_TX_SUPER_RI_ERP_PROT_S 3
|
||||
#define CARL9170_TX_SUPER_RI_AMPDU 0x20
|
||||
#define CARL9170_TX_SUPER_RI_AMPDU_S 5
|
||||
|
||||
struct _carl9170_tx_superdesc {
|
||||
__le16 len;
|
||||
u8 rix;
|
||||
u8 cnt;
|
||||
u8 cookie;
|
||||
u8 ampdu_settings;
|
||||
u8 misc;
|
||||
u8 padding;
|
||||
u8 ri[CARL9170_TX_MAX_RATES];
|
||||
__le32 rr[CARL9170_TX_MAX_RETRY_RATES];
|
||||
} __packed;
|
||||
|
||||
struct _carl9170_tx_superframe {
|
||||
struct _carl9170_tx_superdesc s;
|
||||
struct _ar9170_tx_hwdesc f;
|
||||
u8 frame_data[0];
|
||||
} __packed;
|
||||
|
||||
#define CARL9170_TX_SUPERDESC_LEN 24
|
||||
#define AR9170_TX_HWDESC_LEN 8
|
||||
#define AR9170_TX_SUPERFRAME_LEN (CARL9170_TX_HWDESC_LEN + \
|
||||
AR9170_TX_SUPERDESC_LEN)
|
||||
|
||||
struct ar9170_rx_head {
|
||||
u8 plcp[12];
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_phystatus {
|
||||
union {
|
||||
struct {
|
||||
u8 rssi_ant0, rssi_ant1, rssi_ant2,
|
||||
rssi_ant0x, rssi_ant1x, rssi_ant2x,
|
||||
rssi_combined;
|
||||
} __packed;
|
||||
u8 rssi[7];
|
||||
} __packed;
|
||||
|
||||
u8 evm_stream0[6], evm_stream1[6];
|
||||
u8 phy_err;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_macstatus {
|
||||
u8 SAidx, DAidx;
|
||||
u8 error;
|
||||
u8 status;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_frame_single {
|
||||
struct ar9170_rx_head phy_head;
|
||||
struct ieee80211_hdr i3e;
|
||||
struct ar9170_rx_phystatus phy_tail;
|
||||
struct ar9170_rx_macstatus macstatus;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_frame_head {
|
||||
struct ar9170_rx_head phy_head;
|
||||
struct ieee80211_hdr i3e;
|
||||
struct ar9170_rx_macstatus macstatus;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_frame_middle {
|
||||
struct ieee80211_hdr i3e;
|
||||
struct ar9170_rx_macstatus macstatus;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_frame_tail {
|
||||
struct ieee80211_hdr i3e;
|
||||
struct ar9170_rx_phystatus phy_tail;
|
||||
struct ar9170_rx_macstatus macstatus;
|
||||
} __packed;
|
||||
|
||||
struct ar9170_rx_frame {
|
||||
union {
|
||||
struct ar9170_rx_frame_single single;
|
||||
struct ar9170_rx_frame_head head;
|
||||
struct ar9170_rx_frame_middle middle;
|
||||
struct ar9170_rx_frame_tail tail;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
|
||||
{
|
||||
return (t->SAidx & 0xc0) >> 4 |
|
||||
(t->DAidx & 0xc0) >> 6;
|
||||
}
|
||||
|
||||
enum ar9170_txq {
|
||||
AR9170_TXQ_BE,
|
||||
|
||||
AR9170_TXQ_VI,
|
||||
AR9170_TXQ_VO,
|
||||
AR9170_TXQ_BK,
|
||||
|
||||
__AR9170_NUM_TXQ,
|
||||
};
|
||||
|
||||
static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 };
|
||||
|
||||
#define AR9170_TXQ_DEPTH 32
|
||||
|
||||
#endif /* __CARL9170_SHARED_WLAN_H */
|
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* Copyright (c) 2009 Atheros Communications Inc.
|
||||
* Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
|
||||
*
|
||||
* 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 <asm/unaligned.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "ath.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define REG_READ (common->ops->read)
|
||||
#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg)
|
||||
|
||||
#define IEEE80211_WEP_NKID 4 /* number of key ids */
|
||||
|
||||
/************************/
|
||||
/* Key Cache Management */
|
||||
/************************/
|
||||
|
||||
bool ath_hw_keyreset(struct ath_common *common, u16 entry)
|
||||
{
|
||||
u32 keyType;
|
||||
void *ah = common->ah;
|
||||
|
||||
if (entry >= common->keymax) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"keychache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
|
||||
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
|
||||
|
||||
if (keyType == AR_KEYTABLE_TYPE_TKIP) {
|
||||
u16 micentry = entry + 64;
|
||||
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_hw_keyreset);
|
||||
|
||||
bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
|
||||
{
|
||||
u32 macHi, macLo;
|
||||
u32 unicast_flag = AR_KEYTABLE_VALID;
|
||||
void *ah = common->ah;
|
||||
|
||||
if (entry >= common->keymax) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"keychache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mac != NULL) {
|
||||
/*
|
||||
* AR_KEYTABLE_VALID indicates that the address is a unicast
|
||||
* address, which must match the transmitter address for
|
||||
* decrypting frames.
|
||||
* Not setting this bit allows the hardware to use the key
|
||||
* for multicast frame decryption.
|
||||
*/
|
||||
if (mac[0] & 0x01)
|
||||
unicast_flag = 0;
|
||||
|
||||
macHi = (mac[5] << 8) | mac[4];
|
||||
macLo = (mac[3] << 24) |
|
||||
(mac[2] << 16) |
|
||||
(mac[1] << 8) |
|
||||
mac[0];
|
||||
macLo >>= 1;
|
||||
macLo |= (macHi & 1) << 31;
|
||||
macHi >>= 1;
|
||||
} else {
|
||||
macLo = macHi = 0;
|
||||
}
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
|
||||
const struct ath_keyval *k,
|
||||
const u8 *mac)
|
||||
{
|
||||
void *ah = common->ah;
|
||||
u32 key0, key1, key2, key3, key4;
|
||||
u32 keyType;
|
||||
|
||||
if (entry >= common->keymax) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"keycache entry %u out of range\n", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (k->kv_type) {
|
||||
case ATH_CIPHER_AES_OCB:
|
||||
keyType = AR_KEYTABLE_TYPE_AES;
|
||||
break;
|
||||
case ATH_CIPHER_AES_CCM:
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"AES-CCM not supported by this mac rev\n");
|
||||
return false;
|
||||
}
|
||||
keyType = AR_KEYTABLE_TYPE_CCM;
|
||||
break;
|
||||
case ATH_CIPHER_TKIP:
|
||||
keyType = AR_KEYTABLE_TYPE_TKIP;
|
||||
if (entry + 64 >= common->keymax) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"entry %u inappropriate for TKIP\n", entry);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ATH_CIPHER_WEP:
|
||||
if (k->kv_len < WLAN_KEY_LEN_WEP40) {
|
||||
ath_print(common, ATH_DBG_ANY,
|
||||
"WEP key length %u too small\n", k->kv_len);
|
||||
return false;
|
||||
}
|
||||
if (k->kv_len <= WLAN_KEY_LEN_WEP40)
|
||||
keyType = AR_KEYTABLE_TYPE_40;
|
||||
else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
|
||||
keyType = AR_KEYTABLE_TYPE_104;
|
||||
else
|
||||
keyType = AR_KEYTABLE_TYPE_128;
|
||||
break;
|
||||
case ATH_CIPHER_CLR:
|
||||
keyType = AR_KEYTABLE_TYPE_CLR;
|
||||
break;
|
||||
default:
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"cipher %u not supported\n", k->kv_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
key0 = get_unaligned_le32(k->kv_val + 0);
|
||||
key1 = get_unaligned_le16(k->kv_val + 4);
|
||||
key2 = get_unaligned_le32(k->kv_val + 6);
|
||||
key3 = get_unaligned_le16(k->kv_val + 10);
|
||||
key4 = get_unaligned_le32(k->kv_val + 12);
|
||||
if (k->kv_len <= WLAN_KEY_LEN_WEP104)
|
||||
key4 &= 0xff;
|
||||
|
||||
/*
|
||||
* Note: Key cache registers access special memory area that requires
|
||||
* two 32-bit writes to actually update the values in the internal
|
||||
* memory. Consequently, the exact order and pairs used here must be
|
||||
* maintained.
|
||||
*/
|
||||
|
||||
if (keyType == AR_KEYTABLE_TYPE_TKIP) {
|
||||
u16 micentry = entry + 64;
|
||||
|
||||
/*
|
||||
* Write inverted key[47:0] first to avoid Michael MIC errors
|
||||
* on frames that could be sent or received at the same time.
|
||||
* The correct key will be written in the end once everything
|
||||
* else is ready.
|
||||
*/
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
|
||||
|
||||
/* Write key[95:48] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
|
||||
|
||||
/* Write key[127:96] and key type */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
|
||||
|
||||
/* Write MAC address for the entry */
|
||||
(void) ath_hw_keysetmac(common, entry, mac);
|
||||
|
||||
if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
|
||||
/*
|
||||
* TKIP uses two key cache entries:
|
||||
* Michael MIC TX/RX keys in the same key cache entry
|
||||
* (idx = main index + 64):
|
||||
* key0 [31:0] = RX key [31:0]
|
||||
* key1 [15:0] = TX key [31:16]
|
||||
* key1 [31:16] = reserved
|
||||
* key2 [31:0] = RX key [63:32]
|
||||
* key3 [15:0] = TX key [15:0]
|
||||
* key3 [31:16] = reserved
|
||||
* key4 [31:0] = TX key [63:32]
|
||||
*/
|
||||
u32 mic0, mic1, mic2, mic3, mic4;
|
||||
|
||||
mic0 = get_unaligned_le32(k->kv_mic + 0);
|
||||
mic2 = get_unaligned_le32(k->kv_mic + 4);
|
||||
mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
|
||||
mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
|
||||
mic4 = get_unaligned_le32(k->kv_txmic + 4);
|
||||
|
||||
/* Write RX[31:0] and TX[31:16] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
|
||||
|
||||
/* Write RX[63:32] and TX[15:0] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
|
||||
|
||||
/* Write TX[63:32] and keyType(reserved) */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
|
||||
AR_KEYTABLE_TYPE_CLR);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* TKIP uses four key cache entries (two for group
|
||||
* keys):
|
||||
* Michael MIC TX/RX keys are in different key cache
|
||||
* entries (idx = main index + 64 for TX and
|
||||
* main index + 32 + 96 for RX):
|
||||
* key0 [31:0] = TX/RX MIC key [31:0]
|
||||
* key1 [31:0] = reserved
|
||||
* key2 [31:0] = TX/RX MIC key [63:32]
|
||||
* key3 [31:0] = reserved
|
||||
* key4 [31:0] = reserved
|
||||
*
|
||||
* Upper layer code will call this function separately
|
||||
* for TX and RX keys when these registers offsets are
|
||||
* used.
|
||||
*/
|
||||
u32 mic0, mic2;
|
||||
|
||||
mic0 = get_unaligned_le32(k->kv_mic + 0);
|
||||
mic2 = get_unaligned_le32(k->kv_mic + 4);
|
||||
|
||||
/* Write MIC key[31:0] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
|
||||
|
||||
/* Write MIC key[63:32] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
|
||||
|
||||
/* Write TX[63:32] and keyType(reserved) */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
|
||||
AR_KEYTABLE_TYPE_CLR);
|
||||
}
|
||||
|
||||
/* MAC address registers are reserved for the MIC entry */
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
|
||||
|
||||
/*
|
||||
* Write the correct (un-inverted) key[47:0] last to enable
|
||||
* TKIP now that all other registers are set with correct
|
||||
* values.
|
||||
*/
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
|
||||
} else {
|
||||
/* Write key[47:0] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
|
||||
|
||||
/* Write key[95:48] */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
|
||||
|
||||
/* Write key[127:96] and key type */
|
||||
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
|
||||
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
|
||||
|
||||
/* Write MAC address for the entry */
|
||||
(void) ath_hw_keysetmac(common, entry, mac);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
|
||||
struct ath_keyval *hk, const u8 *addr,
|
||||
bool authenticator)
|
||||
{
|
||||
const u8 *key_rxmic;
|
||||
const u8 *key_txmic;
|
||||
|
||||
key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
|
||||
key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
|
||||
|
||||
if (addr == NULL) {
|
||||
/*
|
||||
* Group key installation - only two key cache entries are used
|
||||
* regardless of splitmic capability since group key is only
|
||||
* used either for TX or RX.
|
||||
*/
|
||||
if (authenticator) {
|
||||
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
|
||||
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
|
||||
} else {
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
|
||||
}
|
||||
return ath_hw_set_keycache_entry(common, keyix, hk, addr);
|
||||
}
|
||||
if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
|
||||
/* TX and RX keys share the same key cache entry. */
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
|
||||
return ath_hw_set_keycache_entry(common, keyix, hk, addr);
|
||||
}
|
||||
|
||||
/* Separate key cache entries for TX and RX */
|
||||
|
||||
/* TX key goes at first index, RX key at +32. */
|
||||
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
|
||||
if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) {
|
||||
/* TX MIC entry failed. No need to proceed further */
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Setting TX MIC Key Failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
/* XXX delete tx key on failure? */
|
||||
return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr);
|
||||
}
|
||||
|
||||
static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
|
||||
if (test_bit(i, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap))
|
||||
continue; /* At least one part of TKIP key allocated */
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) &&
|
||||
(test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
continue; /* At least one part of TKIP key allocated */
|
||||
|
||||
/* Found a free slot for a TKIP key */
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ath_reserve_key_cache_slot(struct ath_common *common,
|
||||
u32 cipher)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
return ath_reserve_key_cache_slot_tkip(common);
|
||||
|
||||
/* First, try to find slots that would not be available for TKIP. */
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
|
||||
if (!test_bit(i, common->keymap) &&
|
||||
(test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
return i;
|
||||
if (!test_bit(i + 32, common->keymap) &&
|
||||
(test_bit(i, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
return i + 32;
|
||||
if (!test_bit(i + 64, common->keymap) &&
|
||||
(test_bit(i , common->keymap) ||
|
||||
test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64 + 32, common->keymap)))
|
||||
return i + 64;
|
||||
if (!test_bit(i + 64 + 32, common->keymap) &&
|
||||
(test_bit(i, common->keymap) ||
|
||||
test_bit(i + 32, common->keymap) ||
|
||||
test_bit(i + 64, common->keymap)))
|
||||
return i + 64 + 32;
|
||||
}
|
||||
} else {
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
|
||||
if (!test_bit(i, common->keymap) &&
|
||||
test_bit(i + 64, common->keymap))
|
||||
return i;
|
||||
if (test_bit(i, common->keymap) &&
|
||||
!test_bit(i + 64, common->keymap))
|
||||
return i + 64;
|
||||
}
|
||||
}
|
||||
|
||||
/* No partially used TKIP slots, pick any available slot */
|
||||
for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
|
||||
/* Do not allow slots that could be needed for TKIP group keys
|
||||
* to be used. This limitation could be removed if we know that
|
||||
* TKIP will not be used. */
|
||||
if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
|
||||
continue;
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
|
||||
if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
|
||||
continue;
|
||||
if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!test_bit(i, common->keymap))
|
||||
return i; /* Found a free slot for a key */
|
||||
}
|
||||
|
||||
/* No free slot found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure encryption in the HW.
|
||||
*/
|
||||
int ath_key_config(struct ath_common *common,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ath_keyval hk;
|
||||
const u8 *mac = NULL;
|
||||
u8 gmac[ETH_ALEN];
|
||||
int ret = 0;
|
||||
int idx;
|
||||
|
||||
memset(&hk, 0, sizeof(hk));
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
hk.kv_type = ATH_CIPHER_WEP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
hk.kv_type = ATH_CIPHER_TKIP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
hk.kv_type = ATH_CIPHER_AES_CCM;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
hk.kv_len = key->keylen;
|
||||
memcpy(hk.kv_val, key->key, key->keylen);
|
||||
|
||||
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
memcpy(gmac, vif->addr, ETH_ALEN);
|
||||
gmac[0] |= 0x01;
|
||||
mac = gmac;
|
||||
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!sta) {
|
||||
idx = key->keyidx;
|
||||
break;
|
||||
}
|
||||
memcpy(gmac, sta->addr, ETH_ALEN);
|
||||
gmac[0] |= 0x01;
|
||||
mac = gmac;
|
||||
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||
break;
|
||||
default:
|
||||
idx = key->keyidx;
|
||||
break;
|
||||
}
|
||||
} else if (key->keyidx) {
|
||||
if (WARN_ON(!sta))
|
||||
return -EOPNOTSUPP;
|
||||
mac = sta->addr;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_AP) {
|
||||
/* Only keyidx 0 should be used with unicast key, but
|
||||
* allow this for client mode for now. */
|
||||
idx = key->keyidx;
|
||||
} else
|
||||
return -EIO;
|
||||
} else {
|
||||
if (WARN_ON(!sta))
|
||||
return -EOPNOTSUPP;
|
||||
mac = sta->addr;
|
||||
|
||||
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||
}
|
||||
|
||||
if (idx < 0)
|
||||
return -ENOSPC; /* no free key cache entries */
|
||||
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
|
||||
vif->type == NL80211_IFTYPE_AP);
|
||||
else
|
||||
ret = ath_hw_set_keycache_entry(common, idx, &hk, mac);
|
||||
|
||||
if (!ret)
|
||||
return -EIO;
|
||||
|
||||
set_bit(idx, common->keymap);
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||
set_bit(idx + 64, common->keymap);
|
||||
set_bit(idx, common->tkip_keymap);
|
||||
set_bit(idx + 64, common->tkip_keymap);
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
|
||||
set_bit(idx + 32, common->keymap);
|
||||
set_bit(idx + 64 + 32, common->keymap);
|
||||
set_bit(idx + 32, common->tkip_keymap);
|
||||
set_bit(idx + 64 + 32, common->tkip_keymap);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_key_config);
|
||||
|
||||
/*
|
||||
* Delete Key.
|
||||
*/
|
||||
void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
|
||||
{
|
||||
ath_hw_keyreset(common, key->hw_key_idx);
|
||||
if (key->hw_key_idx < IEEE80211_WEP_NKID)
|
||||
return;
|
||||
|
||||
clear_bit(key->hw_key_idx, common->keymap);
|
||||
if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
|
||||
return;
|
||||
|
||||
clear_bit(key->hw_key_idx + 64, common->keymap);
|
||||
|
||||
clear_bit(key->hw_key_idx, common->tkip_keymap);
|
||||
clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
|
||||
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
|
||||
ath_hw_keyreset(common, key->hw_key_idx + 32);
|
||||
clear_bit(key->hw_key_idx + 32, common->keymap);
|
||||
clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
|
||||
|
||||
clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
|
||||
clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath_key_delete);
|
|
@ -24,4 +24,27 @@
|
|||
#define AR_BSSMSKL 0x80e0
|
||||
#define AR_BSSMSKU 0x80e4
|
||||
|
||||
#define AR_KEYTABLE_0 0x8800
|
||||
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
|
||||
#define AR_KEY_CACHE_SIZE 128
|
||||
#define AR_RSVD_KEYTABLE_ENTRIES 4
|
||||
#define AR_KEY_TYPE 0x00000007
|
||||
#define AR_KEYTABLE_TYPE_40 0x00000000
|
||||
#define AR_KEYTABLE_TYPE_104 0x00000001
|
||||
#define AR_KEYTABLE_TYPE_128 0x00000003
|
||||
#define AR_KEYTABLE_TYPE_TKIP 0x00000004
|
||||
#define AR_KEYTABLE_TYPE_AES 0x00000005
|
||||
#define AR_KEYTABLE_TYPE_CCM 0x00000006
|
||||
#define AR_KEYTABLE_TYPE_CLR 0x00000007
|
||||
#define AR_KEYTABLE_ANT 0x00000008
|
||||
#define AR_KEYTABLE_VALID 0x00008000
|
||||
#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0)
|
||||
#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4)
|
||||
#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8)
|
||||
#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12)
|
||||
#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16)
|
||||
#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20)
|
||||
#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24)
|
||||
#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28)
|
||||
|
||||
#endif /* ATH_REGISTERS_H */
|
||||
|
|
|
@ -223,6 +223,7 @@ static struct iwl_lib_ops iwl1000_lib = {
|
|||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.recover_from_tx_stall = iwl_bg_monitor_recover,
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
|
|
|
@ -295,7 +295,7 @@ extern const struct iwl_channel_info *iwl3945_get_channel_info(
|
|||
extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate);
|
||||
|
||||
/* scanning */
|
||||
void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
|
||||
/* Requires full declaration of iwl_priv before including */
|
||||
#include "iwl-io.h"
|
||||
|
|
|
@ -2289,6 +2289,7 @@ static struct iwl_lib_ops iwl4965_lib = {
|
|||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.recover_from_tx_stall = iwl_bg_monitor_recover,
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
|
|
|
@ -404,6 +404,7 @@ static struct iwl_lib_ops iwl5000_lib = {
|
|||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.recover_from_tx_stall = iwl_bg_monitor_recover,
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
|
@ -474,6 +475,8 @@ static struct iwl_lib_ops iwl5150_lib = {
|
|||
.rx_stats_read = iwl_ucode_rx_stats_read,
|
||||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.recover_from_tx_stall = iwl_bg_monitor_recover,
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
|
|
|
@ -329,6 +329,7 @@ static struct iwl_lib_ops iwl6000_lib = {
|
|||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.recover_from_tx_stall = iwl_bg_monitor_recover,
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
|
@ -404,6 +405,7 @@ static struct iwl_lib_ops iwl6000g2b_lib = {
|
|||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.recover_from_tx_stall = iwl_bg_monitor_recover,
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
|
|
|
@ -25,9 +25,15 @@
|
|||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*****************************************************************************/
|
||||
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-debugfs.h"
|
||||
|
||||
static const char *fmt_value = " %-30s %10u\n";
|
||||
static const char *fmt_hex = " %-30s 0x%02X\n";
|
||||
static const char *fmt_table = " %-30s %10u %10u %10u %10u\n";
|
||||
static const char *fmt_header =
|
||||
"%-32s current cumulative delta max\n";
|
||||
|
||||
static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
|
||||
{
|
||||
int p = 0;
|
||||
|
@ -121,436 +127,380 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
|||
}
|
||||
|
||||
pos += iwl_statistics_flag(priv, buf, bufsz);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
|
||||
"acumulative delta max\n",
|
||||
"Statistics_Rx - OFDM:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
|
||||
fmt_header, "Statistics_Rx - OFDM:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ina_cnt:",
|
||||
le32_to_cpu(ofdm->ina_cnt),
|
||||
accum_ofdm->ina_cnt,
|
||||
delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"fina_cnt:",
|
||||
fmt_table, "fina_cnt:",
|
||||
le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
|
||||
delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"plcp_err:",
|
||||
fmt_table, "plcp_err:",
|
||||
le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
|
||||
delta_ofdm->plcp_err, max_ofdm->plcp_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "crc32_err:",
|
||||
fmt_table, "crc32_err:",
|
||||
le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
|
||||
delta_ofdm->crc32_err, max_ofdm->crc32_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "overrun_err:",
|
||||
fmt_table, "overrun_err:",
|
||||
le32_to_cpu(ofdm->overrun_err),
|
||||
accum_ofdm->overrun_err, delta_ofdm->overrun_err,
|
||||
max_ofdm->overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"early_overrun_err:",
|
||||
fmt_table, "early_overrun_err:",
|
||||
le32_to_cpu(ofdm->early_overrun_err),
|
||||
accum_ofdm->early_overrun_err,
|
||||
delta_ofdm->early_overrun_err,
|
||||
max_ofdm->early_overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"crc32_good:", le32_to_cpu(ofdm->crc32_good),
|
||||
fmt_table, "crc32_good:",
|
||||
le32_to_cpu(ofdm->crc32_good),
|
||||
accum_ofdm->crc32_good, delta_ofdm->crc32_good,
|
||||
max_ofdm->crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "false_alarm_cnt:",
|
||||
fmt_table, "false_alarm_cnt:",
|
||||
le32_to_cpu(ofdm->false_alarm_cnt),
|
||||
accum_ofdm->false_alarm_cnt,
|
||||
delta_ofdm->false_alarm_cnt,
|
||||
max_ofdm->false_alarm_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"fina_sync_err_cnt:",
|
||||
fmt_table, "fina_sync_err_cnt:",
|
||||
le32_to_cpu(ofdm->fina_sync_err_cnt),
|
||||
accum_ofdm->fina_sync_err_cnt,
|
||||
delta_ofdm->fina_sync_err_cnt,
|
||||
max_ofdm->fina_sync_err_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "sfd_timeout:",
|
||||
fmt_table, "sfd_timeout:",
|
||||
le32_to_cpu(ofdm->sfd_timeout),
|
||||
accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
|
||||
max_ofdm->sfd_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "fina_timeout:",
|
||||
fmt_table, "fina_timeout:",
|
||||
le32_to_cpu(ofdm->fina_timeout),
|
||||
accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
|
||||
max_ofdm->fina_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"unresponded_rts:",
|
||||
fmt_table, "unresponded_rts:",
|
||||
le32_to_cpu(ofdm->unresponded_rts),
|
||||
accum_ofdm->unresponded_rts,
|
||||
delta_ofdm->unresponded_rts,
|
||||
max_ofdm->unresponded_rts);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"rxe_frame_lmt_ovrun:",
|
||||
fmt_table, "rxe_frame_lmt_ovrun:",
|
||||
le32_to_cpu(ofdm->rxe_frame_limit_overrun),
|
||||
accum_ofdm->rxe_frame_limit_overrun,
|
||||
delta_ofdm->rxe_frame_limit_overrun,
|
||||
max_ofdm->rxe_frame_limit_overrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "sent_ack_cnt:",
|
||||
fmt_table, "sent_ack_cnt:",
|
||||
le32_to_cpu(ofdm->sent_ack_cnt),
|
||||
accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
|
||||
max_ofdm->sent_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "sent_cts_cnt:",
|
||||
fmt_table, "sent_cts_cnt:",
|
||||
le32_to_cpu(ofdm->sent_cts_cnt),
|
||||
accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
|
||||
max_ofdm->sent_cts_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"sent_ba_rsp_cnt:",
|
||||
fmt_table, "sent_ba_rsp_cnt:",
|
||||
le32_to_cpu(ofdm->sent_ba_rsp_cnt),
|
||||
accum_ofdm->sent_ba_rsp_cnt,
|
||||
delta_ofdm->sent_ba_rsp_cnt,
|
||||
max_ofdm->sent_ba_rsp_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "dsp_self_kill:",
|
||||
fmt_table, "dsp_self_kill:",
|
||||
le32_to_cpu(ofdm->dsp_self_kill),
|
||||
accum_ofdm->dsp_self_kill,
|
||||
delta_ofdm->dsp_self_kill,
|
||||
max_ofdm->dsp_self_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"mh_format_err:",
|
||||
fmt_table, "mh_format_err:",
|
||||
le32_to_cpu(ofdm->mh_format_err),
|
||||
accum_ofdm->mh_format_err,
|
||||
delta_ofdm->mh_format_err,
|
||||
max_ofdm->mh_format_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"re_acq_main_rssi_sum:",
|
||||
fmt_table, "re_acq_main_rssi_sum:",
|
||||
le32_to_cpu(ofdm->re_acq_main_rssi_sum),
|
||||
accum_ofdm->re_acq_main_rssi_sum,
|
||||
delta_ofdm->re_acq_main_rssi_sum,
|
||||
max_ofdm->re_acq_main_rssi_sum);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
|
||||
"acumulative delta max\n",
|
||||
"Statistics_Rx - CCK:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"ina_cnt:",
|
||||
fmt_header, "Statistics_Rx - CCK:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ina_cnt:",
|
||||
le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
|
||||
delta_cck->ina_cnt, max_cck->ina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"fina_cnt:",
|
||||
fmt_table, "fina_cnt:",
|
||||
le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
|
||||
delta_cck->fina_cnt, max_cck->fina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"plcp_err:",
|
||||
fmt_table, "plcp_err:",
|
||||
le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
|
||||
delta_cck->plcp_err, max_cck->plcp_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"crc32_err:",
|
||||
fmt_table, "crc32_err:",
|
||||
le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
|
||||
delta_cck->crc32_err, max_cck->crc32_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"overrun_err:",
|
||||
fmt_table, "overrun_err:",
|
||||
le32_to_cpu(cck->overrun_err),
|
||||
accum_cck->overrun_err, delta_cck->overrun_err,
|
||||
max_cck->overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"early_overrun_err:",
|
||||
fmt_table, "early_overrun_err:",
|
||||
le32_to_cpu(cck->early_overrun_err),
|
||||
accum_cck->early_overrun_err,
|
||||
delta_cck->early_overrun_err,
|
||||
max_cck->early_overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"crc32_good:",
|
||||
fmt_table, "crc32_good:",
|
||||
le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
|
||||
delta_cck->crc32_good, max_cck->crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"false_alarm_cnt:",
|
||||
fmt_table, "false_alarm_cnt:",
|
||||
le32_to_cpu(cck->false_alarm_cnt),
|
||||
accum_cck->false_alarm_cnt,
|
||||
delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"fina_sync_err_cnt:",
|
||||
fmt_table, "fina_sync_err_cnt:",
|
||||
le32_to_cpu(cck->fina_sync_err_cnt),
|
||||
accum_cck->fina_sync_err_cnt,
|
||||
delta_cck->fina_sync_err_cnt,
|
||||
max_cck->fina_sync_err_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"sfd_timeout:",
|
||||
fmt_table, "sfd_timeout:",
|
||||
le32_to_cpu(cck->sfd_timeout),
|
||||
accum_cck->sfd_timeout, delta_cck->sfd_timeout,
|
||||
max_cck->sfd_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "fina_timeout:",
|
||||
fmt_table, "fina_timeout:",
|
||||
le32_to_cpu(cck->fina_timeout),
|
||||
accum_cck->fina_timeout, delta_cck->fina_timeout,
|
||||
max_cck->fina_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"unresponded_rts:",
|
||||
fmt_table, "unresponded_rts:",
|
||||
le32_to_cpu(cck->unresponded_rts),
|
||||
accum_cck->unresponded_rts, delta_cck->unresponded_rts,
|
||||
max_cck->unresponded_rts);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"rxe_frame_lmt_ovrun:",
|
||||
fmt_table, "rxe_frame_lmt_ovrun:",
|
||||
le32_to_cpu(cck->rxe_frame_limit_overrun),
|
||||
accum_cck->rxe_frame_limit_overrun,
|
||||
delta_cck->rxe_frame_limit_overrun,
|
||||
max_cck->rxe_frame_limit_overrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "sent_ack_cnt:",
|
||||
fmt_table, "sent_ack_cnt:",
|
||||
le32_to_cpu(cck->sent_ack_cnt),
|
||||
accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
|
||||
max_cck->sent_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "sent_cts_cnt:",
|
||||
fmt_table, "sent_cts_cnt:",
|
||||
le32_to_cpu(cck->sent_cts_cnt),
|
||||
accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
|
||||
max_cck->sent_cts_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "sent_ba_rsp_cnt:",
|
||||
fmt_table, "sent_ba_rsp_cnt:",
|
||||
le32_to_cpu(cck->sent_ba_rsp_cnt),
|
||||
accum_cck->sent_ba_rsp_cnt,
|
||||
delta_cck->sent_ba_rsp_cnt,
|
||||
max_cck->sent_ba_rsp_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "dsp_self_kill:",
|
||||
fmt_table, "dsp_self_kill:",
|
||||
le32_to_cpu(cck->dsp_self_kill),
|
||||
accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
|
||||
max_cck->dsp_self_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "mh_format_err:",
|
||||
fmt_table, "mh_format_err:",
|
||||
le32_to_cpu(cck->mh_format_err),
|
||||
accum_cck->mh_format_err, delta_cck->mh_format_err,
|
||||
max_cck->mh_format_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"re_acq_main_rssi_sum:",
|
||||
fmt_table, "re_acq_main_rssi_sum:",
|
||||
le32_to_cpu(cck->re_acq_main_rssi_sum),
|
||||
accum_cck->re_acq_main_rssi_sum,
|
||||
delta_cck->re_acq_main_rssi_sum,
|
||||
max_cck->re_acq_main_rssi_sum);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
|
||||
"acumulative delta max\n",
|
||||
"Statistics_Rx - GENERAL:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "bogus_cts:",
|
||||
fmt_header, "Statistics_Rx - GENERAL:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "bogus_cts:",
|
||||
le32_to_cpu(general->bogus_cts),
|
||||
accum_general->bogus_cts, delta_general->bogus_cts,
|
||||
max_general->bogus_cts);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n", "bogus_ack:",
|
||||
fmt_table, "bogus_ack:",
|
||||
le32_to_cpu(general->bogus_ack),
|
||||
accum_general->bogus_ack, delta_general->bogus_ack,
|
||||
max_general->bogus_ack);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"non_bssid_frames:",
|
||||
fmt_table, "non_bssid_frames:",
|
||||
le32_to_cpu(general->non_bssid_frames),
|
||||
accum_general->non_bssid_frames,
|
||||
delta_general->non_bssid_frames,
|
||||
max_general->non_bssid_frames);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"filtered_frames:",
|
||||
fmt_table, "filtered_frames:",
|
||||
le32_to_cpu(general->filtered_frames),
|
||||
accum_general->filtered_frames,
|
||||
delta_general->filtered_frames,
|
||||
max_general->filtered_frames);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"non_channel_beacons:",
|
||||
fmt_table, "non_channel_beacons:",
|
||||
le32_to_cpu(general->non_channel_beacons),
|
||||
accum_general->non_channel_beacons,
|
||||
delta_general->non_channel_beacons,
|
||||
max_general->non_channel_beacons);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"channel_beacons:",
|
||||
fmt_table, "channel_beacons:",
|
||||
le32_to_cpu(general->channel_beacons),
|
||||
accum_general->channel_beacons,
|
||||
delta_general->channel_beacons,
|
||||
max_general->channel_beacons);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"num_missed_bcon:",
|
||||
fmt_table, "num_missed_bcon:",
|
||||
le32_to_cpu(general->num_missed_bcon),
|
||||
accum_general->num_missed_bcon,
|
||||
delta_general->num_missed_bcon,
|
||||
max_general->num_missed_bcon);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"adc_rx_saturation_time:",
|
||||
fmt_table, "adc_rx_saturation_time:",
|
||||
le32_to_cpu(general->adc_rx_saturation_time),
|
||||
accum_general->adc_rx_saturation_time,
|
||||
delta_general->adc_rx_saturation_time,
|
||||
max_general->adc_rx_saturation_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"ina_detect_search_tm:",
|
||||
fmt_table, "ina_detect_search_tm:",
|
||||
le32_to_cpu(general->ina_detection_search_time),
|
||||
accum_general->ina_detection_search_time,
|
||||
delta_general->ina_detection_search_time,
|
||||
max_general->ina_detection_search_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_silence_rssi_a:",
|
||||
fmt_table, "beacon_silence_rssi_a:",
|
||||
le32_to_cpu(general->beacon_silence_rssi_a),
|
||||
accum_general->beacon_silence_rssi_a,
|
||||
delta_general->beacon_silence_rssi_a,
|
||||
max_general->beacon_silence_rssi_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_silence_rssi_b:",
|
||||
fmt_table, "beacon_silence_rssi_b:",
|
||||
le32_to_cpu(general->beacon_silence_rssi_b),
|
||||
accum_general->beacon_silence_rssi_b,
|
||||
delta_general->beacon_silence_rssi_b,
|
||||
max_general->beacon_silence_rssi_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_silence_rssi_c:",
|
||||
fmt_table, "beacon_silence_rssi_c:",
|
||||
le32_to_cpu(general->beacon_silence_rssi_c),
|
||||
accum_general->beacon_silence_rssi_c,
|
||||
delta_general->beacon_silence_rssi_c,
|
||||
max_general->beacon_silence_rssi_c);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"interference_data_flag:",
|
||||
fmt_table, "interference_data_flag:",
|
||||
le32_to_cpu(general->interference_data_flag),
|
||||
accum_general->interference_data_flag,
|
||||
delta_general->interference_data_flag,
|
||||
max_general->interference_data_flag);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"channel_load:",
|
||||
fmt_table, "channel_load:",
|
||||
le32_to_cpu(general->channel_load),
|
||||
accum_general->channel_load,
|
||||
delta_general->channel_load,
|
||||
max_general->channel_load);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"dsp_false_alarms:",
|
||||
fmt_table, "dsp_false_alarms:",
|
||||
le32_to_cpu(general->dsp_false_alarms),
|
||||
accum_general->dsp_false_alarms,
|
||||
delta_general->dsp_false_alarms,
|
||||
max_general->dsp_false_alarms);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_rssi_a:",
|
||||
fmt_table, "beacon_rssi_a:",
|
||||
le32_to_cpu(general->beacon_rssi_a),
|
||||
accum_general->beacon_rssi_a,
|
||||
delta_general->beacon_rssi_a,
|
||||
max_general->beacon_rssi_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_rssi_b:",
|
||||
fmt_table, "beacon_rssi_b:",
|
||||
le32_to_cpu(general->beacon_rssi_b),
|
||||
accum_general->beacon_rssi_b,
|
||||
delta_general->beacon_rssi_b,
|
||||
max_general->beacon_rssi_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_rssi_c:",
|
||||
fmt_table, "beacon_rssi_c:",
|
||||
le32_to_cpu(general->beacon_rssi_c),
|
||||
accum_general->beacon_rssi_c,
|
||||
delta_general->beacon_rssi_c,
|
||||
max_general->beacon_rssi_c);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_energy_a:",
|
||||
fmt_table, "beacon_energy_a:",
|
||||
le32_to_cpu(general->beacon_energy_a),
|
||||
accum_general->beacon_energy_a,
|
||||
delta_general->beacon_energy_a,
|
||||
max_general->beacon_energy_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_energy_b:",
|
||||
fmt_table, "beacon_energy_b:",
|
||||
le32_to_cpu(general->beacon_energy_b),
|
||||
accum_general->beacon_energy_b,
|
||||
delta_general->beacon_energy_b,
|
||||
max_general->beacon_energy_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"beacon_energy_c:",
|
||||
fmt_table, "beacon_energy_c:",
|
||||
le32_to_cpu(general->beacon_energy_c),
|
||||
accum_general->beacon_energy_c,
|
||||
delta_general->beacon_energy_c,
|
||||
max_general->beacon_energy_c);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
|
||||
"acumulative delta max\n",
|
||||
"Statistics_Rx - OFDM_HT:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"plcp_err:",
|
||||
fmt_header, "Statistics_Rx - OFDM_HT:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "plcp_err:",
|
||||
le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
|
||||
delta_ht->plcp_err, max_ht->plcp_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"overrun_err:",
|
||||
fmt_table, "overrun_err:",
|
||||
le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
|
||||
delta_ht->overrun_err, max_ht->overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"early_overrun_err:",
|
||||
fmt_table, "early_overrun_err:",
|
||||
le32_to_cpu(ht->early_overrun_err),
|
||||
accum_ht->early_overrun_err,
|
||||
delta_ht->early_overrun_err,
|
||||
max_ht->early_overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"crc32_good:",
|
||||
fmt_table, "crc32_good:",
|
||||
le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
|
||||
delta_ht->crc32_good, max_ht->crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"crc32_err:",
|
||||
fmt_table, "crc32_err:",
|
||||
le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
|
||||
delta_ht->crc32_err, max_ht->crc32_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"mh_format_err:",
|
||||
fmt_table, "mh_format_err:",
|
||||
le32_to_cpu(ht->mh_format_err),
|
||||
accum_ht->mh_format_err,
|
||||
delta_ht->mh_format_err, max_ht->mh_format_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg_crc32_good:",
|
||||
fmt_table, "agg_crc32_good:",
|
||||
le32_to_cpu(ht->agg_crc32_good),
|
||||
accum_ht->agg_crc32_good,
|
||||
delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg_mpdu_cnt:",
|
||||
fmt_table, "agg_mpdu_cnt:",
|
||||
le32_to_cpu(ht->agg_mpdu_cnt),
|
||||
accum_ht->agg_mpdu_cnt,
|
||||
delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg_cnt:",
|
||||
fmt_table, "agg_cnt:",
|
||||
le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
|
||||
delta_ht->agg_cnt, max_ht->agg_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"unsupport_mcs:",
|
||||
fmt_table, "unsupport_mcs:",
|
||||
le32_to_cpu(ht->unsupport_mcs),
|
||||
accum_ht->unsupport_mcs,
|
||||
delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
|
||||
|
@ -597,166 +547,141 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
|
|||
}
|
||||
|
||||
pos += iwl_statistics_flag(priv, buf, bufsz);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
|
||||
"acumulative delta max\n",
|
||||
"Statistics_Tx:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"preamble:",
|
||||
fmt_header, "Statistics_Tx:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "preamble:",
|
||||
le32_to_cpu(tx->preamble_cnt),
|
||||
accum_tx->preamble_cnt,
|
||||
delta_tx->preamble_cnt, max_tx->preamble_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"rx_detected_cnt:",
|
||||
fmt_table, "rx_detected_cnt:",
|
||||
le32_to_cpu(tx->rx_detected_cnt),
|
||||
accum_tx->rx_detected_cnt,
|
||||
delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"bt_prio_defer_cnt:",
|
||||
fmt_table, "bt_prio_defer_cnt:",
|
||||
le32_to_cpu(tx->bt_prio_defer_cnt),
|
||||
accum_tx->bt_prio_defer_cnt,
|
||||
delta_tx->bt_prio_defer_cnt,
|
||||
max_tx->bt_prio_defer_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"bt_prio_kill_cnt:",
|
||||
fmt_table, "bt_prio_kill_cnt:",
|
||||
le32_to_cpu(tx->bt_prio_kill_cnt),
|
||||
accum_tx->bt_prio_kill_cnt,
|
||||
delta_tx->bt_prio_kill_cnt,
|
||||
max_tx->bt_prio_kill_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"few_bytes_cnt:",
|
||||
fmt_table, "few_bytes_cnt:",
|
||||
le32_to_cpu(tx->few_bytes_cnt),
|
||||
accum_tx->few_bytes_cnt,
|
||||
delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"cts_timeout:",
|
||||
fmt_table, "cts_timeout:",
|
||||
le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
|
||||
delta_tx->cts_timeout, max_tx->cts_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"ack_timeout:",
|
||||
fmt_table, "ack_timeout:",
|
||||
le32_to_cpu(tx->ack_timeout),
|
||||
accum_tx->ack_timeout,
|
||||
delta_tx->ack_timeout, max_tx->ack_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"expected_ack_cnt:",
|
||||
fmt_table, "expected_ack_cnt:",
|
||||
le32_to_cpu(tx->expected_ack_cnt),
|
||||
accum_tx->expected_ack_cnt,
|
||||
delta_tx->expected_ack_cnt,
|
||||
max_tx->expected_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"actual_ack_cnt:",
|
||||
fmt_table, "actual_ack_cnt:",
|
||||
le32_to_cpu(tx->actual_ack_cnt),
|
||||
accum_tx->actual_ack_cnt,
|
||||
delta_tx->actual_ack_cnt,
|
||||
max_tx->actual_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"dump_msdu_cnt:",
|
||||
fmt_table, "dump_msdu_cnt:",
|
||||
le32_to_cpu(tx->dump_msdu_cnt),
|
||||
accum_tx->dump_msdu_cnt,
|
||||
delta_tx->dump_msdu_cnt,
|
||||
max_tx->dump_msdu_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"abort_nxt_frame_mismatch:",
|
||||
fmt_table, "abort_nxt_frame_mismatch:",
|
||||
le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
|
||||
accum_tx->burst_abort_next_frame_mismatch_cnt,
|
||||
delta_tx->burst_abort_next_frame_mismatch_cnt,
|
||||
max_tx->burst_abort_next_frame_mismatch_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"abort_missing_nxt_frame:",
|
||||
fmt_table, "abort_missing_nxt_frame:",
|
||||
le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
|
||||
accum_tx->burst_abort_missing_next_frame_cnt,
|
||||
delta_tx->burst_abort_missing_next_frame_cnt,
|
||||
max_tx->burst_abort_missing_next_frame_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"cts_timeout_collision:",
|
||||
fmt_table, "cts_timeout_collision:",
|
||||
le32_to_cpu(tx->cts_timeout_collision),
|
||||
accum_tx->cts_timeout_collision,
|
||||
delta_tx->cts_timeout_collision,
|
||||
max_tx->cts_timeout_collision);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"ack_ba_timeout_collision:",
|
||||
fmt_table, "ack_ba_timeout_collision:",
|
||||
le32_to_cpu(tx->ack_or_ba_timeout_collision),
|
||||
accum_tx->ack_or_ba_timeout_collision,
|
||||
delta_tx->ack_or_ba_timeout_collision,
|
||||
max_tx->ack_or_ba_timeout_collision);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg ba_timeout:",
|
||||
fmt_table, "agg ba_timeout:",
|
||||
le32_to_cpu(tx->agg.ba_timeout),
|
||||
accum_tx->agg.ba_timeout,
|
||||
delta_tx->agg.ba_timeout,
|
||||
max_tx->agg.ba_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg ba_resched_frames:",
|
||||
fmt_table, "agg ba_resched_frames:",
|
||||
le32_to_cpu(tx->agg.ba_reschedule_frames),
|
||||
accum_tx->agg.ba_reschedule_frames,
|
||||
delta_tx->agg.ba_reschedule_frames,
|
||||
max_tx->agg.ba_reschedule_frames);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg scd_query_agg_frame:",
|
||||
fmt_table, "agg scd_query_agg_frame:",
|
||||
le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
|
||||
accum_tx->agg.scd_query_agg_frame_cnt,
|
||||
delta_tx->agg.scd_query_agg_frame_cnt,
|
||||
max_tx->agg.scd_query_agg_frame_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg scd_query_no_agg:",
|
||||
fmt_table, "agg scd_query_no_agg:",
|
||||
le32_to_cpu(tx->agg.scd_query_no_agg),
|
||||
accum_tx->agg.scd_query_no_agg,
|
||||
delta_tx->agg.scd_query_no_agg,
|
||||
max_tx->agg.scd_query_no_agg);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg scd_query_agg:",
|
||||
fmt_table, "agg scd_query_agg:",
|
||||
le32_to_cpu(tx->agg.scd_query_agg),
|
||||
accum_tx->agg.scd_query_agg,
|
||||
delta_tx->agg.scd_query_agg,
|
||||
max_tx->agg.scd_query_agg);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg scd_query_mismatch:",
|
||||
fmt_table, "agg scd_query_mismatch:",
|
||||
le32_to_cpu(tx->agg.scd_query_mismatch),
|
||||
accum_tx->agg.scd_query_mismatch,
|
||||
delta_tx->agg.scd_query_mismatch,
|
||||
max_tx->agg.scd_query_mismatch);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg frame_not_ready:",
|
||||
fmt_table, "agg frame_not_ready:",
|
||||
le32_to_cpu(tx->agg.frame_not_ready),
|
||||
accum_tx->agg.frame_not_ready,
|
||||
delta_tx->agg.frame_not_ready,
|
||||
max_tx->agg.frame_not_ready);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg underrun:",
|
||||
fmt_table, "agg underrun:",
|
||||
le32_to_cpu(tx->agg.underrun),
|
||||
accum_tx->agg.underrun,
|
||||
delta_tx->agg.underrun, max_tx->agg.underrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg bt_prio_kill:",
|
||||
fmt_table, "agg bt_prio_kill:",
|
||||
le32_to_cpu(tx->agg.bt_prio_kill),
|
||||
accum_tx->agg.bt_prio_kill,
|
||||
delta_tx->agg.bt_prio_kill,
|
||||
max_tx->agg.bt_prio_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"agg rx_ba_rsp_cnt:",
|
||||
fmt_table, "agg rx_ba_rsp_cnt:",
|
||||
le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
|
||||
accum_tx->agg.rx_ba_rsp_cnt,
|
||||
delta_tx->agg.rx_ba_rsp_cnt,
|
||||
|
@ -767,15 +692,15 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
|
|||
"tx power: (1/2 dB step)\n");
|
||||
if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tantenna A: 0x%X\n",
|
||||
fmt_hex, "antenna A:",
|
||||
tx->tx_power.ant_a);
|
||||
if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tantenna B: 0x%X\n",
|
||||
fmt_hex, "antenna B:",
|
||||
tx->tx_power.ant_b);
|
||||
if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tantenna C: 0x%X\n",
|
||||
fmt_hex, "antenna C:",
|
||||
tx->tx_power.ant_c);
|
||||
}
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
|
@ -838,84 +763,72 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
|
|||
}
|
||||
|
||||
pos += iwl_statistics_flag(priv, buf, bufsz);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
|
||||
"acumulative delta max\n",
|
||||
"Statistics_General:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, " %-30s %10u\n",
|
||||
"temperature:",
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_General:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_value, "temperature:",
|
||||
le32_to_cpu(general->temperature));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, " %-30s %10u\n",
|
||||
"temperature_m:",
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_value, "temperature_m:",
|
||||
le32_to_cpu(general->temperature_m));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"burst_check:",
|
||||
fmt_value, "ttl_timestamp:",
|
||||
le32_to_cpu(general->ttl_timestamp));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "burst_check:",
|
||||
le32_to_cpu(dbg->burst_check),
|
||||
accum_dbg->burst_check,
|
||||
delta_dbg->burst_check, max_dbg->burst_check);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"burst_count:",
|
||||
fmt_table, "burst_count:",
|
||||
le32_to_cpu(dbg->burst_count),
|
||||
accum_dbg->burst_count,
|
||||
delta_dbg->burst_count, max_dbg->burst_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"wait_for_silence_timeout_count:",
|
||||
fmt_table, "wait_for_silence_timeout_count:",
|
||||
le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
|
||||
accum_dbg->wait_for_silence_timeout_cnt,
|
||||
delta_dbg->wait_for_silence_timeout_cnt,
|
||||
max_dbg->wait_for_silence_timeout_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"sleep_time:",
|
||||
fmt_table, "sleep_time:",
|
||||
le32_to_cpu(general->sleep_time),
|
||||
accum_general->sleep_time,
|
||||
delta_general->sleep_time, max_general->sleep_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"slots_out:",
|
||||
fmt_table, "slots_out:",
|
||||
le32_to_cpu(general->slots_out),
|
||||
accum_general->slots_out,
|
||||
delta_general->slots_out, max_general->slots_out);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"slots_idle:",
|
||||
fmt_table, "slots_idle:",
|
||||
le32_to_cpu(general->slots_idle),
|
||||
accum_general->slots_idle,
|
||||
delta_general->slots_idle, max_general->slots_idle);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
|
||||
le32_to_cpu(general->ttl_timestamp));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"tx_on_a:",
|
||||
fmt_table, "tx_on_a:",
|
||||
le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
|
||||
delta_div->tx_on_a, max_div->tx_on_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"tx_on_b:",
|
||||
fmt_table, "tx_on_b:",
|
||||
le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
|
||||
delta_div->tx_on_b, max_div->tx_on_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"exec_time:",
|
||||
fmt_table, "exec_time:",
|
||||
le32_to_cpu(div->exec_time), accum_div->exec_time,
|
||||
delta_div->exec_time, max_div->exec_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"probe_time:",
|
||||
fmt_table, "probe_time:",
|
||||
le32_to_cpu(div->probe_time), accum_div->probe_time,
|
||||
delta_div->probe_time, max_div->probe_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"rx_enable_counter:",
|
||||
fmt_table, "rx_enable_counter:",
|
||||
le32_to_cpu(general->rx_enable_counter),
|
||||
accum_general->rx_enable_counter,
|
||||
delta_general->rx_enable_counter,
|
||||
max_general->rx_enable_counter);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" %-30s %10u %10u %10u %10u\n",
|
||||
"num_of_sos_states:",
|
||||
fmt_table, "num_of_sos_states:",
|
||||
le32_to_cpu(general->num_of_sos_states),
|
||||
accum_general->num_of_sos_states,
|
||||
delta_general->num_of_sos_states,
|
||||
|
@ -1011,3 +924,147 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file,
|
|||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t iwl_reply_tx_error_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) +
|
||||
(sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
|
||||
ssize_t ret;
|
||||
|
||||
if (!iwl_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
IWL_ERR(priv, "Can not allocate Buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
|
||||
priv->_agn.reply_tx_stats.pp_delay);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
|
||||
priv->_agn.reply_tx_stats.pp_few_bytes);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
|
||||
priv->_agn.reply_tx_stats.pp_bt_prio);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
|
||||
priv->_agn.reply_tx_stats.pp_quiet_period);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
|
||||
priv->_agn.reply_tx_stats.pp_calc_ttak);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(
|
||||
TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
|
||||
priv->_agn.reply_tx_stats.int_crossed_retry);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
|
||||
priv->_agn.reply_tx_stats.short_limit);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
|
||||
priv->_agn.reply_tx_stats.long_limit);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
|
||||
priv->_agn.reply_tx_stats.fifo_underrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
|
||||
priv->_agn.reply_tx_stats.drain_flow);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
|
||||
priv->_agn.reply_tx_stats.rfkill_flush);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
|
||||
priv->_agn.reply_tx_stats.life_expire);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
|
||||
priv->_agn.reply_tx_stats.dest_ps);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
|
||||
priv->_agn.reply_tx_stats.host_abort);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
|
||||
priv->_agn.reply_tx_stats.pp_delay);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
|
||||
priv->_agn.reply_tx_stats.sta_invalid);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
|
||||
priv->_agn.reply_tx_stats.frag_drop);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
|
||||
priv->_agn.reply_tx_stats.tid_disable);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
|
||||
priv->_agn.reply_tx_stats.fifo_flush);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(
|
||||
TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
|
||||
priv->_agn.reply_tx_stats.insuff_cf_poll);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
|
||||
priv->_agn.reply_tx_stats.fail_hw_drop);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_tx_fail_reason(
|
||||
TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
|
||||
priv->_agn.reply_tx_stats.sta_color_mismatch);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
|
||||
priv->_agn.reply_tx_stats.unknown);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\nStatistics_Agg_TX_Error:\n");
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.underrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.bt_prio);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.few_bytes);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.abort);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(
|
||||
AGG_TX_STATE_LAST_SENT_TTL_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.last_sent_ttl);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(
|
||||
AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.last_sent_try);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(
|
||||
AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.last_sent_bt_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.scd_query);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(
|
||||
AGG_TX_STATE_TEST_BAD_CRC32_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.bad_crc32);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.response);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.dump_tx);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
|
||||
iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
|
||||
priv->_agn.reply_agg_tx_stats.delay_tx);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
|
||||
priv->_agn.reply_agg_tx_stats.unknown);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
|
|||
size_t count, loff_t *ppos);
|
||||
ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
#else
|
||||
static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
@ -60,4 +62,9 @@ static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -287,6 +287,15 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
|
|||
ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
|
||||
|
||||
/*
|
||||
* If the PAN context is inactive, then we don't need
|
||||
* to update the PAN parameters, the last thing we'll
|
||||
* have done before it goes inactive is making the PAN
|
||||
* parameters be WLAN-only.
|
||||
*/
|
||||
if (!ctx_pan->is_active)
|
||||
return 0;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
/* only 2 slots are currently allowed */
|
||||
|
@ -312,7 +321,7 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
|
|||
bcnint = max_t(int, bcnint,
|
||||
ctx_bss->vif->bss_conf.beacon_int);
|
||||
if (!bcnint)
|
||||
bcnint = 100;
|
||||
bcnint = DEFAULT_BEACON_INTERVAL;
|
||||
slot0 = bcnint / 2;
|
||||
slot1 = bcnint - slot0;
|
||||
|
||||
|
@ -330,7 +339,12 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
|
|||
slot0 = 0;
|
||||
slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
|
||||
ctx_pan->vif->bss_conf.beacon_int;
|
||||
slot1 = max_t(int, 100, slot1);
|
||||
slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
|
||||
|
||||
if (test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
slot0 = slot1 * 3 - 20;
|
||||
slot1 = 20;
|
||||
}
|
||||
}
|
||||
|
||||
cmd.slots[0].width = cpu_to_le16(slot0);
|
||||
|
|
|
@ -46,6 +46,181 @@ static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
|
|||
tx_resp->frame_count) & MAX_SN;
|
||||
}
|
||||
|
||||
static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
|
||||
{
|
||||
status &= TX_STATUS_MSK;
|
||||
|
||||
switch (status) {
|
||||
case TX_STATUS_POSTPONE_DELAY:
|
||||
priv->_agn.reply_tx_stats.pp_delay++;
|
||||
break;
|
||||
case TX_STATUS_POSTPONE_FEW_BYTES:
|
||||
priv->_agn.reply_tx_stats.pp_few_bytes++;
|
||||
break;
|
||||
case TX_STATUS_POSTPONE_BT_PRIO:
|
||||
priv->_agn.reply_tx_stats.pp_bt_prio++;
|
||||
break;
|
||||
case TX_STATUS_POSTPONE_QUIET_PERIOD:
|
||||
priv->_agn.reply_tx_stats.pp_quiet_period++;
|
||||
break;
|
||||
case TX_STATUS_POSTPONE_CALC_TTAK:
|
||||
priv->_agn.reply_tx_stats.pp_calc_ttak++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
|
||||
priv->_agn.reply_tx_stats.int_crossed_retry++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_SHORT_LIMIT:
|
||||
priv->_agn.reply_tx_stats.short_limit++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_LONG_LIMIT:
|
||||
priv->_agn.reply_tx_stats.long_limit++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_FIFO_UNDERRUN:
|
||||
priv->_agn.reply_tx_stats.fifo_underrun++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_DRAIN_FLOW:
|
||||
priv->_agn.reply_tx_stats.drain_flow++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_RFKILL_FLUSH:
|
||||
priv->_agn.reply_tx_stats.rfkill_flush++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_LIFE_EXPIRE:
|
||||
priv->_agn.reply_tx_stats.life_expire++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_DEST_PS:
|
||||
priv->_agn.reply_tx_stats.dest_ps++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_HOST_ABORTED:
|
||||
priv->_agn.reply_tx_stats.host_abort++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_BT_RETRY:
|
||||
priv->_agn.reply_tx_stats.bt_retry++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_STA_INVALID:
|
||||
priv->_agn.reply_tx_stats.sta_invalid++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_FRAG_DROPPED:
|
||||
priv->_agn.reply_tx_stats.frag_drop++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_TID_DISABLE:
|
||||
priv->_agn.reply_tx_stats.tid_disable++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_FIFO_FLUSHED:
|
||||
priv->_agn.reply_tx_stats.fifo_flush++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
|
||||
priv->_agn.reply_tx_stats.insuff_cf_poll++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_PASSIVE_NO_RX:
|
||||
priv->_agn.reply_tx_stats.fail_hw_drop++;
|
||||
break;
|
||||
case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
|
||||
priv->_agn.reply_tx_stats.sta_color_mismatch++;
|
||||
break;
|
||||
default:
|
||||
priv->_agn.reply_tx_stats.unknown++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
|
||||
{
|
||||
status &= AGG_TX_STATUS_MSK;
|
||||
|
||||
switch (status) {
|
||||
case AGG_TX_STATE_UNDERRUN_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.underrun++;
|
||||
break;
|
||||
case AGG_TX_STATE_BT_PRIO_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.bt_prio++;
|
||||
break;
|
||||
case AGG_TX_STATE_FEW_BYTES_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.few_bytes++;
|
||||
break;
|
||||
case AGG_TX_STATE_ABORT_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.abort++;
|
||||
break;
|
||||
case AGG_TX_STATE_LAST_SENT_TTL_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.last_sent_ttl++;
|
||||
break;
|
||||
case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.last_sent_try++;
|
||||
break;
|
||||
case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.last_sent_bt_kill++;
|
||||
break;
|
||||
case AGG_TX_STATE_SCD_QUERY_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.scd_query++;
|
||||
break;
|
||||
case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.bad_crc32++;
|
||||
break;
|
||||
case AGG_TX_STATE_RESPONSE_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.response++;
|
||||
break;
|
||||
case AGG_TX_STATE_DUMP_TX_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.dump_tx++;
|
||||
break;
|
||||
case AGG_TX_STATE_DELAY_TX_MSK:
|
||||
priv->_agn.reply_agg_tx_stats.delay_tx++;
|
||||
break;
|
||||
default:
|
||||
priv->_agn.reply_agg_tx_stats.unknown++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwlagn_set_tx_status(struct iwl_priv *priv,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct iwl5000_tx_resp *tx_resp,
|
||||
int txq_id, bool is_agg)
|
||||
{
|
||||
u16 status = le16_to_cpu(tx_resp->status.status);
|
||||
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
if (is_agg)
|
||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
|
||||
info);
|
||||
if (!iwl_is_tx_success(status))
|
||||
iwlagn_count_tx_err_status(priv, status);
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
|
||||
"0x%x retries %d\n",
|
||||
txq_id,
|
||||
iwl_get_tx_fail_reason(status), status,
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
tx_resp->failure_frame);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
|
||||
|
||||
const char *iwl_get_agg_tx_fail_reason(u16 status)
|
||||
{
|
||||
status &= AGG_TX_STATUS_MSK;
|
||||
switch (status) {
|
||||
case AGG_TX_STATE_TRANSMITTED:
|
||||
return "SUCCESS";
|
||||
AGG_TX_STATE_FAIL(UNDERRUN_MSK);
|
||||
AGG_TX_STATE_FAIL(BT_PRIO_MSK);
|
||||
AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
|
||||
AGG_TX_STATE_FAIL(ABORT_MSK);
|
||||
AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
|
||||
AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
|
||||
AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
|
||||
AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
|
||||
AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
|
||||
AGG_TX_STATE_FAIL(RESPONSE_MSK);
|
||||
AGG_TX_STATE_FAIL(DUMP_TX_MSK);
|
||||
AGG_TX_STATE_FAIL(DELAY_TX_MSK);
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
|
||||
struct iwl_ht_agg *agg,
|
||||
struct iwl5000_tx_resp *tx_resp,
|
||||
|
@ -53,9 +228,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
|
|||
{
|
||||
u16 status;
|
||||
struct agg_tx_status *frame_status = &tx_resp->status;
|
||||
struct ieee80211_tx_info *info = NULL;
|
||||
struct ieee80211_hdr *hdr = NULL;
|
||||
u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
|
||||
int i, sh, idx;
|
||||
u16 seq;
|
||||
|
||||
|
@ -64,31 +237,20 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
|
|||
|
||||
agg->frame_count = tx_resp->frame_count;
|
||||
agg->start_idx = start_idx;
|
||||
agg->rate_n_flags = rate_n_flags;
|
||||
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
|
||||
agg->bitmap = 0;
|
||||
|
||||
/* # frames attempted by Tx command */
|
||||
if (agg->frame_count == 1) {
|
||||
/* Only one frame was attempted; no block-ack will arrive */
|
||||
status = le16_to_cpu(frame_status[0].status);
|
||||
idx = start_idx;
|
||||
|
||||
/* FIXME: code repetition */
|
||||
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
|
||||
agg->frame_count, agg->start_idx, idx);
|
||||
|
||||
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
|
||||
|
||||
/* FIXME: code repetition end */
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
|
||||
status & 0xff, tx_resp->failure_frame);
|
||||
IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags);
|
||||
|
||||
iwlagn_set_tx_status(priv,
|
||||
IEEE80211_SKB_CB(
|
||||
priv->txq[txq_id].txb[idx].skb),
|
||||
tx_resp, txq_id, true);
|
||||
agg->wait_for_ba = 0;
|
||||
} else {
|
||||
/* Two or more frames were attempted; expect block-ack */
|
||||
|
@ -109,12 +271,20 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
|
|||
idx = SEQ_TO_INDEX(seq);
|
||||
txq_id = SEQ_TO_QUEUE(seq);
|
||||
|
||||
if (status & AGG_TX_STATUS_MSK)
|
||||
iwlagn_count_agg_tx_err_status(priv, status);
|
||||
|
||||
if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
|
||||
AGG_TX_STATE_ABORT_MSK))
|
||||
continue;
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n",
|
||||
agg->frame_count, txq_id, idx);
|
||||
IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
|
||||
"try-count (0x%08x)\n",
|
||||
iwl_get_agg_tx_fail_reason(status),
|
||||
status & AGG_TX_STATUS_MSK,
|
||||
status & AGG_TX_TRY_MSK);
|
||||
|
||||
hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
|
||||
if (!hdr) {
|
||||
|
@ -281,20 +451,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
|
|||
}
|
||||
} else {
|
||||
BUG_ON(txq_id != txq->swq_id);
|
||||
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwlagn_hwrate_to_tx_control(priv,
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
info);
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
|
||||
"0x%x retries %d\n",
|
||||
txq_id,
|
||||
iwl_get_tx_fail_reason(status), status,
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
tx_resp->failure_frame);
|
||||
|
||||
iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
|
||||
freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
|
||||
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
|
||||
|
||||
|
@ -1154,7 +1311,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
|||
return added;
|
||||
}
|
||||
|
||||
void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||
int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SCAN_CMD,
|
||||
|
@ -1162,7 +1319,6 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
struct iwl_scan_cmd *scan;
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
u32 rate_flags = 0;
|
||||
u16 cmd_len;
|
||||
|
@ -1175,59 +1331,20 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
int chan_mod;
|
||||
u8 active_chains;
|
||||
u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (vif)
|
||||
ctx = iwl_rxon_ctx_from_vif(vif);
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
|
||||
if (!iwl_is_ready(priv)) {
|
||||
IWL_WARN(priv, "request scan called when driver not ready.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Make sure the scan wasn't canceled before this queued work
|
||||
* was given the chance to run... */
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status))
|
||||
goto done;
|
||||
|
||||
/* This should never be called or scheduled if there is currently
|
||||
* a scan active in the hardware. */
|
||||
if (test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests in parallel. "
|
||||
"Ignoring second request.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_HC(priv, "Scan request while abort pending. Queuing.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (iwl_is_rfkill(priv)) {
|
||||
IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!test_bit(STATUS_READY, &priv->status)) {
|
||||
IWL_DEBUG_HC(priv, "Scan request while uninitialized. Queuing.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!priv->scan_cmd) {
|
||||
priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
|
||||
IWL_MAX_SCAN_SIZE, GFP_KERNEL);
|
||||
if (!priv->scan_cmd) {
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"fail to allocate memory for scan\n");
|
||||
goto done;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
scan = priv->scan_cmd;
|
||||
|
@ -1334,8 +1451,8 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
IWL_GOOD_CRC_TH_NEVER;
|
||||
break;
|
||||
default:
|
||||
IWL_WARN(priv, "Invalid scan band count\n");
|
||||
goto done;
|
||||
IWL_WARN(priv, "Invalid scan band\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
band = priv->scan_band;
|
||||
|
@ -1415,7 +1532,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
}
|
||||
if (scan->channel_count == 0) {
|
||||
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
|
||||
goto done;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
|
||||
|
@ -1423,30 +1540,21 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
cmd.data = scan;
|
||||
scan->len = cpu_to_le16(cmd.len);
|
||||
|
||||
if (priv->cfg->ops->hcmd->set_pan_params) {
|
||||
ret = priv->cfg->ops->hcmd->set_pan_params(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_bit(STATUS_SCAN_HW, &priv->status);
|
||||
ret = iwl_send_cmd_sync(priv, &cmd);
|
||||
if (ret) {
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
if (priv->cfg->ops->hcmd->set_pan_params)
|
||||
priv->cfg->ops->hcmd->set_pan_params(priv);
|
||||
}
|
||||
|
||||
if (priv->cfg->ops->hcmd->set_pan_params &&
|
||||
priv->cfg->ops->hcmd->set_pan_params(priv))
|
||||
goto done;
|
||||
|
||||
if (iwl_send_cmd_sync(priv, &cmd))
|
||||
goto done;
|
||||
|
||||
queue_delayed_work(priv->workqueue, &priv->scan_check,
|
||||
IWL_SCAN_CHECK_WATCHDOG);
|
||||
|
||||
return;
|
||||
|
||||
done:
|
||||
/* Cannot perform scan. Make sure we clear scanning
|
||||
* bits from status so next scan request can be performed.
|
||||
* If we don't clear scanning status bit here all next scan
|
||||
* will fail
|
||||
*/
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
/* inform mac80211 scan aborted */
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
|
||||
|
@ -1673,6 +1781,8 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
|
|||
bt_cmd.kill_ack_mask = priv->kill_ack_mask;
|
||||
bt_cmd.kill_cts_mask = priv->kill_cts_mask;
|
||||
bt_cmd.valid = priv->bt_valid;
|
||||
bt_cmd.tx_prio_boost = 0;
|
||||
bt_cmd.rx_prio_boost = 0;
|
||||
|
||||
/*
|
||||
* Configure BT coex mode to "no coexistence" when the
|
||||
|
|
|
@ -453,15 +453,6 @@ static inline u8 first_antenna(u8 mask)
|
|||
}
|
||||
|
||||
|
||||
static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
|
||||
{
|
||||
u8 rate = iwl_rates[rate_index].prev_ieee;
|
||||
|
||||
if (rate == IWL_RATE_INVALID)
|
||||
rate = rate_index;
|
||||
return rate;
|
||||
}
|
||||
|
||||
static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
|
||||
{
|
||||
u8 rate = iwl3945_rates[rate_index].prev_ieee;
|
||||
|
|
|
@ -307,6 +307,17 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
|
|||
goto restart;
|
||||
}
|
||||
|
||||
if (priv->cfg->advanced_bt_coexist) {
|
||||
/*
|
||||
* Tell uCode we are ready to perform calibration
|
||||
* need to perform this before any calibration
|
||||
* no need to close the envlope since we are going
|
||||
* to load the runtime uCode later.
|
||||
*/
|
||||
iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
|
||||
}
|
||||
iwlagn_send_calib_cfg(priv);
|
||||
return;
|
||||
|
||||
|
@ -364,7 +375,7 @@ static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
|
|||
0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static void iwlagn_send_prio_tbl(struct iwl_priv *priv)
|
||||
void iwlagn_send_prio_tbl(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
|
||||
|
||||
|
@ -375,7 +386,7 @@ static void iwlagn_send_prio_tbl(struct iwl_priv *priv)
|
|||
IWL_ERR(priv, "failed to send BT prio tbl command\n");
|
||||
}
|
||||
|
||||
static void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
|
||||
void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
|
||||
{
|
||||
struct iwl_bt_coex_prot_env_cmd env_cmd;
|
||||
|
||||
|
@ -482,25 +493,6 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
|
|||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (priv->cfg->advanced_bt_coexist) {
|
||||
/* Configure Bluetooth device coexistence support */
|
||||
/* need to perform this before any calibration */
|
||||
priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
|
||||
priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
|
||||
priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
|
||||
priv->cfg->ops->hcmd->send_bt_config(priv);
|
||||
priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
|
||||
|
||||
if (bt_coex_active && priv->iw_mode != NL80211_IFTYPE_ADHOC) {
|
||||
iwlagn_send_prio_tbl(priv);
|
||||
iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
iwlagn_send_wimax_coex(priv);
|
||||
|
||||
iwlagn_set_Xtal_calib(priv);
|
||||
|
|
|
@ -110,6 +110,9 @@ int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
if (!iwl_is_alive(priv))
|
||||
return -EBUSY;
|
||||
|
||||
if (!ctx->is_active)
|
||||
return 0;
|
||||
|
||||
/* always get timestamp with Rx frame */
|
||||
ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
|
||||
|
||||
|
@ -223,9 +226,8 @@ int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
priv->start_calib = 0;
|
||||
if (new_assoc) {
|
||||
priv->start_calib = 0;
|
||||
/* Apply the new configuration
|
||||
* RXON assoc doesn't clear the station table in uCode,
|
||||
*/
|
||||
|
@ -369,7 +371,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
|
|||
|
||||
if (!priv->beacon_ctx) {
|
||||
IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize memory */
|
||||
|
@ -1278,7 +1280,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
|
|||
IWL_ERR(priv, "Microcode SW error detected. "
|
||||
" Restarting 0x%X.\n", inta);
|
||||
priv->isr_stats.sw++;
|
||||
priv->isr_stats.sw_err = inta;
|
||||
iwl_irq_handle_error(priv);
|
||||
handled |= CSR_INT_BIT_SW_ERR;
|
||||
}
|
||||
|
@ -1459,7 +1460,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|||
IWL_ERR(priv, "Microcode SW error detected. "
|
||||
" Restarting 0x%X.\n", inta);
|
||||
priv->isr_stats.sw++;
|
||||
priv->isr_stats.sw_err = inta;
|
||||
iwl_irq_handle_error(priv);
|
||||
handled |= CSR_INT_BIT_SW_ERR;
|
||||
}
|
||||
|
@ -2467,6 +2467,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
|||
}
|
||||
|
||||
desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
|
||||
priv->isr_stats.err_code = desc;
|
||||
pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
|
||||
blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
|
||||
blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
|
||||
|
@ -2813,6 +2814,22 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|||
if (iwl_is_rfkill(priv))
|
||||
return;
|
||||
|
||||
if (priv->cfg->advanced_bt_coexist) {
|
||||
/* Configure Bluetooth device coexistence support */
|
||||
priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
|
||||
priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
|
||||
priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
|
||||
priv->cfg->ops->hcmd->send_bt_config(priv);
|
||||
priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
|
||||
if (bt_coex_active && priv->iw_mode != NL80211_IFTYPE_ADHOC)
|
||||
iwlagn_send_prio_tbl(priv);
|
||||
|
||||
/* FIXME: w/a to force change uCode BT state machine */
|
||||
iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
}
|
||||
ieee80211_wake_queues(priv->hw);
|
||||
|
||||
priv->active_rate = IWL_RATES_MASK;
|
||||
|
@ -2875,8 +2892,9 @@ static void __iwl_down(struct iwl_priv *priv)
|
|||
|
||||
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
|
||||
|
||||
if (!exit_pending)
|
||||
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
iwl_scan_cancel_timeout(priv, 200);
|
||||
|
||||
exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
|
||||
/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
|
||||
* to prevent rearm timer */
|
||||
|
@ -3486,15 +3504,6 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
|
|||
|
||||
priv->is_open = 0;
|
||||
|
||||
if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
/* stop mac, cancel any scan request and clear
|
||||
* RXON_FILTER_ASSOC_MSK BIT
|
||||
*/
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
iwl_down(priv);
|
||||
|
||||
flush_workqueue(priv->workqueue);
|
||||
|
@ -4062,13 +4071,15 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
|||
priv->cfg->ops->lib->cancel_deferred_work(priv);
|
||||
|
||||
cancel_delayed_work_sync(&priv->init_alive_start);
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
cancel_work_sync(&priv->start_internal_scan);
|
||||
cancel_delayed_work(&priv->alive_start);
|
||||
cancel_work_sync(&priv->run_time_calib_work);
|
||||
cancel_work_sync(&priv->beacon_update);
|
||||
|
||||
iwl_cancel_scan_deferred_work(priv);
|
||||
|
||||
cancel_work_sync(&priv->bt_full_concurrency);
|
||||
cancel_work_sync(&priv->bt_runtime_config);
|
||||
|
||||
del_timer_sync(&priv->statistics_periodic);
|
||||
del_timer_sync(&priv->ucode_trace);
|
||||
}
|
||||
|
@ -4286,6 +4297,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
for (i = 0; i < NUM_IWL_RXON_CTX; i++)
|
||||
priv->contexts[i].ctxid = i;
|
||||
|
||||
priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
|
||||
priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
|
||||
priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
|
||||
priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
|
||||
priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
|
||||
|
|
|
@ -134,6 +134,8 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv,
|
|||
void iwlagn_init_alive_start(struct iwl_priv *priv);
|
||||
int iwlagn_alive_notify(struct iwl_priv *priv);
|
||||
int iwl_verify_ucode(struct iwl_priv *priv);
|
||||
void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
|
||||
void iwlagn_send_prio_tbl(struct iwl_priv *priv);
|
||||
|
||||
/* lib */
|
||||
void iwl_check_abort_status(struct iwl_priv *priv,
|
||||
|
@ -217,7 +219,7 @@ void iwl_reply_statistics(struct iwl_priv *priv,
|
|||
struct iwl_rx_mem_buffer *rxb);
|
||||
|
||||
/* scan */
|
||||
void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
|
||||
/* station mgmt */
|
||||
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
|
||||
|
@ -236,4 +238,9 @@ void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
|
|||
void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
|
||||
void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
const char *iwl_get_agg_tx_fail_reason(u16 status);
|
||||
#else
|
||||
static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; }
|
||||
#endif
|
||||
#endif /* __iwl_agn_h__ */
|
||||
|
|
|
@ -1820,13 +1820,8 @@ enum {
|
|||
TX_STATUS_FAIL_TID_DISABLE = 0x8d,
|
||||
TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
|
||||
TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
|
||||
/* uCode drop due to FW drop request */
|
||||
TX_STATUS_FAIL_FW_DROP = 0x90,
|
||||
/*
|
||||
* uCode drop due to station color mismatch
|
||||
* between tx command and station table
|
||||
*/
|
||||
TX_STATUS_FAIL_STA_COLOR_MISMATCH_DROP = 0x91,
|
||||
TX_STATUS_FAIL_PASSIVE_NO_RX = 0x90,
|
||||
TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
|
||||
};
|
||||
|
||||
#define TX_PACKET_MODE_REGULAR 0x0000
|
||||
|
@ -1868,6 +1863,9 @@ enum {
|
|||
AGG_TX_STATE_DELAY_TX_MSK = 0x400
|
||||
};
|
||||
|
||||
#define AGG_TX_STATUS_MSK 0x00000fff /* bits 0:11 */
|
||||
#define AGG_TX_TRY_MSK 0x0000f000 /* bits 12:15 */
|
||||
|
||||
#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
|
||||
AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
|
||||
AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
|
||||
|
@ -2488,7 +2486,12 @@ struct iwlagn_bt_cmd {
|
|||
__le16 bt4_decision_time; /* unused */
|
||||
__le16 valid;
|
||||
u8 prio_boost;
|
||||
u8 reserved[3];
|
||||
/*
|
||||
* set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
|
||||
* if configure the following patterns
|
||||
*/
|
||||
u8 tx_prio_boost; /* SW boost of WiFi tx priority */
|
||||
__le16 rx_prio_boost; /* SW boost of WiFi rx priority */
|
||||
};
|
||||
|
||||
#define IWLAGN_BT_SCO_ACTIVE cpu_to_le32(BIT(0))
|
||||
|
|
|
@ -196,6 +196,9 @@ static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (!ctx->is_active)
|
||||
return;
|
||||
|
||||
ctx->qos_data.def_qos_parm.qos_flags = 0;
|
||||
|
||||
if (ctx->qos_data.qos_active)
|
||||
|
@ -488,8 +491,29 @@ EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
|
|||
|
||||
static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
|
||||
{
|
||||
u16 new_val = 0;
|
||||
u16 beacon_factor = 0;
|
||||
u16 new_val;
|
||||
u16 beacon_factor;
|
||||
|
||||
/*
|
||||
* If mac80211 hasn't given us a beacon interval, program
|
||||
* the default into the device (not checking this here
|
||||
* would cause the adjustment below to return the maximum
|
||||
* value, which may break PAN.)
|
||||
*/
|
||||
if (!beacon_val)
|
||||
return DEFAULT_BEACON_INTERVAL;
|
||||
|
||||
/*
|
||||
* If the beacon interval we obtained from the peer
|
||||
* is too large, we'll have to wake up more often
|
||||
* (and in IBSS case, we'll beacon too much)
|
||||
*
|
||||
* For example, if max_beacon_val is 4096, and the
|
||||
* requested beacon interval is 7000, we'll have to
|
||||
* use 3500 to be able to wake up on the beacons.
|
||||
*
|
||||
* This could badly influence beacon detection stats.
|
||||
*/
|
||||
|
||||
beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
|
||||
new_val = beacon_val / beacon_factor;
|
||||
|
@ -526,10 +550,22 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
ctx->timing.atim_window = 0;
|
||||
|
||||
if (ctx->ctxid == IWL_RXON_CTX_PAN &&
|
||||
(!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION)) {
|
||||
(!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
|
||||
iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
|
||||
priv->contexts[IWL_RXON_CTX_BSS].vif &&
|
||||
priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
|
||||
ctx->timing.beacon_interval =
|
||||
priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
|
||||
beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
} else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
|
||||
iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
|
||||
priv->contexts[IWL_RXON_CTX_PAN].vif &&
|
||||
priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
|
||||
(!iwl_is_associated_ctx(ctx) || !ctx->vif ||
|
||||
!ctx->vif->bss_conf.beacon_int)) {
|
||||
ctx->timing.beacon_interval =
|
||||
priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
|
||||
beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
} else {
|
||||
beacon_int = iwl_adjust_beacon_interval(beacon_int,
|
||||
priv->hw_params.max_beacon_itrvl * TIME_UNIT);
|
||||
|
@ -1797,9 +1833,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
|||
priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
|
||||
}
|
||||
|
||||
if (changes & BSS_CHANGED_BEACON_INT) {
|
||||
/* TODO: in AP mode, do something to make this take effect */
|
||||
}
|
||||
if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP)
|
||||
iwl_send_rxon_timing(priv, ctx);
|
||||
|
||||
if (changes & BSS_CHANGED_BSSID) {
|
||||
IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
|
||||
|
@ -2009,9 +2044,14 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
*/
|
||||
priv->iw_mode = vif->type;
|
||||
|
||||
ctx->is_active = true;
|
||||
|
||||
err = iwl_set_mode(priv, vif);
|
||||
if (err)
|
||||
if (err) {
|
||||
if (!ctx->always_active)
|
||||
ctx->is_active = false;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (priv->cfg->advanced_bt_coexist &&
|
||||
vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
|
@ -2041,7 +2081,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
|
||||
bool scan_completed = false;
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||
|
||||
|
@ -2050,14 +2089,14 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
WARN_ON(ctx->vif != vif);
|
||||
ctx->vif = NULL;
|
||||
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
if (priv->scan_vif == vif) {
|
||||
iwl_scan_cancel_timeout(priv, 200);
|
||||
iwl_force_scan_end(priv);
|
||||
}
|
||||
iwl_set_mode(priv, vif);
|
||||
|
||||
if (priv->scan_vif == vif) {
|
||||
scan_completed = true;
|
||||
priv->scan_vif = NULL;
|
||||
priv->scan_request = NULL;
|
||||
}
|
||||
if (!ctx->always_active)
|
||||
ctx->is_active = false;
|
||||
|
||||
/*
|
||||
* When removing the IBSS interface, overwrite the
|
||||
|
@ -2072,9 +2111,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
memset(priv->bssid, 0, ETH_ALEN);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (scan_completed)
|
||||
ieee80211_scan_completed(priv->hw, true);
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
|
||||
}
|
||||
|
@ -2255,6 +2291,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
|
|||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
if (!iwl_is_ready_rf(priv)) {
|
||||
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
@ -2264,7 +2301,6 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
|
|||
/* we are restarting association process
|
||||
* clear RXON_FILTER_ASSOC_MSK bit
|
||||
*/
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
iwlcore_commit_rxon(priv, ctx);
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ struct iwl_hcmd_utils_ops {
|
|||
__le16 fc, __le32 *tx_flags);
|
||||
int (*calc_rssi)(struct iwl_priv *priv,
|
||||
struct iwl_rx_phy_res *rx_resp);
|
||||
void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
};
|
||||
|
||||
struct iwl_apm_ops {
|
||||
|
@ -130,6 +130,8 @@ struct iwl_debugfs_ops {
|
|||
size_t count, loff_t *ppos);
|
||||
ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
};
|
||||
|
||||
struct iwl_temp_ops {
|
||||
|
@ -553,6 +555,7 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
|
|||
void iwl_init_scan_params(struct iwl_priv *priv);
|
||||
int iwl_scan_cancel(struct iwl_priv *priv);
|
||||
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
|
||||
void iwl_force_scan_end(struct iwl_priv *priv);
|
||||
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
|
@ -568,6 +571,7 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
|
|||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
|
||||
void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
|
|
|
@ -575,10 +575,10 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
|
|||
priv->isr_stats.hw);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
|
||||
priv->isr_stats.sw);
|
||||
if (priv->isr_stats.sw > 0) {
|
||||
if (priv->isr_stats.sw || priv->isr_stats.hw) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tLast Restarting Code: 0x%X\n",
|
||||
priv->isr_stats.sw_err);
|
||||
priv->isr_stats.err_code);
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
|
||||
|
@ -1604,6 +1604,56 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
|
||||
int pos = 0;
|
||||
char buf[40];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "use %s for aggregation\n",
|
||||
(priv->cfg->use_rts_for_aggregation) ? "rts/cts" :
|
||||
"cts-to-self");
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int rts;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &rts) != 1)
|
||||
return -EINVAL;
|
||||
if (rts)
|
||||
priv->cfg->use_rts_for_aggregation = true;
|
||||
else
|
||||
priv->cfg->use_rts_for_aggregation = false;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
|
||||
if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error)
|
||||
return priv->cfg->ops->lib->debugfs_ops.reply_tx_error(
|
||||
file, user_buf, count, ppos);
|
||||
else
|
||||
return -ENODATA;
|
||||
}
|
||||
DEBUGFS_READ_FILE_OPS(rx_statistics);
|
||||
DEBUGFS_READ_FILE_OPS(tx_statistics);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
|
||||
|
@ -1629,6 +1679,8 @@ DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
|
|||
DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
|
||||
DEBUGFS_WRITE_FILE_OPS(monitor_period);
|
||||
DEBUGFS_READ_FILE_OPS(bt_traffic);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
|
||||
DEBUGFS_READ_FILE_OPS(reply_tx_error);
|
||||
|
||||
/*
|
||||
* Create the debugfs files and directories
|
||||
|
@ -1689,6 +1741,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
|||
DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
|
||||
if (priv->cfg->ops->lib->dev_txfifo_flush)
|
||||
DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
|
||||
|
||||
if (priv->cfg->sensitivity_calib_by_driver)
|
||||
DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
|
||||
|
@ -1698,6 +1751,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
|||
DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
|
||||
if (priv->cfg->bt_statistics)
|
||||
DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR);
|
||||
|
|
|
@ -945,7 +945,7 @@ enum iwl_pa_type {
|
|||
struct isr_statistics {
|
||||
u32 hw;
|
||||
u32 sw;
|
||||
u32 sw_err;
|
||||
u32 err_code;
|
||||
u32 sch;
|
||||
u32 alive;
|
||||
u32 rfkill;
|
||||
|
@ -957,6 +957,50 @@ struct isr_statistics {
|
|||
u32 unhandled;
|
||||
};
|
||||
|
||||
/* reply_tx_statistics (for _agn devices) */
|
||||
struct reply_tx_error_statistics {
|
||||
u32 pp_delay;
|
||||
u32 pp_few_bytes;
|
||||
u32 pp_bt_prio;
|
||||
u32 pp_quiet_period;
|
||||
u32 pp_calc_ttak;
|
||||
u32 int_crossed_retry;
|
||||
u32 short_limit;
|
||||
u32 long_limit;
|
||||
u32 fifo_underrun;
|
||||
u32 drain_flow;
|
||||
u32 rfkill_flush;
|
||||
u32 life_expire;
|
||||
u32 dest_ps;
|
||||
u32 host_abort;
|
||||
u32 bt_retry;
|
||||
u32 sta_invalid;
|
||||
u32 frag_drop;
|
||||
u32 tid_disable;
|
||||
u32 fifo_flush;
|
||||
u32 insuff_cf_poll;
|
||||
u32 fail_hw_drop;
|
||||
u32 sta_color_mismatch;
|
||||
u32 unknown;
|
||||
};
|
||||
|
||||
/* reply_agg_tx_statistics (for _agn devices) */
|
||||
struct reply_agg_tx_error_statistics {
|
||||
u32 underrun;
|
||||
u32 bt_prio;
|
||||
u32 few_bytes;
|
||||
u32 abort;
|
||||
u32 last_sent_ttl;
|
||||
u32 last_sent_try;
|
||||
u32 last_sent_bt_kill;
|
||||
u32 scd_query;
|
||||
u32 bad_crc32;
|
||||
u32 response;
|
||||
u32 dump_tx;
|
||||
u32 delay_tx;
|
||||
u32 unknown;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/* management statistics */
|
||||
enum iwl_mgmt_stats {
|
||||
|
@ -1116,6 +1160,13 @@ struct iwl_rxon_context {
|
|||
const u8 *ac_to_queue;
|
||||
u8 mcast_queue;
|
||||
|
||||
/*
|
||||
* We could use the vif to indicate active, but we
|
||||
* also need it to be active during disabling when
|
||||
* we already removed the vif for type setting.
|
||||
*/
|
||||
bool always_active, is_active;
|
||||
|
||||
enum iwl_rxon_context_id ctxid;
|
||||
|
||||
u32 interface_modes, exclusive_interface_modes;
|
||||
|
@ -1408,6 +1459,9 @@ struct iwl_priv {
|
|||
|
||||
struct iwl_notif_statistics statistics;
|
||||
struct iwl_bt_notif_statistics statistics_bt;
|
||||
/* counts reply_tx error */
|
||||
struct reply_tx_error_statistics reply_tx_stats;
|
||||
struct reply_agg_tx_error_statistics reply_agg_tx_stats;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
struct iwl_notif_statistics accum_statistics;
|
||||
struct iwl_notif_statistics delta_statistics;
|
||||
|
|
|
@ -54,82 +54,28 @@
|
|||
#define IWL_PASSIVE_DWELL_BASE (100)
|
||||
#define IWL_CHANNEL_TUNE_TIME 5
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* iwl_scan_cancel - Cancel any currently executing HW scan
|
||||
*
|
||||
* NOTE: priv->mutex is not required before calling this function
|
||||
*/
|
||||
int iwl_scan_cancel(struct iwl_priv *priv)
|
||||
{
|
||||
if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
if (!test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Queuing scan abort.\n");
|
||||
queue_work(priv->workqueue, &priv->abort_scan);
|
||||
|
||||
} else
|
||||
IWL_DEBUG_SCAN(priv, "Scan abort already in progress.\n");
|
||||
|
||||
return test_bit(STATUS_SCANNING, &priv->status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_scan_cancel);
|
||||
/**
|
||||
* iwl_scan_cancel_timeout - Cancel any currently executing HW scan
|
||||
* @ms: amount of time to wait (in milliseconds) for scan to abort
|
||||
*
|
||||
* NOTE: priv->mutex must be held before calling this function
|
||||
*/
|
||||
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
int ret;
|
||||
|
||||
ret = iwl_scan_cancel(priv);
|
||||
if (ret && ms) {
|
||||
mutex_unlock(&priv->mutex);
|
||||
while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
|
||||
test_bit(STATUS_SCANNING, &priv->status))
|
||||
msleep(1);
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
return test_bit(STATUS_SCANNING, &priv->status);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_scan_cancel_timeout);
|
||||
|
||||
static int iwl_send_scan_abort(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
struct iwl_rx_packet *pkt;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SCAN_ABORT_CMD,
|
||||
.flags = CMD_WANT_SKB,
|
||||
};
|
||||
|
||||
/* If there isn't a scan actively going on in the hardware
|
||||
* then we are in between scan bands and not actually
|
||||
* actively scanning, so don't send the abort command */
|
||||
if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
return 0;
|
||||
}
|
||||
/* Exit instantly with error when device is not ready
|
||||
* to receive scan abort command or it does not perform
|
||||
* hardware scan currently */
|
||||
if (!test_bit(STATUS_READY, &priv->status) ||
|
||||
!test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
|
||||
!test_bit(STATUS_SCAN_HW, &priv->status) ||
|
||||
test_bit(STATUS_FW_ERROR, &priv->status) ||
|
||||
test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EIO;
|
||||
|
||||
ret = iwl_send_cmd_sync(priv, &cmd);
|
||||
if (ret) {
|
||||
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pkt = (struct iwl_rx_packet *)cmd.reply_page;
|
||||
if (pkt->u.status != CAN_ABORT_STATUS) {
|
||||
|
@ -139,16 +85,104 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
|
|||
* can occur if we send the scan abort before we
|
||||
* the microcode has notified us that a scan is
|
||||
* completed. */
|
||||
IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status);
|
||||
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
iwl_free_pages(priv, cmd.reply_page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
|
||||
{
|
||||
/* check if scan was requested from mac80211 */
|
||||
if (priv->scan_request) {
|
||||
IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
|
||||
ieee80211_scan_completed(priv->hw, aborted);
|
||||
}
|
||||
|
||||
priv->is_internal_short_scan = false;
|
||||
priv->scan_vif = NULL;
|
||||
priv->scan_request = NULL;
|
||||
}
|
||||
|
||||
void iwl_force_scan_end(struct iwl_priv *priv)
|
||||
{
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
|
||||
return;
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
iwl_complete_scan(priv, true);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_force_scan_end);
|
||||
|
||||
static void iwl_do_scan_abort(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = iwl_send_scan_abort(priv);
|
||||
if (ret) {
|
||||
IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
|
||||
iwl_force_scan_end(priv);
|
||||
} else
|
||||
IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_scan_cancel - Cancel any currently executing HW scan
|
||||
*/
|
||||
int iwl_scan_cancel(struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
|
||||
queue_work(priv->workqueue, &priv->abort_scan);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_scan_cancel);
|
||||
|
||||
/**
|
||||
* iwl_scan_cancel_timeout - Cancel any currently executing HW scan
|
||||
* @ms: amount of time to wait (in milliseconds) for scan to abort
|
||||
*
|
||||
*/
|
||||
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(ms);
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
|
||||
|
||||
iwl_do_scan_abort(priv);
|
||||
|
||||
while (time_before_eq(jiffies, timeout)) {
|
||||
if (!test_bit(STATUS_SCAN_HW, &priv->status))
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
return test_bit(STATUS_SCAN_HW, &priv->status);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_scan_cancel_timeout);
|
||||
|
||||
/* Service response to REPLY_SCAN_CMD (0x80) */
|
||||
static void iwl_rx_reply_scan(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
|
@ -158,7 +192,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
|
|||
struct iwl_scanreq_notification *notif =
|
||||
(struct iwl_scanreq_notification *)pkt->u.raw;
|
||||
|
||||
IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status);
|
||||
IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -217,26 +251,16 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
|
|||
/* The HW is no longer scanning */
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n",
|
||||
IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
|
||||
(priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
|
||||
jiffies_to_msecs(elapsed_jiffies
|
||||
(priv->scan_start, jiffies)));
|
||||
|
||||
/*
|
||||
* If a request to abort was given, or the scan did not succeed
|
||||
* then we reset the scan state machine and terminate,
|
||||
* re-queuing another scan if one has been requested
|
||||
*/
|
||||
if (test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status))
|
||||
IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Setting scan to off\n");
|
||||
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
|
||||
if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
|
||||
priv->cfg->advanced_bt_coexist && priv->bt_status !=
|
||||
scan_notif->bt_status) {
|
||||
priv->cfg->advanced_bt_coexist &&
|
||||
priv->bt_status != scan_notif->bt_status) {
|
||||
if (scan_notif->bt_status) {
|
||||
/* BT on */
|
||||
if (!priv->bt_ch_announce)
|
||||
|
@ -254,7 +278,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
|
|||
priv->bt_status = scan_notif->bt_status;
|
||||
queue_work(priv->workqueue, &priv->bt_traffic_change_work);
|
||||
}
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
}
|
||||
|
||||
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
|
||||
|
@ -324,19 +347,53 @@ void iwl_init_scan_params(struct iwl_priv *priv)
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_init_scan_params);
|
||||
|
||||
static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||
static int __must_check iwl_scan_initiate(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
bool internal,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
int ret;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Starting scan...\n");
|
||||
set_bit(STATUS_SCANNING, &priv->status);
|
||||
priv->is_internal_short_scan = false;
|
||||
priv->scan_start = jiffies;
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (WARN_ON(!priv->cfg->ops->utils->request_scan))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
priv->cfg->ops->utils->request_scan(priv, vif);
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
|
||||
if (!iwl_is_ready_rf(priv)) {
|
||||
IWL_WARN(priv, "Request scan called when driver not ready.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"Multiple concurrent scan requests in parallel.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
|
||||
internal ? "internal short " : "");
|
||||
|
||||
set_bit(STATUS_SCANNING, &priv->status);
|
||||
priv->is_internal_short_scan = internal;
|
||||
priv->scan_start = jiffies;
|
||||
priv->scan_band = band;
|
||||
|
||||
ret = priv->cfg->ops->utils->request_scan(priv, vif);
|
||||
if (ret) {
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
priv->is_internal_short_scan = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
queue_delayed_work(priv->workqueue, &priv->scan_check,
|
||||
IWL_SCAN_CHECK_WATCHDOG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -355,12 +412,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (!iwl_is_ready_rf(priv)) {
|
||||
ret = -EIO;
|
||||
IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCANNING, &priv->status) &&
|
||||
!priv->is_internal_short_scan) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
|
||||
|
@ -368,14 +419,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* mac80211 will only ask for one band at a time */
|
||||
priv->scan_band = req->channels[0]->band;
|
||||
priv->scan_request = req;
|
||||
priv->scan_vif = vif;
|
||||
|
||||
|
@ -383,10 +427,12 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
|||
* If an internal scan is in progress, just set
|
||||
* up the scan_request as per above.
|
||||
*/
|
||||
if (priv->is_internal_short_scan)
|
||||
if (priv->is_internal_short_scan) {
|
||||
IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
|
||||
ret = 0;
|
||||
else
|
||||
ret = iwl_scan_initiate(priv, vif);
|
||||
} else
|
||||
ret = iwl_scan_initiate(priv, vif, false,
|
||||
req->channels[0]->band);
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
|
||||
|
@ -411,6 +457,8 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
|
|||
struct iwl_priv *priv =
|
||||
container_of(work, struct iwl_priv, start_internal_scan);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Start internal scan\n");
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (priv->is_internal_short_scan == true) {
|
||||
|
@ -418,31 +466,13 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
if (!iwl_is_ready_rf(priv)) {
|
||||
IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
priv->scan_band = priv->band;
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
|
||||
set_bit(STATUS_SCANNING, &priv->status);
|
||||
priv->is_internal_short_scan = true;
|
||||
|
||||
if (WARN_ON(!priv->cfg->ops->utils->request_scan))
|
||||
goto unlock;
|
||||
|
||||
priv->cfg->ops->utils->request_scan(priv, NULL);
|
||||
if (iwl_scan_initiate(priv, NULL, true, priv->band))
|
||||
IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
|
||||
unlock:
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
@ -452,18 +482,13 @@ static void iwl_bg_scan_check(struct work_struct *data)
|
|||
struct iwl_priv *priv =
|
||||
container_of(data, struct iwl_priv, scan_check.work);
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
IWL_DEBUG_SCAN(priv, "Scan check work\n");
|
||||
|
||||
/* Since we are here firmware does not finish scan and
|
||||
* most likely is in bad shape, so we don't bother to
|
||||
* send abort command, just force scan complete to mac80211 */
|
||||
mutex_lock(&priv->mutex);
|
||||
if (test_bit(STATUS_SCANNING, &priv->status) &&
|
||||
!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan completion watchdog (%dms)\n",
|
||||
jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
|
||||
|
||||
if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
iwl_send_scan_abort(priv);
|
||||
}
|
||||
iwl_force_scan_end(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
|
@ -519,15 +544,12 @@ static void iwl_bg_abort_scan(struct work_struct *work)
|
|||
{
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
|
||||
|
||||
if (!test_bit(STATUS_READY, &priv->status) ||
|
||||
!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
|
||||
return;
|
||||
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
IWL_DEBUG_SCAN(priv, "Abort scan work\n");
|
||||
|
||||
/* We keep scan_check work queued in case when firmware will not
|
||||
* report back scan completed notification */
|
||||
mutex_lock(&priv->mutex);
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status))
|
||||
iwl_send_scan_abort(priv);
|
||||
iwl_scan_cancel_timeout(priv, 200);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
|
@ -535,30 +557,52 @@ static void iwl_bg_scan_completed(struct work_struct *work)
|
|||
{
|
||||
struct iwl_priv *priv =
|
||||
container_of(work, struct iwl_priv, scan_completed);
|
||||
bool internal = false;
|
||||
bool scan_completed = false;
|
||||
bool aborted;
|
||||
struct iwl_rxon_context *ctx;
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
|
||||
IWL_DEBUG_SCAN(priv, "Completed %sscan.\n",
|
||||
priv->is_internal_short_scan ? "internal short " : "");
|
||||
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
if (priv->is_internal_short_scan) {
|
||||
priv->is_internal_short_scan = false;
|
||||
IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
|
||||
internal = true;
|
||||
} else if (priv->scan_request) {
|
||||
scan_completed = true;
|
||||
priv->scan_request = NULL;
|
||||
priv->scan_vif = NULL;
|
||||
|
||||
aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
if (aborted)
|
||||
IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
|
||||
|
||||
if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
|
||||
goto out_settings;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
goto out;
|
||||
if (priv->is_internal_short_scan && !aborted) {
|
||||
int err;
|
||||
|
||||
if (internal && priv->scan_request)
|
||||
iwl_scan_initiate(priv, priv->scan_vif);
|
||||
/* Check if mac80211 requested scan during our internal scan */
|
||||
if (priv->scan_request == NULL)
|
||||
goto out_complete;
|
||||
|
||||
/* If so request a new scan */
|
||||
err = iwl_scan_initiate(priv, priv->scan_vif, false,
|
||||
priv->scan_request->channels[0]->band);
|
||||
if (err) {
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"failed to initiate pending scan: %d\n", err);
|
||||
aborted = true;
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_complete:
|
||||
iwl_complete_scan(priv, aborted);
|
||||
|
||||
out_settings:
|
||||
/* Can we still talk to firmware ? */
|
||||
if (!iwl_is_ready_rf(priv))
|
||||
goto out;
|
||||
|
||||
/* Since setting the TXPOWER may have been deferred while
|
||||
* performing the scan, fire one off */
|
||||
|
@ -571,19 +615,11 @@ static void iwl_bg_scan_completed(struct work_struct *work)
|
|||
for_each_context(priv, ctx)
|
||||
iwlcore_commit_rxon(priv, ctx);
|
||||
|
||||
out:
|
||||
if (priv->cfg->ops->hcmd->set_pan_params)
|
||||
priv->cfg->ops->hcmd->set_pan_params(priv);
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
/*
|
||||
* Do not hold mutex here since this will cause mac80211 to call
|
||||
* into driver again into functions that will attempt to take
|
||||
* mutex.
|
||||
*/
|
||||
if (scan_completed)
|
||||
ieee80211_scan_completed(priv->hw, false);
|
||||
}
|
||||
|
||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
|
||||
|
@ -595,3 +631,16 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_setup_scan_deferred_work);
|
||||
|
||||
void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
cancel_work_sync(&priv->start_internal_scan);
|
||||
cancel_work_sync(&priv->abort_scan);
|
||||
cancel_work_sync(&priv->scan_completed);
|
||||
|
||||
if (cancel_delayed_work_sync(&priv->scan_check)) {
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_force_scan_end(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_cancel_scan_deferred_work);
|
||||
|
|
|
@ -386,7 +386,8 @@ static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
|
|||
{
|
||||
int i, r;
|
||||
struct iwl_link_quality_cmd *link_cmd;
|
||||
u32 rate_flags;
|
||||
u32 rate_flags = 0;
|
||||
__le32 rate_n_flags;
|
||||
|
||||
link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
|
||||
if (!link_cmd) {
|
||||
|
@ -400,18 +401,14 @@ static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
|
|||
else
|
||||
r = IWL_RATE_1M_INDEX;
|
||||
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
|
||||
rate_flags = 0;
|
||||
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
|
||||
rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
|
||||
RATE_MCS_ANT_POS;
|
||||
|
||||
link_cmd->rs_table[i].rate_n_flags =
|
||||
iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
|
||||
r = iwl_get_prev_ieee_rate(r);
|
||||
}
|
||||
rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
|
||||
|
||||
link_cmd->general_params.single_stream_ant_msk =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
|
|
|
@ -666,8 +666,8 @@ const char *iwl_get_tx_fail_reason(u32 status)
|
|||
TX_STATUS_FAIL(TID_DISABLE);
|
||||
TX_STATUS_FAIL(FIFO_FLUSHED);
|
||||
TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
|
||||
TX_STATUS_FAIL(FW_DROP);
|
||||
TX_STATUS_FAIL(STA_COLOR_MISMATCH_DROP);
|
||||
TX_STATUS_FAIL(PASSIVE_NO_RX);
|
||||
TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
|
|
|
@ -1730,7 +1730,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
|||
IWL_ERR(priv, "Microcode SW error detected. "
|
||||
"Restarting 0x%X.\n", inta);
|
||||
priv->isr_stats.sw++;
|
||||
priv->isr_stats.sw_err = inta;
|
||||
iwl_irq_handle_error(priv);
|
||||
handled |= CSR_INT_BIT_SW_ERR;
|
||||
}
|
||||
|
@ -2568,15 +2567,13 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv);
|
|||
static void __iwl3945_down(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
int exit_pending;
|
||||
|
||||
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
iwl_scan_cancel_timeout(priv, 200);
|
||||
|
||||
if (!exit_pending)
|
||||
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
|
||||
/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
|
||||
* to prevent rearm timer */
|
||||
|
@ -2820,7 +2817,7 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
|
|||
|
||||
}
|
||||
|
||||
void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||
int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SCAN_CMD,
|
||||
|
@ -2828,61 +2825,19 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
struct iwl3945_scan_cmd *scan;
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
u8 n_probes = 0;
|
||||
enum ieee80211_band band;
|
||||
bool is_active = false;
|
||||
int ret;
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
|
||||
if (!iwl_is_ready(priv)) {
|
||||
IWL_WARN(priv, "request scan called when driver not ready.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Make sure the scan wasn't canceled before this queued work
|
||||
* was given the chance to run... */
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status))
|
||||
goto done;
|
||||
|
||||
/* This should never be called or scheduled if there is currently
|
||||
* a scan active in the hardware. */
|
||||
if (test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests "
|
||||
"Ignoring second request.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_HC(priv,
|
||||
"Scan request while abort pending. Queuing.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (iwl_is_rfkill(priv)) {
|
||||
IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!test_bit(STATUS_READY, &priv->status)) {
|
||||
IWL_DEBUG_HC(priv,
|
||||
"Scan request while uninitialized. Queuing.\n");
|
||||
goto done;
|
||||
}
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (!priv->scan_cmd) {
|
||||
priv->scan_cmd = kmalloc(sizeof(struct iwl3945_scan_cmd) +
|
||||
IWL_MAX_SCAN_SIZE, GFP_KERNEL);
|
||||
if (!priv->scan_cmd) {
|
||||
IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n");
|
||||
goto done;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
scan = priv->scan_cmd;
|
||||
|
@ -2977,7 +2932,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
break;
|
||||
default:
|
||||
IWL_WARN(priv, "Invalid scan band\n");
|
||||
goto done;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!priv->is_internal_short_scan) {
|
||||
|
@ -3012,7 +2967,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
|
||||
if (scan->channel_count == 0) {
|
||||
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
|
||||
goto done;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
|
||||
|
@ -3021,25 +2976,10 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
scan->len = cpu_to_le16(cmd.len);
|
||||
|
||||
set_bit(STATUS_SCAN_HW, &priv->status);
|
||||
if (iwl_send_cmd_sync(priv, &cmd))
|
||||
goto done;
|
||||
|
||||
queue_delayed_work(priv->workqueue, &priv->scan_check,
|
||||
IWL_SCAN_CHECK_WATCHDOG);
|
||||
|
||||
return;
|
||||
|
||||
done:
|
||||
/* can not perform scan make sure we clear scanning
|
||||
* bits from status so next scan request can be performed.
|
||||
* if we dont clear scanning status bit here all next scan
|
||||
* will fail
|
||||
*/
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
|
||||
/* inform mac80211 scan aborted */
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
ret = iwl_send_cmd_sync(priv, &cmd);
|
||||
if (ret)
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl3945_bg_restart(struct work_struct *data)
|
||||
|
@ -3233,15 +3173,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
|
|||
|
||||
priv->is_open = 0;
|
||||
|
||||
if (iwl_is_ready_rf(priv)) {
|
||||
/* stop mac, cancel any scan request and clear
|
||||
* RXON_FILTER_ASSOC_MSK BIT
|
||||
*/
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_scan_cancel_timeout(priv, 100);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
iwl3945_down(priv);
|
||||
|
||||
flush_workqueue(priv->workqueue);
|
||||
|
@ -3831,10 +3762,10 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
|
|||
iwl3945_hw_cancel_deferred_work(priv);
|
||||
|
||||
cancel_delayed_work_sync(&priv->init_alive_start);
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
cancel_delayed_work(&priv->alive_start);
|
||||
cancel_work_sync(&priv->start_internal_scan);
|
||||
cancel_work_sync(&priv->beacon_update);
|
||||
|
||||
iwl_cancel_scan_deferred_work(priv);
|
||||
}
|
||||
|
||||
static struct attribute *iwl3945_sysfs_entries[] = {
|
||||
|
|
|
@ -481,7 +481,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
|||
struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
|
||||
int bsssize;
|
||||
const u8 *pos;
|
||||
u16 nr_sets;
|
||||
const u8 *tsfdesc;
|
||||
int tsfsize;
|
||||
int i;
|
||||
|
@ -490,12 +489,11 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
|||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
|
||||
nr_sets = le16_to_cpu(scanresp->nr_sets);
|
||||
|
||||
lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n",
|
||||
nr_sets, bsssize, le16_to_cpu(resp->size));
|
||||
scanresp->nr_sets, bsssize, le16_to_cpu(resp->size));
|
||||
|
||||
if (nr_sets == 0) {
|
||||
if (scanresp->nr_sets == 0) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -574,7 +574,7 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
|
|||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
|
||||
cmd.id = !!inverted;
|
||||
cmd.id = cpu_to_le32(!!inverted);
|
||||
|
||||
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue