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

This commit is contained in:
David S. Miller 2010-09-21 18:17:19 -07:00
commit a0741ca949
155 changed files with 17206 additions and 3270 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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();
}

View File

@ -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/

View File

@ -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";

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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,

View File

@ -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

View File

@ -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) \

View File

@ -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))

View File

@ -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
*

View File

@ -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 */

View File

@ -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));
/*

View File

@ -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===*/

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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] =

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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 */
/***********************************/

View File

@ -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 */

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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 */
/********************/

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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, &reg, 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);
}

View File

@ -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 */

View File

@ -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", &reg, &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", &reg, &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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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"

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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__ */

View File

@ -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))

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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";

View File

@ -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[] = {

View File

@ -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;
}

View File

@ -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