提交 b618f6f8 编写于 作者: J John W. Linville

Merge branch 'master' of...

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

Conflicts:
	arch/arm/mach-omap2/board-omap3pandora.c
	drivers/net/wireless/ath/ath5k/base.c
......@@ -1120,6 +1120,13 @@ W: http://wireless.kernel.org/en/users/Drivers/ar9170
S: Maintained
F: drivers/net/wireless/ath/ar9170/
CARL9170 LINUX COMMUNITY WIRELESS DRIVER
M: Christian Lamparter <chunkeey@googlemail.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/carl9170
S: Maintained
F: drivers/net/wireless/ath/carl9170/
ATK0110 HWMON DRIVER
M: Luca Tettamanti <kronos.it@gmail.com>
L: lm-sensors@lm-sensors.org
......@@ -6427,7 +6434,7 @@ W: http://wireless.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/wl12xx/wl1271*
F: include/linux/spi/wl12xx.h
F: include/linux/wl12xx.h
WL3501 WIRELESS PCMCIA CARD DRIVER
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
......
......@@ -25,7 +25,7 @@
#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
#include <linux/spi/wl12xx.h>
#include <linux/wl12xx.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/leds.h>
......
......@@ -14,7 +14,7 @@
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
#include <linux/spi/wl12xx.h>
#include <linux/wl12xx.h>
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#include <linux/clk.h>
......
......@@ -16,6 +16,8 @@
#include <linux/gpio.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
#include <linux/wl12xx.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
......@@ -27,6 +29,9 @@
#include "mux.h"
#include "hsmmc.h"
#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
/* Zoom2 has Qwerty keyboard*/
static int board_keymap[] = {
KEY(0, 0, KEY_E),
......@@ -106,6 +111,11 @@ static struct regulator_consumer_supply zoom_vmmc2_supply = {
.supply = "vmmc",
};
static struct regulator_consumer_supply zoom_vmmc3_supply = {
.supply = "vmmc",
.dev_name = "mmci-omap-hs.2",
};
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data zoom_vmmc1 = {
.constraints = {
......@@ -151,6 +161,38 @@ static struct regulator_init_data zoom_vsim = {
.consumer_supplies = &zoom_vsim_supply,
};
static struct regulator_init_data zoom_vmmc3 = {
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &zoom_vmmc3_supply,
};
static struct fixed_voltage_config zoom_vwlan = {
.supply_name = "vwl1271",
.microvolts = 1800000, /* 1.8V */
.gpio = OMAP_ZOOM_WLAN_PMENA_GPIO,
.startup_delay = 70000, /* 70msec */
.enable_high = 1,
.enabled_at_boot = 0,
.init_data = &zoom_vmmc3,
};
static struct platform_device omap_vwlan_device = {
.name = "reg-fixed-voltage",
.id = 1,
.dev = {
.platform_data = &zoom_vwlan,
},
};
struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
.irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
/* ZOOM ref clock is 26 MHz */
.board_ref_clock = 1,
};
static struct omap2_hsmmc_info mmc[] __initdata = {
{
.name = "external",
......@@ -168,6 +210,14 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.nonremovable = true,
.power_saving = true,
},
{
.name = "wl1271",
.mmc = 3,
.wires = 4,
.gpio_wp = -EINVAL,
.gpio_cd = -EINVAL,
.nonremovable = true,
},
{} /* Terminator */
};
......@@ -279,7 +329,11 @@ static void enable_board_wakeup_source(void)
void __init zoom_peripherals_init(void)
{
if (wl12xx_set_platform_data(&omap_zoom_wlan_data))
pr_err("error setting wl12xx data\n");
omap_i2c_init();
platform_device_register(&omap_vwlan_device);
usb_musb_init(&musb_board_data);
enable_board_wakeup_source();
}
......@@ -50,5 +50,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL12XX) += wl12xx/
# small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/wl12xx_platform_data.o
obj-$(CONFIG_IWM) += iwmc3200wifi/
......@@ -105,7 +105,7 @@ static struct pci_driver airo_driver = {
of statistics in the /proc filesystem */
#define IGNLABEL(comment) NULL
static char *statsLabels[] = {
static const char *statsLabels[] = {
"RxOverrun",
IGNLABEL("RxPlcpCrcErr"),
IGNLABEL("RxPlcpFormatErr"),
......@@ -932,7 +932,7 @@ typedef struct aironet_ioctl {
unsigned char __user *data; // d-data
} aironet_ioctl;
static char swversion[] = "2.1";
static const char swversion[] = "2.1";
#endif /* CISCO_EXT */
#define NUM_MODULES 2
......@@ -1374,7 +1374,7 @@ static int micsetup(struct airo_info *ai) {
return SUCCESS;
}
static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
static const u8 micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
/*===========================================================================
* Description: Mic a packet
......@@ -5023,7 +5023,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file)
airo_config_commit(dev, NULL, NULL, NULL);
}
static char *get_rmode(__le16 mode)
static const char *get_rmode(__le16 mode)
{
switch(mode & RXMODE_MASK) {
case RXMODE_RFMON: return "rfmon";
......
......@@ -25,5 +25,6 @@ config ATH_DEBUG
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/ar9170/Kconfig"
source "drivers/net/wireless/ath/carl9170/Kconfig"
endif
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_AR9170_USB) += ar9170/
obj-$(CONFIG_CARL9170) += carl9170/
obj-$(CONFIG_ATH_COMMON) += ath.o
ath-objs := main.o \
regd.o \
hw.o
hw.o \
key.o
ath-$(CONFIG_ATH_DEBUG) += debug.o
......@@ -71,6 +71,32 @@ struct ath_regulatory {
struct reg_dmn_pair_mapping *regpair;
};
enum ath_crypt_caps {
ATH_CRYPT_CAP_CIPHER_AESCCM = BIT(0),
ATH_CRYPT_CAP_MIC_COMBINED = BIT(1),
};
struct ath_keyval {
u8 kv_type;
u8 kv_pad;
u16 kv_len;
u8 kv_val[16]; /* TK */
u8 kv_mic[8]; /* Michael MIC key */
u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
* supports both MIC keys in the same key cache entry;
* in that case, kv_mic is the RX key) */
};
enum ath_cipher {
ATH_CIPHER_WEP = 0,
ATH_CIPHER_AES_OCB = 1,
ATH_CIPHER_AES_CCM = 2,
ATH_CIPHER_CKIP = 3,
ATH_CIPHER_TKIP = 4,
ATH_CIPHER_CLR = 5,
ATH_CIPHER_MIC = 127
};
/**
* struct ath_ops - Register read/write operations
*
......@@ -120,7 +146,7 @@ struct ath_common {
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
u8 splitmic;
enum ath_crypt_caps crypt_caps;
struct ath_regulatory regulatory;
const struct ath_ops *ops;
......@@ -132,5 +158,11 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
gfp_t gfp_mask);
void ath_hw_setbssidmask(struct ath_common *common);
void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
int ath_key_config(struct ath_common *common,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
bool ath_hw_keyreset(struct ath_common *common, u16 entry);
#endif /* ATH_H */
......@@ -206,6 +206,8 @@
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */
#define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */
#define AR5K_INIT_CARR_SENSE_EN 1
/*Swap RX/TX Descriptor for big endian archs*/
......@@ -256,8 +258,6 @@
(AR5K_INIT_PROG_IFS_TURBO) \
)
/* token to use for aifs, cwmin, cwmax in MadWiFi */
#define AR5K_TXQ_USEDEFAULT ((u32) -1)
/* GENERIC CHIPSET DEFINITIONS */
......@@ -528,9 +528,9 @@ struct ath5k_txq_info {
enum ath5k_tx_queue tqi_type;
enum ath5k_tx_queue_subtype tqi_subtype;
u16 tqi_flags; /* Tx queue flags (see above) */
u32 tqi_aifs; /* Arbitrated Interframe Space */
s32 tqi_cw_min; /* Minimum Contention Window */
s32 tqi_cw_max; /* Maximum Contention Window */
u8 tqi_aifs; /* Arbitrated Interframe Space */
u16 tqi_cw_min; /* Minimum Contention Window */
u16 tqi_cw_max; /* Maximum Contention Window */
u32 tqi_cbr_period; /* Constant bit rate period */
u32 tqi_cbr_overflow_limit;
u32 tqi_burst_time;
......@@ -1028,8 +1028,6 @@ struct ath5k_hw {
bool ah_turbo;
bool ah_calibration;
bool ah_single_chip;
bool ah_aes_support;
bool ah_combined_mic;
enum ath5k_version ah_version;
enum ath5k_radio ah_radio;
......@@ -1044,9 +1042,6 @@ struct ath5k_hw {
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
u32 ah_atim_window;
u32 ah_aifs;
u32 ah_cw_min;
u32 ah_cw_max;
u32 ah_limit_tx_retries;
u8 ah_coverage_class;
......@@ -1207,11 +1202,6 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah);
/* Key table (WEP) functions */
int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
const struct ieee80211_key_conf *key, const u8 *mac);
int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
/* Queue Control Unit, DFS Control Unit Functions */
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
......
......@@ -119,8 +119,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_imr = 0;
ah->ah_atim_window = 0;
ah->ah_aifs = AR5K_TUNE_AIFS;
ah->ah_cw_min = AR5K_TUNE_CWMIN;
ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
ah->ah_software_retry = false;
ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
......@@ -314,12 +312,16 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
}
/* Crypto settings */
ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
!AR5K_EEPROM_AES_DIS(ee->ee_misc5));
common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
if (srev >= AR5K_SREV_AR5212_V4 &&
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
!AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
if (srev >= AR5K_SREV_AR2414) {
ah->ah_combined_mic = true;
common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
AR5K_MISC_MODE_COMBINED_MIC);
}
......
......@@ -60,6 +60,9 @@
#define ATH_TXBUF 200 /* number of TX buffers */
#define ATH_BCBUF 1 /* number of beacon buffers */
#define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */
#define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */
struct ath5k_buf {
struct list_head list;
struct ath5k_desc *desc; /* virtual addr of desc */
......@@ -83,6 +86,9 @@ struct ath5k_txq {
struct list_head q; /* transmit queue */
spinlock_t lock; /* lock on q and link */
bool setup;
int txq_len; /* number of queued buffers */
bool txq_poll_mark;
unsigned int txq_stuck; /* informational counter */
};
#define ATH5K_LED_MAX_NAME_LEN 31
......@@ -204,7 +210,6 @@ struct ath5k_softc {
spinlock_t txbuflock;
unsigned int txbuf_len; /* buf count in txbuf list */
struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
......@@ -230,6 +235,8 @@ struct ath5k_softc {
struct ath5k_ani_state ani_state;
struct tasklet_struct ani_tasklet; /* ANI calibration */
struct delayed_work tx_complete_work;
};
#define ath5k_hw_hasbssidmask(_ah) \
......
......@@ -763,7 +763,7 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
struct ath5k_txq *txq;
struct ath5k_buf *bf, *bf0;
int i, n = 0;
int i, n;
len += snprintf(buf+len, sizeof(buf)-len,
"available txbuffers: %d\n", sc->txbuf_len);
......@@ -777,9 +777,16 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
if (!txq->setup)
continue;
n = 0;
spin_lock_bh(&txq->lock);
list_for_each_entry_safe(bf, bf0, &txq->q, list)
n++;
len += snprintf(buf+len, sizeof(buf)-len, " len: %d\n", n);
spin_unlock_bh(&txq->lock);
len += snprintf(buf+len, sizeof(buf)-len,
" len: %d bufs: %d\n", txq->txq_len, n);
len += snprintf(buf+len, sizeof(buf)-len,
" stuck: %d\n", txq->txq_stuck);
}
if (len > sizeof(buf))
......
......@@ -640,197 +640,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
}
/*********************\
* Key table functions *
\*********************/
/*
* Reset a key entry on the table
*/
int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
{
unsigned int i, type;
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
/* Reset associated MIC entry if TKIP
* is enabled located at offset (entry + 64) */
if (type == AR5K_KEYTABLE_TYPE_TKIP) {
AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
ath5k_hw_reg_write(ah, 0,
AR5K_KEYTABLE_OFF(micentry, i));
}
/*
* Set NULL encryption on AR5212+
*
* Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
* AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
*
* Note2: Windows driver (ndiswrapper) sets this to
* 0x00000714 instead of 0x00000007
*/
if (ah->ah_version >= AR5K_AR5211) {
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
AR5K_KEYTABLE_TYPE(entry));
if (type == AR5K_KEYTABLE_TYPE_TKIP) {
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
AR5K_KEYTABLE_TYPE(micentry));
}
}
return 0;
}
static
int ath5k_keycache_type(const struct ieee80211_key_conf *key)
{
switch (key->cipher) {
case WLAN_CIPHER_SUITE_TKIP:
return AR5K_KEYTABLE_TYPE_TKIP;
case WLAN_CIPHER_SUITE_CCMP:
return AR5K_KEYTABLE_TYPE_CCM;
case WLAN_CIPHER_SUITE_WEP40:
return AR5K_KEYTABLE_TYPE_40;
case WLAN_CIPHER_SUITE_WEP104:
return AR5K_KEYTABLE_TYPE_104;
default:
return -EINVAL;
}
}
/*
* Set a key entry on the table
*/
int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
const struct ieee80211_key_conf *key, const u8 *mac)
{
unsigned int i;
int keylen;
__le32 key_v[5] = {};
__le32 key0 = 0, key1 = 0;
__le32 *rxmic, *txmic;
int keytype;
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
bool is_tkip;
const u8 *key_ptr;
is_tkip = (key->cipher == WLAN_CIPHER_SUITE_TKIP);
/*
* key->keylen comes in from mac80211 in bytes.
* TKIP is 128 bit + 128 bit mic
*/
keylen = (is_tkip) ? (128 / 8) : key->keylen;
if (entry > AR5K_KEYTABLE_SIZE ||
(is_tkip && micentry > AR5K_KEYTABLE_SIZE))
return -EOPNOTSUPP;
if (unlikely(keylen > 16))
return -EOPNOTSUPP;
keytype = ath5k_keycache_type(key);
if (keytype < 0)
return keytype;
/*
* each key block is 6 bytes wide, written as pairs of
* alternating 32 and 16 bit le values.
*/
key_ptr = key->key;
for (i = 0; keylen >= 6; keylen -= 6) {
memcpy(&key_v[i], key_ptr, 6);
i += 2;
key_ptr += 6;
}
if (keylen)
memcpy(&key_v[i], key_ptr, keylen);
/* intentionally corrupt key until mic is installed */
if (is_tkip) {
key0 = key_v[0] = ~key_v[0];
key1 = key_v[1] = ~key_v[1];
}
for (i = 0; i < ARRAY_SIZE(key_v); i++)
ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
AR5K_KEYTABLE_OFF(entry, i));
ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
if (is_tkip) {
/* Install rx/tx MIC */
rxmic = (__le32 *) &key->key[16];
txmic = (__le32 *) &key->key[24];
if (ah->ah_combined_mic) {
key_v[0] = rxmic[0];
key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
key_v[2] = rxmic[1];
key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
key_v[4] = txmic[1];
} else {
key_v[0] = rxmic[0];
key_v[1] = 0;
key_v[2] = rxmic[1];
key_v[3] = 0;
key_v[4] = 0;
}
for (i = 0; i < ARRAY_SIZE(key_v); i++)
ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
AR5K_KEYTABLE_OFF(micentry, i));
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
AR5K_KEYTABLE_TYPE(micentry));
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
/* restore first 2 words of key */
ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
AR5K_KEYTABLE_OFF(entry, 0));
ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
AR5K_KEYTABLE_OFF(entry, 1));
}
return ath5k_hw_set_key_lladdr(ah, entry, mac);
}
int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
{
u32 low_id, high_id;
/* Invalid entry (key table overflow) */
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
/*
* MAC may be NULL if it's a broadcast key. In this case no need to
* to compute get_unaligned_le32 and get_unaligned_le16 as we
* already know it.
*/
if (!mac) {
low_id = 0xffffffff;
high_id = 0xffff | AR5K_KEYTABLE_VALID;
} else {
low_id = get_unaligned_le32(mac);
high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
}
ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
return 0;
}
/**
* ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
*
......
......@@ -1377,7 +1377,7 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
/* protect against divide by 0 and loss of sign bits */
if (i_coffd == 0 || q_coffd < 2)
return -1;
return 0;
i_coff = (-iq_corr) / i_coffd;
i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
......
......@@ -35,25 +35,59 @@ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
return 0;
}
/*
* Make sure cw is a power of 2 minus 1 and smaller than 1024
*/
static u16 ath5k_cw_validate(u16 cw_req)
{
u32 cw = 1;
cw_req = min(cw_req, (u16)1023);
while (cw < cw_req)
cw = (cw << 1) | 1;
return cw;
}
/*
* Set properties for a transmit queue
*/
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
const struct ath5k_txq_info *queue_info)
const struct ath5k_txq_info *qinfo)
{
struct ath5k_txq_info *qi;
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
qi = &ah->ah_txq[queue];
if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
return -EIO;
memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
/* copy and validate values */
qi->tqi_type = qinfo->tqi_type;
qi->tqi_subtype = qinfo->tqi_subtype;
qi->tqi_flags = qinfo->tqi_flags;
/*
* According to the docs: Although the AIFS field is 8 bit wide,
* the maximum supported value is 0xFC. Setting it higher than that
* will cause the DCU to hang.
*/
qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
qi->tqi_cbr_period = qinfo->tqi_cbr_period;
qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
qi->tqi_burst_time = qinfo->tqi_burst_time;
qi->tqi_ready_time = qinfo->tqi_ready_time;
/*XXX: Is this supported on 5210 ?*/
if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
/*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
(qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
return 0;
}
......@@ -186,7 +220,7 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
*/
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
{
u32 cw_min, cw_max, retry_lg, retry_sh;
u32 retry_lg, retry_sh;
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
......@@ -217,14 +251,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
/* Set IFS0 */
if (ah->ah_turbo) {
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
(ah->ah_aifs + tq->tqi_aifs) *
AR5K_INIT_SLOT_TIME_TURBO) <<
tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
AR5K_IFS0);
} else {
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
(ah->ah_aifs + tq->tqi_aifs) *
AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
AR5K_IFS0_DIFS_S) |
AR5K_INIT_SIFS, AR5K_IFS0);
}
......@@ -247,35 +280,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_PHY_FRAME_CTL_5210);
}
/*
* Calculate cwmin/max by channel mode
*/
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
ah->ah_aifs = AR5K_TUNE_AIFS;
/*XR is only supported on 5212*/
if (IS_CHAN_XR(ah->ah_current_channel) &&
ah->ah_version == AR5K_AR5212) {
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
ah->ah_aifs = AR5K_TUNE_AIFS_XR;
/*B mode is not supported on 5210*/
} else if (IS_CHAN_B(ah->ah_current_channel) &&
ah->ah_version != AR5K_AR5210) {
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
ah->ah_aifs = AR5K_TUNE_AIFS_11B;
}
cw_min = 1;
while (cw_min < ah->ah_cw_min)
cw_min = (cw_min << 1) | 1;
cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
/*
* Calculate and set retry limits
*/
......@@ -292,7 +296,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
/*No QCU/DCU [5210]*/
if (ah->ah_version == AR5K_AR5210) {
ath5k_hw_reg_write(ah,
(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
AR5K_NODCU_RETRY_LMT_SLG_RETRY)
| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
......@@ -314,14 +318,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
/*===Rest is also for QCU/DCU only [5211+]===*/
/*
* Set initial content window (cw_min/cw_max)
* Set contention window (cw_min/cw_max)
* and arbitrated interframe space (aifs)...
*/
ath5k_hw_reg_write(ah,
AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
AR5K_DCU_LCL_IFS_AIFS),
AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
AR5K_QUEUE_DFS_LOCAL_IFS(queue));
/*
......
......@@ -1822,50 +1822,8 @@
/*===5212 end===*/
/*
* Key table (WEP) register
*/
#define AR5K_KEYTABLE_0_5210 0x9000
#define AR5K_KEYTABLE_0_5211 0x8800
#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5))
#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5))
#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \
AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2))
#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5)
#define AR5K_KEYTABLE_TYPE_40 0x00000000
#define AR5K_KEYTABLE_TYPE_104 0x00000001
#define AR5K_KEYTABLE_TYPE_128 0x00000003
#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */
#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */
#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */
#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */
#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */
#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6)
#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7)
#define AR5K_KEYTABLE_VALID 0x00008000
/* If key type is TKIP and MIC is enabled
* MIC key goes in offset entry + 64 */
#define AR5K_KEYTABLE_MIC_OFFSET 64
/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit
* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit
* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit
*
* Some vendors have introduced bigger WEP keys to address
* security vulnerabilities in WEP. This includes:
*
* WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
*
* We can expand this if we find ar5k Atheros cards with a larger
* key table size.
*/
#define AR5K_KEYTABLE_SIZE_5210 64
#define AR5K_KEYTABLE_SIZE_5211 128
#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
/*===PHY REGISTERS===*/
......
......@@ -32,6 +32,14 @@ config ATH9K_DEBUGFS
Also required for changing debug message flags at run time.
config ATH9K_RATE_CONTROL
bool "Atheros ath9k rate control"
depends on ATH9K
default y
---help---
Say Y, if you want to use the ath9k specific rate control
module instead of minstrel_ht.
config ATH9K_HTC
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211
......
......@@ -5,8 +5,8 @@ ath9k-y += beacon.o \
recv.o \
xmit.o \
virtual.o \
rc.o
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
......
......@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include "hw.h"
#include "hw-ops.h"
......@@ -48,7 +49,7 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = {
{ 7, 8, 0 } /* lvl 9 */
};
#define ATH9K_ANI_OFDM_NUM_LEVEL \
(sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0]))
ARRAY_SIZE(ofdm_level_table)
#define ATH9K_ANI_OFDM_MAX_LEVEL \
(ATH9K_ANI_OFDM_NUM_LEVEL-1)
#define ATH9K_ANI_OFDM_DEF_LEVEL \
......@@ -94,7 +95,7 @@ static const struct ani_cck_level_entry cck_level_table[] = {
};
#define ATH9K_ANI_CCK_NUM_LEVEL \
(sizeof(cck_level_table)/sizeof(cck_level_table[0]))
ARRAY_SIZE(cck_level_table)
#define ATH9K_ANI_CCK_MAX_LEVEL \
(ATH9K_ANI_CCK_NUM_LEVEL-1)
#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
......
......@@ -580,3 +580,53 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
else
ath9k_hw_attach_ani_ops_old(ah);
}
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
{
u32 modesIndex;
int i;
switch (chan->chanmode) {
case CHANNEL_A:
case CHANNEL_A_HT20:
modesIndex = 1;
break;
case CHANNEL_A_HT40PLUS:
case CHANNEL_A_HT40MINUS:
modesIndex = 2;
break;
case CHANNEL_G:
case CHANNEL_G_HT20:
case CHANNEL_B:
modesIndex = 4;
break;
case CHANNEL_G_HT40PLUS:
case CHANNEL_G_HT40MINUS:
modesIndex = 3;
break;
default:
return;
}
ENABLE_REGWRITE_BUFFER(ah);
for (i = 0; i < ah->iniModes_9271_ANI_reg.ia_rows; i++) {
u32 reg = INI_RA(&ah->iniModes_9271_ANI_reg, i, 0);
u32 val = INI_RA(&ah->iniModes_9271_ANI_reg, i, modesIndex);
u32 val_orig;
if (reg == AR_PHY_CCK_DETECT) {
val_orig = REG_READ(ah, reg);
val &= AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
val_orig &= ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
REG_WRITE(ah, reg, val|val_orig);
} else
REG_WRITE(ah, reg, val);
}
REGWRITE_BUFFER_FLUSH(ah);
DISABLE_REGWRITE_BUFFER(ah);
}
......@@ -530,3 +530,38 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
ar9002_hw_set_nf_limits(ah);
}
void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
u32 regval;
regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
antconf->main_lna_conf = (regval & AR_PHY_9285_ANT_DIV_MAIN_LNACONF) >>
AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S;
antconf->alt_lna_conf = (regval & AR_PHY_9285_ANT_DIV_ALT_LNACONF) >>
AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
AR_PHY_9285_FAST_DIV_BIAS_S;
}
EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get);
void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
u32 regval;
regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
regval &= ~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
AR_PHY_9285_ANT_DIV_ALT_LNACONF |
AR_PHY_9285_FAST_DIV_BIAS);
regval |= ((antconf->main_lna_conf << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S)
& AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
regval |= ((antconf->alt_lna_conf << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S)
& AR_PHY_9285_ANT_DIV_ALT_LNACONF);
regval |= ((antconf->fast_div_bias << AR_PHY_9285_FAST_DIV_BIAS_S)
& AR_PHY_9285_FAST_DIV_BIAS);
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}
EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set);
......@@ -302,6 +302,8 @@
#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
#define AR_PHY_9285_FAST_DIV_BIAS 0x00007E00
#define AR_PHY_9285_FAST_DIV_BIAS_S 9
#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
#define AR_PHY_9285_ANT_DIV_CTL 0x01000000
#define AR_PHY_9285_ANT_DIV_CTL_S 24
......
......@@ -968,7 +968,7 @@ static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah)
}
static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
enum ieee80211_band freq_band)
enum ath9k_hal_freq_band freq_band)
{
return 1;
}
......
......@@ -616,7 +616,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
} else if (rxsp->status11 & AR_MichaelErr) {
rxs->rs_status |= ATH9K_RXERR_MIC;
}
} else if (rxsp->status11 & AR_KeyMiss)
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
}
return 0;
......
......@@ -254,7 +254,7 @@ struct ath_atx_tid {
struct list_head buf_q;
struct ath_node *an;
struct ath_atx_ac *ac;
struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
u16 seq_start;
u16 seq_next;
u16 baw_size;
......@@ -345,9 +345,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_edma_tasklet(struct ath_softc *sc);
void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath9k_enable_ps(struct ath_softc *sc);
......@@ -481,6 +480,60 @@ struct ath_led {
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
/* Antenna diversity/combining */
#define ATH_ANT_RX_CURRENT_SHIFT 4
#define ATH_ANT_RX_MAIN_SHIFT 2
#define ATH_ANT_RX_MASK 0x3
#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
#define ATH_ANT_DIV_COMB_INIT_COUNT 95
#define ATH_ANT_DIV_COMB_MAX_COUNT 100
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
enum ath9k_ant_div_comb_lna_conf {
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
ATH_ANT_DIV_COMB_LNA2,
ATH_ANT_DIV_COMB_LNA1,
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
};
struct ath_ant_comb {
u16 count;
u16 total_pkt_count;
bool scan;
bool scan_not_start;
int main_total_rssi;
int alt_total_rssi;
int alt_recv_cnt;
int main_recv_cnt;
int rssi_lna1;
int rssi_lna2;
int rssi_add;
int rssi_sub;
int rssi_first;
int rssi_second;
int rssi_third;
bool alt_good;
int quick_scan_cnt;
int main_conf;
enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
int first_bias;
int second_bias;
bool first_ratio;
bool second_ratio;
unsigned long scan_start_time;
};
/********************/
/* Main driver core */
/********************/
......@@ -509,7 +562,6 @@ void ath_deinit_leds(struct ath_softc *sc);
#define SC_OP_RXFLUSH BIT(7)
#define SC_OP_LED_ASSOCIATED BIT(8)
#define SC_OP_LED_ON BIT(9)
#define SC_OP_SCANNING BIT(10)
#define SC_OP_TSF_RESET BIT(11)
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
#define SC_OP_BT_SCAN BIT(13)
......@@ -597,6 +649,8 @@ struct ath_softc {
struct ath_btcoex btcoex;
struct ath_descdma txsdma;
struct ath_ant_comb ant_comb;
};
struct ath_wiphy {
......@@ -663,7 +717,7 @@ static inline void ath_ahb_exit(void) {};
void ath9k_ps_wakeup(struct ath_softc *sc);
void ath9k_ps_restore(struct ath_softc *sc);
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int ath9k_wiphy_add(struct ath_softc *sc);
int ath9k_wiphy_del(struct ath_wiphy *aphy);
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
......
......@@ -148,276 +148,6 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ath9k_cmn_get_curchannel);
static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
struct ath9k_keyval *hk, const u8 *addr,
bool authenticator)
{
struct ath_hw *ah = common->ah;
const u8 *key_rxmic;
const u8 *key_txmic;
key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
if (addr == NULL) {
/*
* Group key installation - only two key cache entries are used
* regardless of splitmic capability since group key is only
* used either for TX or RX.
*/
if (authenticator) {
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
} else {
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
}
return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
}
if (!common->splitmic) {
/* TX and RX keys share the same key cache entry. */
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
}
/* Separate key cache entries for TX and RX */
/* TX key goes at first index, RX key at +32. */
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
ath_print(common, ATH_DBG_FATAL,
"Setting TX MIC Key Failed\n");
return 0;
}
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
/* XXX delete tx key on failure? */
return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
}
static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
{
int i;
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
if (test_bit(i, common->keymap) ||
test_bit(i + 64, common->keymap))
continue; /* At least one part of TKIP key allocated */
if (common->splitmic &&
(test_bit(i + 32, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
continue; /* At least one part of TKIP key allocated */
/* Found a free slot for a TKIP key */
return i;
}
return -1;
}
static int ath_reserve_key_cache_slot(struct ath_common *common,
u32 cipher)
{
int i;
if (cipher == WLAN_CIPHER_SUITE_TKIP)
return ath_reserve_key_cache_slot_tkip(common);
/* First, try to find slots that would not be available for TKIP. */
if (common->splitmic) {
for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
if (!test_bit(i, common->keymap) &&
(test_bit(i + 32, common->keymap) ||
test_bit(i + 64, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
return i;
if (!test_bit(i + 32, common->keymap) &&
(test_bit(i, common->keymap) ||
test_bit(i + 64, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
return i + 32;
if (!test_bit(i + 64, common->keymap) &&
(test_bit(i , common->keymap) ||
test_bit(i + 32, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
return i + 64;
if (!test_bit(i + 64 + 32, common->keymap) &&
(test_bit(i, common->keymap) ||
test_bit(i + 32, common->keymap) ||
test_bit(i + 64, common->keymap)))
return i + 64 + 32;
}
} else {
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
if (!test_bit(i, common->keymap) &&
test_bit(i + 64, common->keymap))
return i;
if (test_bit(i, common->keymap) &&
!test_bit(i + 64, common->keymap))
return i + 64;
}
}
/* No partially used TKIP slots, pick any available slot */
for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
/* Do not allow slots that could be needed for TKIP group keys
* to be used. This limitation could be removed if we know that
* TKIP will not be used. */
if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
continue;
if (common->splitmic) {
if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
continue;
if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
continue;
}
if (!test_bit(i, common->keymap))
return i; /* Found a free slot for a key */
}
/* No free slot found */
return -1;
}
/*
* Configure encryption in the HW.
*/
int ath9k_cmn_key_config(struct ath_common *common,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct ath_hw *ah = common->ah;
struct ath9k_keyval hk;
const u8 *mac = NULL;
u8 gmac[ETH_ALEN];
int ret = 0;
int idx;
memset(&hk, 0, sizeof(hk));
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
hk.kv_type = ATH9K_CIPHER_WEP;
break;
case WLAN_CIPHER_SUITE_TKIP:
hk.kv_type = ATH9K_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
hk.kv_type = ATH9K_CIPHER_AES_CCM;
break;
default:
return -EOPNOTSUPP;
}
hk.kv_len = key->keylen;
memcpy(hk.kv_val, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
switch (vif->type) {
case NL80211_IFTYPE_AP:
memcpy(gmac, vif->addr, ETH_ALEN);
gmac[0] |= 0x01;
mac = gmac;
idx = ath_reserve_key_cache_slot(common, key->cipher);
break;
case NL80211_IFTYPE_ADHOC:
if (!sta) {
idx = key->keyidx;
break;
}
memcpy(gmac, sta->addr, ETH_ALEN);
gmac[0] |= 0x01;
mac = gmac;
idx = ath_reserve_key_cache_slot(common, key->cipher);
break;
default:
idx = key->keyidx;
break;
}
} else if (key->keyidx) {
if (WARN_ON(!sta))
return -EOPNOTSUPP;
mac = sta->addr;
if (vif->type != NL80211_IFTYPE_AP) {
/* Only keyidx 0 should be used with unicast key, but
* allow this for client mode for now. */
idx = key->keyidx;
} else
return -EIO;
} else {
if (WARN_ON(!sta))
return -EOPNOTSUPP;
mac = sta->addr;
idx = ath_reserve_key_cache_slot(common, key->cipher);
}
if (idx < 0)
return -ENOSPC; /* no free key cache entries */
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
vif->type == NL80211_IFTYPE_AP);
else
ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
if (!ret)
return -EIO;
set_bit(idx, common->keymap);
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
set_bit(idx + 64, common->keymap);
set_bit(idx, common->tkip_keymap);
set_bit(idx + 64, common->tkip_keymap);
if (common->splitmic) {
set_bit(idx + 32, common->keymap);
set_bit(idx + 64 + 32, common->keymap);
set_bit(idx + 32, common->tkip_keymap);
set_bit(idx + 64 + 32, common->tkip_keymap);
}
}
return idx;
}
EXPORT_SYMBOL(ath9k_cmn_key_config);
/*
* Delete Key.
*/
void ath9k_cmn_key_delete(struct ath_common *common,
struct ieee80211_key_conf *key)
{
struct ath_hw *ah = common->ah;
ath9k_hw_keyreset(ah, key->hw_key_idx);
if (key->hw_key_idx < IEEE80211_WEP_NKID)
return;
clear_bit(key->hw_key_idx, common->keymap);
if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
return;
clear_bit(key->hw_key_idx + 64, common->keymap);
clear_bit(key->hw_key_idx, common->tkip_keymap);
clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
if (common->splitmic) {
ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
clear_bit(key->hw_key_idx + 32, common->keymap);
clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
}
}
EXPORT_SYMBOL(ath9k_cmn_key_delete);
int ath9k_cmn_count_streams(unsigned int chainmask, int max)
{
int streams = 0;
......
......@@ -66,12 +66,6 @@ void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
struct ath9k_channel *ichan);
struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
struct ath_hw *ah);
int ath9k_cmn_key_config(struct ath_common *common,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
void ath9k_cmn_key_delete(struct ath_common *common,
struct ieee80211_key_conf *key);
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
enum ath_stomp_type stomp_type);
......@@ -492,12 +492,55 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
unsigned int len = 0;
int i;
u8 addr[ETH_ALEN];
u32 tmp;
len += snprintf(buf + len, sizeof(buf) - len,
"primary: %s (%s chan=%d ht=%d)\n",
wiphy_name(sc->pri_wiphy->hw->wiphy),
ath_wiphy_state_str(sc->pri_wiphy->state),
sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht);
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addr: %pM\n", addr);
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
tmp = ath9k_hw_getrxfilter(sc->sc_ah);
len += snprintf(buf + len, sizeof(buf) - len,
"rfilt: 0x%x", tmp);
if (tmp & ATH9K_RX_FILTER_UCAST)
len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
if (tmp & ATH9K_RX_FILTER_MCAST)
len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
if (tmp & ATH9K_RX_FILTER_BCAST)
len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
if (tmp & ATH9K_RX_FILTER_CONTROL)
len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
if (tmp & ATH9K_RX_FILTER_BEACON)
len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
if (tmp & ATH9K_RX_FILTER_PROM)
len += snprintf(buf + len, sizeof(buf) - len, " PROM");
if (tmp & ATH9K_RX_FILTER_PROBEREQ)
len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
if (tmp & ATH9K_RX_FILTER_PHYERR)
len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
if (tmp & ATH9K_RX_FILTER_MYBEACON)
len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
if (tmp & ATH9K_RX_FILTER_COMP_BAR)
len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
if (tmp & ATH9K_RX_FILTER_PSPOLL)
len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
if (tmp & ATH9K_RX_FILTER_PHYRADAR)
len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n");
else
len += snprintf(buf + len, sizeof(buf) - len, "\n");
/* Put variable-length stuff down here, and check for overflows. */
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
if (aphy == NULL)
......@@ -508,16 +551,6 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
ath_wiphy_state_str(aphy->state),
aphy->chan_idx, aphy->chan_is_ht);
}
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addr: %pM\n", addr);
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
if (len > sizeof(buf))
len = sizeof(buf);
......
......@@ -266,6 +266,8 @@ enum eeprom_param {
EEP_INTERNAL_REGULATOR,
EEP_SWREG,
EEP_PAPRD,
EEP_MODAL_VER,
EEP_ANT_DIV_CTL1,
};
enum ar5416_rates {
......@@ -670,7 +672,8 @@ struct eeprom_ops {
bool (*fill_eeprom)(struct ath_hw *hw);
int (*get_eeprom_ver)(struct ath_hw *hw);
int (*get_eeprom_rev)(struct ath_hw *hw);
u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
u8 (*get_num_ant_config)(struct ath_hw *hw,
enum ath9k_hal_freq_band band);
u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
struct ath9k_channel *chan);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
......
......@@ -213,6 +213,10 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
return 0;
case EEP_PWR_TABLE_OFFSET:
return AR5416_PWR_TABLE_OFFSET_DB;
case EEP_MODAL_VER:
return pModal->version;
case EEP_ANT_DIV_CTL1:
return pModal->antdiv_ctl1;
default:
return 0;
}
......@@ -1157,7 +1161,7 @@ static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
}
static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
enum ieee80211_band freq_band)
enum ath9k_hal_freq_band freq_band)
{
return 1;
}
......
......@@ -1126,7 +1126,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
}
static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
enum ieee80211_band freq_band)
enum ath9k_hal_freq_band freq_band)
{
return 1;
}
......
......@@ -1418,11 +1418,11 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
}
static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
enum ieee80211_band freq_band)
enum ath9k_hal_freq_band freq_band)
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct modal_eep_header *pModal =
&(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
&(eep->modalHeader[freq_band]);
struct base_eep_header *pBase = &eep->baseEepHeader;
u8 num_ant_config;
......
......@@ -92,10 +92,10 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
cmd->skb = skb;
cmd->hif_dev = hif_dev;
usb_fill_int_urb(urb, hif_dev->udev,
usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE),
usb_fill_bulk_urb(urb, hif_dev->udev,
usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE),
skb->data, skb->len,
hif_usb_regout_cb, cmd, 1);
hif_usb_regout_cb, cmd);
usb_anchor_urb(urb, &hif_dev->regout_submitted);
ret = usb_submit_urb(urb, GFP_KERNEL);
......@@ -541,7 +541,8 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
}
usb_fill_int_urb(urb, hif_dev->udev,
usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
usb_rcvbulkpipe(hif_dev->udev,
USB_REG_IN_PIPE),
nskb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, nskb, 1);
......@@ -720,7 +721,8 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
goto err;
usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev,
usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
usb_rcvbulkpipe(hif_dev->udev,
USB_REG_IN_PIPE),
skb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, skb, 1);
......@@ -822,7 +824,9 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
{
int ret;
int ret, idx;
struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
struct usb_endpoint_descriptor *endp;
/* Request firmware */
ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
......@@ -850,6 +854,22 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
goto err_fw_download;
}
/* On downloading the firmware to the target, the USB descriptor of EP4
* is 'patched' to change the type of the endpoint to Bulk. This will
* bring down CPU usage during the scan period.
*/
for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
endp = &alt->endpoint[idx].desc;
if (((endp->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
== 0x04) &&
((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_INT)) {
endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
endp->bInterval = 0;
}
}
return 0;
err_fw_download:
......
......@@ -566,7 +566,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
* reset the contents on initial power up.
*/
for (i = 0; i < common->keymax; i++)
ath9k_hw_keyreset(priv->ah, (u16) i);
ath_hw_keyreset(common, (u16) i);
}
static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
......@@ -601,8 +601,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
common->tx_chainmask = priv->ah->caps.tx_chainmask;
common->rx_chainmask = priv->ah->caps.rx_chainmask;
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
priv->ah->opmode = NL80211_IFTYPE_STATION;
}
......
......@@ -137,8 +137,6 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (priv->op_flags & OP_FULL_RESET)
fastcc = false;
/* Fiddle around with fastcc later on, for now just use full reset */
fastcc = false;
ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
......@@ -146,9 +144,10 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
WMI_CMD(WMI_STOP_RECV_CMDID);
ath_print(common, ATH_DBG_CONFIG,
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
priv->ah->curchan->channel,
channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
fastcc);
caldata = &priv->caldata[channel->hw_value];
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
......@@ -1591,7 +1590,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
ret = ath9k_cmn_key_config(common, vif, sta, key);
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
......@@ -1605,7 +1604,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
}
break;
case DISABLE_KEY:
ath9k_cmn_key_delete(common, key);
ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
......
......@@ -415,8 +415,7 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
ath9k_hw_setrxfilter(ah, rfilt);
/* configure bssid mask */
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
ath_hw_setbssidmask(common);
ath_hw_setbssidmask(common);
/* configure operational mode */
ath9k_hw_setopmode(ah);
......
......@@ -1258,11 +1258,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
(chan->channel != ah->curchan->channel) &&
((chan->channelFlags & CHANNEL_ALL) ==
(ah->curchan->channelFlags & CHANNEL_ALL)) &&
!AR_SREV_9280(ah)) {
(!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) {
if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true);
if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
return 0;
}
}
......@@ -1474,283 +1476,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
EXPORT_SYMBOL(ath9k_hw_reset);
/************************/
/* Key Cache Management */
/************************/
bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
{
u32 keyType;
if (entry >= ah->caps.keycache_size) {
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
"keychache entry %u out of range\n", entry);
return false;
}
keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
u16 micentry = entry + 64;
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
}
return true;
}
EXPORT_SYMBOL(ath9k_hw_keyreset);
static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
{
u32 macHi, macLo;
u32 unicast_flag = AR_KEYTABLE_VALID;
if (entry >= ah->caps.keycache_size) {
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
"keychache entry %u out of range\n", entry);
return false;
}
if (mac != NULL) {
/*
* AR_KEYTABLE_VALID indicates that the address is a unicast
* address, which must match the transmitter address for
* decrypting frames.
* Not setting this bit allows the hardware to use the key
* for multicast frame decryption.
*/
if (mac[0] & 0x01)
unicast_flag = 0;
macHi = (mac[5] << 8) | mac[4];
macLo = (mac[3] << 24) |
(mac[2] << 16) |
(mac[1] << 8) |
mac[0];
macLo >>= 1;
macLo |= (macHi & 1) << 31;
macHi >>= 1;
} else {
macLo = macHi = 0;
}
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
return true;
}
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
const struct ath9k_keyval *k,
const u8 *mac)
{
const struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
u32 key0, key1, key2, key3, key4;
u32 keyType;
if (entry >= pCap->keycache_size) {
ath_print(common, ATH_DBG_FATAL,
"keycache entry %u out of range\n", entry);
return false;
}
switch (k->kv_type) {
case ATH9K_CIPHER_AES_OCB:
keyType = AR_KEYTABLE_TYPE_AES;
break;
case ATH9K_CIPHER_AES_CCM:
if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
ath_print(common, ATH_DBG_ANY,
"AES-CCM not supported by mac rev 0x%x\n",
ah->hw_version.macRev);
return false;
}
keyType = AR_KEYTABLE_TYPE_CCM;
break;
case ATH9K_CIPHER_TKIP:
keyType = AR_KEYTABLE_TYPE_TKIP;
if (ATH9K_IS_MIC_ENABLED(ah)
&& entry + 64 >= pCap->keycache_size) {
ath_print(common, ATH_DBG_ANY,
"entry %u inappropriate for TKIP\n", entry);
return false;
}
break;
case ATH9K_CIPHER_WEP:
if (k->kv_len < WLAN_KEY_LEN_WEP40) {
ath_print(common, ATH_DBG_ANY,
"WEP key length %u too small\n", k->kv_len);
return false;
}
if (k->kv_len <= WLAN_KEY_LEN_WEP40)
keyType = AR_KEYTABLE_TYPE_40;
else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
keyType = AR_KEYTABLE_TYPE_104;
else
keyType = AR_KEYTABLE_TYPE_128;
break;
case ATH9K_CIPHER_CLR:
keyType = AR_KEYTABLE_TYPE_CLR;
break;
default:
ath_print(common, ATH_DBG_FATAL,
"cipher %u not supported\n", k->kv_type);
return false;
}
key0 = get_unaligned_le32(k->kv_val + 0);
key1 = get_unaligned_le16(k->kv_val + 4);
key2 = get_unaligned_le32(k->kv_val + 6);
key3 = get_unaligned_le16(k->kv_val + 10);
key4 = get_unaligned_le32(k->kv_val + 12);
if (k->kv_len <= WLAN_KEY_LEN_WEP104)
key4 &= 0xff;
/*
* Note: Key cache registers access special memory area that requires
* two 32-bit writes to actually update the values in the internal
* memory. Consequently, the exact order and pairs used here must be
* maintained.
*/
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
u16 micentry = entry + 64;
/*
* Write inverted key[47:0] first to avoid Michael MIC errors
* on frames that could be sent or received at the same time.
* The correct key will be written in the end once everything
* else is ready.
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
/* Write key[95:48] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
/* Write key[127:96] and key type */
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
/* Write MAC address for the entry */
(void) ath9k_hw_keysetmac(ah, entry, mac);
if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
/*
* TKIP uses two key cache entries:
* Michael MIC TX/RX keys in the same key cache entry
* (idx = main index + 64):
* key0 [31:0] = RX key [31:0]
* key1 [15:0] = TX key [31:16]
* key1 [31:16] = reserved
* key2 [31:0] = RX key [63:32]
* key3 [15:0] = TX key [15:0]
* key3 [31:16] = reserved
* key4 [31:0] = TX key [63:32]
*/
u32 mic0, mic1, mic2, mic3, mic4;
mic0 = get_unaligned_le32(k->kv_mic + 0);
mic2 = get_unaligned_le32(k->kv_mic + 4);
mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
mic4 = get_unaligned_le32(k->kv_txmic + 4);
/* Write RX[31:0] and TX[31:16] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
/* Write RX[63:32] and TX[15:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
/* Write TX[63:32] and keyType(reserved) */
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
AR_KEYTABLE_TYPE_CLR);
} else {
/*
* TKIP uses four key cache entries (two for group
* keys):
* Michael MIC TX/RX keys are in different key cache
* entries (idx = main index + 64 for TX and
* main index + 32 + 96 for RX):
* key0 [31:0] = TX/RX MIC key [31:0]
* key1 [31:0] = reserved
* key2 [31:0] = TX/RX MIC key [63:32]
* key3 [31:0] = reserved
* key4 [31:0] = reserved
*
* Upper layer code will call this function separately
* for TX and RX keys when these registers offsets are
* used.
*/
u32 mic0, mic2;
mic0 = get_unaligned_le32(k->kv_mic + 0);
mic2 = get_unaligned_le32(k->kv_mic + 4);
/* Write MIC key[31:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
/* Write MIC key[63:32] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
/* Write TX[63:32] and keyType(reserved) */
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
AR_KEYTABLE_TYPE_CLR);
}
/* MAC address registers are reserved for the MIC entry */
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
/*
* Write the correct (un-inverted) key[47:0] last to enable
* TKIP now that all other registers are set with correct
* values.
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
} else {
/* Write key[47:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
/* Write key[95:48] */
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
/* Write key[127:96] and key type */
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
/* Write MAC address for the entry */
(void) ath9k_hw_keysetmac(ah, entry, mac);
}
return true;
}
EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
/******************************/
/* Power Management (Chipset) */
/******************************/
......@@ -2056,6 +1781,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
u16 capField = 0, eeval;
u8 ant_div_ctl1;
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
regulatory->current_rd = eeval;
......@@ -2140,24 +1866,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->low_5ghz_chan = 4920;
pCap->high_5ghz_chan = 6100;
pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
if (ah->config.ht_enable)
pCap->hw_caps |= ATH9K_HW_CAP_HT;
else
pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
pCap->hw_caps |= ATH9K_HW_CAP_GTT;
pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
if (capField & AR_EEPROM_EEPCAP_MAXQCU)
pCap->total_queues =
MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
......@@ -2170,8 +1885,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
else
pCap->keycache_size = AR_KEYTABLE_SIZE;
pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
else
......@@ -2280,6 +1993,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
if (AR_SREV_9285(ah))
if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
ant_div_ctl1 =
ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
}
return 0;
}
......
......@@ -181,29 +181,19 @@ enum wireless_mode {
};
enum ath9k_hw_caps {
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
ATH9K_HW_CAP_MIC_TKIP = BIT(2),
ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3),
ATH9K_HW_CAP_CIPHER_CKIP = BIT(4),
ATH9K_HW_CAP_CIPHER_TKIP = BIT(5),
ATH9K_HW_CAP_VEOL = BIT(6),
ATH9K_HW_CAP_BSSIDMASK = BIT(7),
ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8),
ATH9K_HW_CAP_HT = BIT(9),
ATH9K_HW_CAP_GTT = BIT(10),
ATH9K_HW_CAP_FASTCC = BIT(11),
ATH9K_HW_CAP_RFSILENT = BIT(12),
ATH9K_HW_CAP_CST = BIT(13),
ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
ATH9K_HW_CAP_EDMA = BIT(17),
ATH9K_HW_CAP_RAC_SUPPORTED = BIT(18),
ATH9K_HW_CAP_LDPC = BIT(19),
ATH9K_HW_CAP_FASTCLOCK = BIT(20),
ATH9K_HW_CAP_SGI_20 = BIT(21),
ATH9K_HW_CAP_PAPRD = BIT(22),
ATH9K_HW_CAP_HT = BIT(0),
ATH9K_HW_CAP_RFSILENT = BIT(1),
ATH9K_HW_CAP_CST = BIT(2),
ATH9K_HW_CAP_ENHANCEDPM = BIT(3),
ATH9K_HW_CAP_AUTOSLEEP = BIT(4),
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5),
ATH9K_HW_CAP_EDMA = BIT(6),
ATH9K_HW_CAP_RAC_SUPPORTED = BIT(7),
ATH9K_HW_CAP_LDPC = BIT(8),
ATH9K_HW_CAP_FASTCLOCK = BIT(9),
ATH9K_HW_CAP_SGI_20 = BIT(10),
ATH9K_HW_CAP_PAPRD = BIT(11),
ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12),
};
struct ath9k_hw_capabilities {
......@@ -495,6 +485,12 @@ struct ath_gen_timer_table {
} timer_mask;
};
struct ath_hw_antcomb_conf {
u8 main_lna_conf;
u8 alt_lna_conf;
u8 fast_div_bias;
};
/**
* struct ath_hw_private_ops - callbacks used internally by hardware code
*
......@@ -874,12 +870,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
int ath9k_hw_fill_cap_info(struct ath_hw *ah);
u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
/* Key Cache Management */
bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
const struct ath9k_keyval *k,
const u8 *mac);
/* GPIO / RFKILL / Antennae */
void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
......@@ -888,6 +878,10 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
/* General Operation */
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
......@@ -985,6 +979,7 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
void ar9002_hw_attach_ops(struct ath_hw *ah);
void ar9003_hw_attach_ops(struct ath_hw *ah);
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
/*
* ANI work can be shared between all families but a next
* generation implementation of ANI will be used only for AR9003 only
......
......@@ -381,7 +381,7 @@ static void ath9k_init_crypto(struct ath_softc *sc)
* reset the contents on initial power up.
*/
for (i = 0; i < common->keymax; i++)
ath9k_hw_keyreset(sc->sc_ah, (u16) i);
ath_hw_keyreset(common, (u16) i);
/*
* Check whether the separate key cache entries
......@@ -389,8 +389,8 @@ static void ath9k_init_crypto(struct ath_softc *sc)
* With split mic keys the number of stations is limited
* to 27 otherwise 59.
*/
if (!(sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA))
common->splitmic = 1;
if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
}
static int ath9k_init_btcoex(struct ath_softc *sc)
......@@ -522,8 +522,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
ath9k_hw_set_diversity(sc->sc_ah, true);
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
......@@ -531,6 +530,9 @@ static void ath9k_init_misc(struct ath_softc *sc)
sc->beacon.bslot[i] = NULL;
sc->beacon.bslot_aphy[i] = NULL;
}
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
}
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
......@@ -641,7 +643,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
if (AR_SREV_5416(sc->sc_ah))
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->queues = 4;
hw->max_rates = 4;
......@@ -651,7 +654,9 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif);
#ifdef CONFIG_ATH9K_RATE_CONTROL
hw->rate_control_algorithm = "ath9k_rate_control";
#endif
if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
......
......@@ -714,6 +714,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
rs->rs_status |= ATH9K_RXERR_MIC;
else if (ads.ds_rxstatus8 & AR_KeyMiss)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
}
return 0;
......
......@@ -660,17 +660,6 @@ struct ath9k_11n_rate_series {
u32 RateFlags;
};
struct ath9k_keyval {
u8 kv_type;
u8 kv_pad;
u16 kv_len;
u8 kv_val[16]; /* TK */
u8 kv_mic[8]; /* Michael MIC key */
u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
* supports both MIC keys in the same key cache entry;
* in that case, kv_mic is the RX key) */
};
enum ath9k_key_type {
ATH9K_KEY_TYPE_CLEAR,
ATH9K_KEY_TYPE_WEP,
......@@ -678,16 +667,6 @@ enum ath9k_key_type {
ATH9K_KEY_TYPE_TKIP,
};
enum ath9k_cipher {
ATH9K_CIPHER_WEP = 0,
ATH9K_CIPHER_AES_OCB = 1,
ATH9K_CIPHER_AES_CCM = 2,
ATH9K_CIPHER_CKIP = 3,
ATH9K_CIPHER_TKIP = 4,
ATH9K_CIPHER_CLR = 5,
ATH9K_CIPHER_MIC = 127
};
struct ath_hw;
struct ath9k_channel;
......
......@@ -255,10 +255,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
ath_update_txpow(sc);
ath9k_hw_set_interrupts(ah, ah->imask);
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL | SC_OP_SCANNING))) {
ath_start_ani(common);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
ath_beacon_config(sc, NULL);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ath_start_ani(common);
}
ps_restore:
......@@ -957,7 +957,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
ath_update_txpow(sc);
if (sc->sc_flags & SC_OP_BEACONS)
if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
ath_beacon_config(sc, NULL); /* restart beacons */
ath9k_hw_set_interrupts(ah, ah->imask);
......@@ -1156,8 +1156,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
else
ah->imask |= ATH9K_INT_RX;
if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
ah->imask |= ATH9K_INT_GTT;
ah->imask |= ATH9K_INT_GTT;
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ah->imask |= ATH9K_INT_CST;
......@@ -1379,12 +1378,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
sc->nvifs > 0) {
ret = -ENOBUFS;
goto out;
}
switch (vif->type) {
case NL80211_IFTYPE_STATION:
ic_opmode = NL80211_IFTYPE_STATION;
......@@ -1414,8 +1407,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
sc->nvifs++;
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
ath9k_set_bssid_mask(hw);
ath9k_set_bssid_mask(hw, vif);
if (sc->nvifs > 1)
goto out; /* skip global settings for secondary vif */
......@@ -1562,6 +1554,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
* IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
*/
if (changed & IEEE80211_CONF_CHANGE_PS) {
unsigned long flags;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (conf->flags & IEEE80211_CONF_PS) {
sc->ps_flags |= PS_ENABLED;
/*
......@@ -1576,7 +1570,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
sc->ps_enabled = false;
sc->ps_flags &= ~(PS_ENABLED |
PS_NULLFUNC_COMPLETED);
ath9k_setpower(sc, ATH9K_PM_AWAKE);
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
ath9k_hw_setrxabort(sc->sc_ah, 0);
......@@ -1591,6 +1585,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
}
}
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
......@@ -1777,7 +1772,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
ret = ath9k_cmn_key_config(common, vif, sta, key);
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
......@@ -1791,7 +1786,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
}
break;
case DISABLE_KEY:
ath9k_cmn_key_delete(common, key);
ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
......@@ -1975,8 +1970,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
break;
case IEEE80211_AMPDU_TX_START:
ath9k_ps_wakeup(sc);
ath_tx_aggr_start(sc, sta, tid, ssn);
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ret = ath_tx_aggr_start(sc, sta, tid, ssn);
if (!ret)
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_STOP:
......@@ -2039,7 +2035,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
sc->sc_flags |= SC_OP_SCANNING;
mutex_unlock(&sc->mutex);
}
......@@ -2054,7 +2049,6 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
mutex_unlock(&sc->mutex);
}
......
......@@ -45,9 +45,6 @@
} \
} while (0)
#define ATH9K_IS_MIC_ENABLED(ah) \
((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
#define ANTSWAP_AB 0x0001
#define REDUCE_CHAIN_0 0x00000050
#define REDUCE_CHAIN_1 0x00000051
......
......@@ -1320,6 +1320,22 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
return caps;
}
static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an,
u8 tidno)
{
struct ath_atx_tid *txtid;
if (!(sc->sc_flags & SC_OP_TXAGGR))
return false;
txtid = ATH_AN_2_TID(an, tidno);
if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
return true;
return false;
}
/***********************************/
/* mac80211 Rate Control callbacks */
/***********************************/
......
......@@ -224,7 +224,18 @@ enum ath9k_internal_frame_type {
ATH9K_IFT_UNPAUSE
};
#ifdef CONFIG_ATH9K_RATE_CONTROL
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);
#else
static inline int ath_rate_control_register(void)
{
return 0;
}
static inline void ath_rate_control_unregister(void)
{
}
#endif
#endif /* RC_H */
......@@ -19,6 +19,15 @@
#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb))
static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
int mindelta, int main_rssi_avg,
int alt_rssi_avg, int pkt_count)
{
return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
}
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
{
return sc->ps_enabled &&
......@@ -110,8 +119,7 @@ static void ath_opmode_init(struct ath_softc *sc)
ath9k_hw_setrxfilter(ah, rfilt);
/* configure bssid mask */
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
ath_hw_setbssidmask(common);
ath_hw_setbssidmask(common);
/* configure operational mode */
ath9k_hw_setopmode(ah);
......@@ -292,7 +300,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
ath_opmode_init(sc);
ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING));
ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
}
static void ath_edma_stop_recv(struct ath_softc *sc)
......@@ -440,6 +448,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt |= ATH9K_RX_FILTER_CONTROL;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
(sc->nvifs <= 1) &&
!(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
......@@ -454,9 +463,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (conf_is_ht(&sc->hw->conf))
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* TODO: only needed if more than one BSSID is in use in
* station/adhoc mode */
if (sc->sec_wiphy || (sc->nvifs > 1) ||
(sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* The following may also be needed for other older chips */
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
......@@ -498,7 +506,7 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
spin_unlock_bh(&sc->rx.rxbuflock);
ath_opmode_init(sc);
ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING));
ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
return 0;
}
......@@ -631,7 +639,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
* No more broadcast/multicast frames to be received at this
* point.
*/
sc->ps_flags &= ~PS_WAIT_FOR_CAB;
sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON);
ath_print(common, ATH_DBG_PS,
"All PS CAB frames received, back to sleep\n");
} else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
......@@ -1076,6 +1084,539 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
struct ath_hw_antcomb_conf ant_conf,
int main_rssi_avg)
{
antcomb->quick_scan_cnt = 0;
if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
antcomb->rssi_lna2 = main_rssi_avg;
else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
antcomb->rssi_lna1 = main_rssi_avg;
switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
case (0x10): /* LNA2 A-B */
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
antcomb->first_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
break;
case (0x20): /* LNA1 A-B */
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
antcomb->first_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
break;
case (0x21): /* LNA1 LNA2 */
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
antcomb->first_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
antcomb->second_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
break;
case (0x12): /* LNA2 LNA1 */
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
antcomb->first_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
antcomb->second_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
break;
case (0x13): /* LNA2 A+B */
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
antcomb->first_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
break;
case (0x23): /* LNA1 A+B */
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
antcomb->first_quick_scan_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
break;
default:
break;
}
}
static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
struct ath_hw_antcomb_conf *div_ant_conf,
int main_rssi_avg, int alt_rssi_avg,
int alt_ratio)
{
/* alt_good */
switch (antcomb->quick_scan_cnt) {
case 0:
/* set alt to main, and alt to first conf */
div_ant_conf->main_lna_conf = antcomb->main_conf;
div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
break;
case 1:
/* set alt to main, and alt to first conf */
div_ant_conf->main_lna_conf = antcomb->main_conf;
div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
antcomb->rssi_first = main_rssi_avg;
antcomb->rssi_second = alt_rssi_avg;
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
/* main is LNA1 */
if (ath_is_alt_ant_ratio_better(alt_ratio,
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
main_rssi_avg, alt_rssi_avg,
antcomb->total_pkt_count))
antcomb->first_ratio = true;
else
antcomb->first_ratio = false;
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
if (ath_is_alt_ant_ratio_better(alt_ratio,
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
main_rssi_avg, alt_rssi_avg,
antcomb->total_pkt_count))
antcomb->first_ratio = true;
else
antcomb->first_ratio = false;
} else {
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
(alt_rssi_avg > main_rssi_avg +
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
(alt_rssi_avg > main_rssi_avg)) &&
(antcomb->total_pkt_count > 50))
antcomb->first_ratio = true;
else
antcomb->first_ratio = false;
}
break;
case 2:
antcomb->alt_good = false;
antcomb->scan_not_start = false;
antcomb->scan = false;
antcomb->rssi_first = main_rssi_avg;
antcomb->rssi_third = alt_rssi_avg;
if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
antcomb->rssi_lna1 = alt_rssi_avg;
else if (antcomb->second_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA2)
antcomb->rssi_lna2 = alt_rssi_avg;
else if (antcomb->second_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
antcomb->rssi_lna2 = main_rssi_avg;
else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
antcomb->rssi_lna1 = main_rssi_avg;
}
if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
else
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
if (ath_is_alt_ant_ratio_better(alt_ratio,
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
main_rssi_avg, alt_rssi_avg,
antcomb->total_pkt_count))
antcomb->second_ratio = true;
else
antcomb->second_ratio = false;
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
if (ath_is_alt_ant_ratio_better(alt_ratio,
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
main_rssi_avg, alt_rssi_avg,
antcomb->total_pkt_count))
antcomb->second_ratio = true;
else
antcomb->second_ratio = false;
} else {
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
(alt_rssi_avg > main_rssi_avg +
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
(alt_rssi_avg > main_rssi_avg)) &&
(antcomb->total_pkt_count > 50))
antcomb->second_ratio = true;
else
antcomb->second_ratio = false;
}
/* set alt to the conf with maximun ratio */
if (antcomb->first_ratio && antcomb->second_ratio) {
if (antcomb->rssi_second > antcomb->rssi_third) {
/* first alt*/
if ((antcomb->first_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA1) ||
(antcomb->first_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA2))
/* Set alt LNA1 or LNA2*/
if (div_ant_conf->main_lna_conf ==
ATH_ANT_DIV_COMB_LNA2)
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
else
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
else
/* Set alt to A+B or A-B */
div_ant_conf->alt_lna_conf =
antcomb->first_quick_scan_conf;
} else if ((antcomb->second_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA1) ||
(antcomb->second_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA2)) {
/* Set alt LNA1 or LNA2 */
if (div_ant_conf->main_lna_conf ==
ATH_ANT_DIV_COMB_LNA2)
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
else
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
} else {
/* Set alt to A+B or A-B */
div_ant_conf->alt_lna_conf =
antcomb->second_quick_scan_conf;
}
} else if (antcomb->first_ratio) {
/* first alt */
if ((antcomb->first_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA1) ||
(antcomb->first_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA2))
/* Set alt LNA1 or LNA2 */
if (div_ant_conf->main_lna_conf ==
ATH_ANT_DIV_COMB_LNA2)
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
else
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
else
/* Set alt to A+B or A-B */
div_ant_conf->alt_lna_conf =
antcomb->first_quick_scan_conf;
} else if (antcomb->second_ratio) {
/* second alt */
if ((antcomb->second_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA1) ||
(antcomb->second_quick_scan_conf ==
ATH_ANT_DIV_COMB_LNA2))
/* Set alt LNA1 or LNA2 */
if (div_ant_conf->main_lna_conf ==
ATH_ANT_DIV_COMB_LNA2)
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
else
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
else
/* Set alt to A+B or A-B */
div_ant_conf->alt_lna_conf =
antcomb->second_quick_scan_conf;
} else {
/* main is largest */
if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
(antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
/* Set alt LNA1 or LNA2 */
if (div_ant_conf->main_lna_conf ==
ATH_ANT_DIV_COMB_LNA2)
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
else
div_ant_conf->alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
else
/* Set alt to A+B or A-B */
div_ant_conf->alt_lna_conf = antcomb->main_conf;
}
break;
default:
break;
}
}
static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf)
{
/* Adjust the fast_div_bias based on main and alt lna conf */
switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
case (0x01): /* A-B LNA2 */
ant_conf->fast_div_bias = 0x3b;
break;
case (0x02): /* A-B LNA1 */
ant_conf->fast_div_bias = 0x3d;
break;
case (0x03): /* A-B A+B */
ant_conf->fast_div_bias = 0x1;
break;
case (0x10): /* LNA2 A-B */
ant_conf->fast_div_bias = 0x7;
break;
case (0x12): /* LNA2 LNA1 */
ant_conf->fast_div_bias = 0x2;
break;
case (0x13): /* LNA2 A+B */
ant_conf->fast_div_bias = 0x7;
break;
case (0x20): /* LNA1 A-B */
ant_conf->fast_div_bias = 0x6;
break;
case (0x21): /* LNA1 LNA2 */
ant_conf->fast_div_bias = 0x0;
break;
case (0x23): /* LNA1 A+B */
ant_conf->fast_div_bias = 0x6;
break;
case (0x30): /* A+B A-B */
ant_conf->fast_div_bias = 0x1;
break;
case (0x31): /* A+B LNA2 */
ant_conf->fast_div_bias = 0x3b;
break;
case (0x32): /* A+B LNA1 */
ant_conf->fast_div_bias = 0x3d;
break;
default:
break;
}
}
/* Antenna diversity and combining */
static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
{
struct ath_hw_antcomb_conf div_ant_conf;
struct ath_ant_comb *antcomb = &sc->ant_comb;
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
int curr_main_set, curr_bias;
int main_rssi = rs->rs_rssi_ctl0;
int alt_rssi = rs->rs_rssi_ctl1;
int rx_ant_conf, main_ant_conf;
bool short_scan = false;
rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
ATH_ANT_RX_MASK;
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
ATH_ANT_RX_MASK;
/* Record packet only when alt_rssi is positive */
if (alt_rssi > 0) {
antcomb->total_pkt_count++;
antcomb->main_total_rssi += main_rssi;
antcomb->alt_total_rssi += alt_rssi;
if (main_ant_conf == rx_ant_conf)
antcomb->main_recv_cnt++;
else
antcomb->alt_recv_cnt++;
}
/* Short scan check */
if (antcomb->scan && antcomb->alt_good) {
if (time_after(jiffies, antcomb->scan_start_time +
msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
short_scan = true;
else
if (antcomb->total_pkt_count ==
ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
antcomb->total_pkt_count);
if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
short_scan = true;
}
}
if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
rs->rs_moreaggr) && !short_scan)
return;
if (antcomb->total_pkt_count) {
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
antcomb->total_pkt_count);
main_rssi_avg = (antcomb->main_total_rssi /
antcomb->total_pkt_count);
alt_rssi_avg = (antcomb->alt_total_rssi /
antcomb->total_pkt_count);
}
ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
curr_alt_set = div_ant_conf.alt_lna_conf;
curr_main_set = div_ant_conf.main_lna_conf;
curr_bias = div_ant_conf.fast_div_bias;
antcomb->count++;
if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
main_rssi_avg);
antcomb->alt_good = true;
} else {
antcomb->alt_good = false;
}
antcomb->count = 0;
antcomb->scan = true;
antcomb->scan_not_start = true;
}
if (!antcomb->scan) {
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
/* Switch main and alt LNA */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
}
goto div_comb_done;
} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
(curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
/* Set alt to another LNA */
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
goto div_comb_done;
}
if ((alt_rssi_avg < (main_rssi_avg +
ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
goto div_comb_done;
}
if (!antcomb->scan_not_start) {
switch (curr_alt_set) {
case ATH_ANT_DIV_COMB_LNA2:
antcomb->rssi_lna2 = alt_rssi_avg;
antcomb->rssi_lna1 = main_rssi_avg;
antcomb->scan = true;
/* set to A+B */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
break;
case ATH_ANT_DIV_COMB_LNA1:
antcomb->rssi_lna1 = alt_rssi_avg;
antcomb->rssi_lna2 = main_rssi_avg;
antcomb->scan = true;
/* set to A+B */
div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
break;
case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
antcomb->rssi_add = alt_rssi_avg;
antcomb->scan = true;
/* set to A-B */
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
break;
case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
antcomb->rssi_sub = alt_rssi_avg;
antcomb->scan = false;
if (antcomb->rssi_lna2 >
(antcomb->rssi_lna1 +
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
/* use LNA2 as main LNA */
if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
(antcomb->rssi_add > antcomb->rssi_sub)) {
/* set to A+B */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
} else if (antcomb->rssi_sub >
antcomb->rssi_lna1) {
/* set to A-B */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
} else {
/* set to LNA1 */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
}
} else {
/* use LNA1 as main LNA */
if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
(antcomb->rssi_add > antcomb->rssi_sub)) {
/* set to A+B */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
} else if (antcomb->rssi_sub >
antcomb->rssi_lna1) {
/* set to A-B */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
} else {
/* set to LNA2 */
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
}
}
break;
default:
break;
}
} else {
if (!antcomb->alt_good) {
antcomb->scan_not_start = false;
/* Set alt to another LNA */
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
div_ant_conf.main_lna_conf =
ATH_ANT_DIV_COMB_LNA1;
div_ant_conf.alt_lna_conf =
ATH_ANT_DIV_COMB_LNA2;
}
goto div_comb_done;
}
}
ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
main_rssi_avg, alt_rssi_avg,
alt_ratio);
antcomb->quick_scan_cnt++;
div_comb_done:
ath_ant_div_conf_fast_divbias(&div_ant_conf);
ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
antcomb->scan_start_time = jiffies;
antcomb->total_pkt_count = 0;
antcomb->main_total_rssi = 0;
antcomb->alt_total_rssi = 0;
antcomb->main_recv_cnt = 0;
antcomb->alt_recv_cnt = 0;
}
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
struct ath_buf *bf;
......@@ -1099,6 +1640,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
u8 rx_status_len = ah->caps.rx_status_len;
u64 tsf = 0;
u32 tsf_lower = 0;
unsigned long flags;
if (edma)
dma_type = DMA_BIDIRECTIONAL;
......@@ -1207,11 +1749,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
sc->rx.rxotherant = 0;
}
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (unlikely(ath9k_check_auto_sleep(sc) ||
(sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA))))
ath_rx_ps(sc, skb);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
ath_ant_comb_scan(sc, &rs);
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
......
......@@ -19,45 +19,36 @@
#include "ath9k.h"
struct ath9k_vif_iter_data {
int count;
u8 *addr;
const u8 *hw_macaddr;
u8 mask[ETH_ALEN];
};
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath9k_vif_iter_data *iter_data = data;
u8 *nbuf;
nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
GFP_ATOMIC);
if (nbuf == NULL)
return;
int i;
memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
iter_data->addr = nbuf;
iter_data->count++;
for (i = 0; i < ETH_ALEN; i++)
iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
}
void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_vif_iter_data iter_data;
int i, j;
u8 mask[ETH_ALEN];
int i;
/*
* Add primary MAC address even if it is not in active use since it
* will be configured to the hardware as the starting point and the
* BSSID mask will need to be changed if another address is active.
* Use the hardware MAC address as reference, the hardware uses it
* together with the BSSID mask when matching addresses.
*/
iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
if (iter_data.addr) {
memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
iter_data.count = 1;
} else
iter_data.count = 0;
iter_data.hw_macaddr = common->macaddr;
memset(&iter_data.mask, 0xff, ETH_ALEN);
if (vif)
ath9k_vif_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
spin_lock_bh(&sc->wiphy_lock);
......@@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
}
spin_unlock_bh(&sc->wiphy_lock);
/* Generate an address mask to cover all active addresses */
memset(mask, 0, ETH_ALEN);
for (i = 0; i < iter_data.count; i++) {
u8 *a1 = iter_data.addr + i * ETH_ALEN;
for (j = i + 1; j < iter_data.count; j++) {
u8 *a2 = iter_data.addr + j * ETH_ALEN;
mask[0] |= a1[0] ^ a2[0];
mask[1] |= a1[1] ^ a2[1];
mask[2] |= a1[2] ^ a2[2];
mask[3] |= a1[3] ^ a2[3];
mask[4] |= a1[4] ^ a2[4];
mask[5] |= a1[5] ^ a2[5];
}
}
kfree(iter_data.addr);
/* Invert the mask and configure hardware */
common->bssidmask[0] = ~mask[0];
common->bssidmask[1] = ~mask[1];
common->bssidmask[2] = ~mask[2];
common->bssidmask[3] = ~mask[3];
common->bssidmask[4] = ~mask[4];
common->bssidmask[5] = ~mask[5];
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
}
......
......@@ -124,55 +124,11 @@ void ath9k_wmi_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
struct ath_common *common = ath9k_hw_common(priv->ah);
struct wmi_cmd_hdr *hdr;
struct wmi_swba *swba_hdr;
enum wmi_event_id event;
struct sk_buff *skb;
void *wmi_event;
unsigned long flags;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
__be32 txrate;
#endif
spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
skb = priv->wmi->wmi_skb;
spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
ath_print(common, ATH_DBG_WMI, "SWBA Event received\n");
hdr = (struct wmi_cmd_hdr *) skb->data;
event = be16_to_cpu(hdr->command_id);
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
ath_print(common, ATH_DBG_WMI,
"WMI Event: 0x%x\n", event);
switch (event) {
case WMI_TGT_RDY_EVENTID:
break;
case WMI_SWBA_EVENTID:
swba_hdr = (struct wmi_swba *) wmi_event;
ath9k_htc_swba(priv, swba_hdr->beacon_pending);
break;
case WMI_FATAL_EVENTID:
break;
case WMI_TXTO_EVENTID:
break;
case WMI_BMISS_EVENTID:
break;
case WMI_WLAN_TXCOMP_EVENTID:
break;
case WMI_DELBA_EVENTID:
break;
case WMI_TXRATE_EVENTID:
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
priv->debug.txrate = be32_to_cpu(txrate);
#endif
break;
default:
break;
}
kfree_skb(skb);
}
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
......@@ -191,6 +147,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr;
u16 cmd_id;
void *wmi_event;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
__be32 txrate;
#endif
if (unlikely(wmi->stopped))
goto free_skb;
......@@ -199,10 +159,22 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id);
if (cmd_id & 0x1000) {
spin_lock(&wmi->wmi_lock);
wmi->wmi_skb = skb;
spin_unlock(&wmi->wmi_lock);
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
switch (cmd_id) {
case WMI_SWBA_EVENTID:
wmi->beacon_pending = *(u8 *)wmi_event;
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
break;
case WMI_TXRATE_EVENTID:
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
#endif
break;
default:
break;
}
kfree_skb(skb);
return;
}
......
......@@ -31,10 +31,6 @@ struct wmi_cmd_hdr {
__be16 seq_no;
} __packed;
struct wmi_swba {
u8 beacon_pending;
} __packed;
enum wmi_cmd_id {
WMI_ECHO_CMDID = 0x0001,
WMI_ACCESS_MEMORY_CMDID,
......@@ -104,7 +100,7 @@ struct wmi {
u32 cmd_rsp_len;
bool stopped;
struct sk_buff *wmi_skb;
u8 beacon_pending;
spinlock_t wmi_lock;
atomic_t mwrite_cnt;
......
......@@ -61,6 +61,8 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int txok);
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
int nbad, int txok, bool update_rc);
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
int seqno);
enum {
MCS_HT20,
......@@ -143,18 +145,23 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
struct ath_buf *bf;
struct list_head bf_head;
INIT_LIST_HEAD(&bf_head);
struct ath_tx_status ts;
WARN_ON(!tid->paused);
INIT_LIST_HEAD(&bf_head);
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);
}
spin_unlock_bh(&txq->axq_lock);
if (txtid->baw_head != txtid->baw_tail) {
/*
* 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 {
else
txtid->state &= ~AGGR_ADDBA_COMPLETE;
ath_tx_flush_tid(sc, txtid);
}
spin_unlock_bh(&txq->axq_lock);
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 */
/********************/
......
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
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
/*
* 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 */
/*
* 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);
}
/*
* 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 */
此差异已折叠。
/*
* 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 */
/*
* 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 */
此差异已折叠。
/*
* 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 */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
#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 */
此差异已折叠。
此差异已折叠。
......@@ -24,4 +24,27 @@
#define AR_BSSMSKL 0x80e0
#define AR_BSSMSKU 0x80e4
#define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128
#define AR_RSVD_KEYTABLE_ENTRIES 4
#define AR_KEY_TYPE 0x00000007
#define AR_KEYTABLE_TYPE_40 0x00000000
#define AR_KEYTABLE_TYPE_104 0x00000001
#define AR_KEYTABLE_TYPE_128 0x00000003
#define AR_KEYTABLE_TYPE_TKIP 0x00000004
#define AR_KEYTABLE_TYPE_AES 0x00000005
#define AR_KEYTABLE_TYPE_CCM 0x00000006
#define AR_KEYTABLE_TYPE_CLR 0x00000007
#define AR_KEYTABLE_ANT 0x00000008
#define AR_KEYTABLE_VALID 0x00008000
#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0)
#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4)
#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8)
#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12)
#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16)
#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20)
#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24)
#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28)
#endif /* ATH_REGISTERS_H */
......@@ -223,6 +223,7 @@ static struct iwl_lib_ops iwl1000_lib = {
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
......
......@@ -295,7 +295,7 @@ extern const struct iwl_channel_info *iwl3945_get_channel_info(
extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate);
/* scanning */
void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
/* Requires full declaration of iwl_priv before including */
#include "iwl-io.h"
......
......@@ -2289,6 +2289,7 @@ static struct iwl_lib_ops iwl4965_lib = {
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
......
......@@ -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";
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册