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

This commit is contained in:
David S. Miller 2011-04-25 12:46:37 -07:00
commit 345578d97c
192 changed files with 7236 additions and 5970 deletions

View File

@ -188,7 +188,7 @@ config BT_MRVL
The core driver to support Marvell Bluetooth devices. The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support This driver is required if you want to support
Marvell Bluetooth devices, such as 8688. Marvell Bluetooth devices, such as 8688/8787.
Say Y here to compile Marvell Bluetooth driver Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module. into the kernel or say M to compile it as module.
@ -201,7 +201,7 @@ config BT_MRVL_SDIO
The driver for Marvell Bluetooth chipsets with SDIO interface. The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth This driver is required if you want to use Marvell Bluetooth
devices with SDIO interface. Currently only SD8688 chipset is devices with SDIO interface. Currently SD8688/SD8787 chipsets are
supported. supported.
Say Y here to compile support for Marvell BT-over-SDIO driver Say Y here to compile support for Marvell BT-over-SDIO driver

View File

@ -138,9 +138,6 @@ static int ath3k_load_firmware(struct usb_device *udev,
count -= size; count -= size;
} }
kfree(send_buf);
return 0;
error: error:
kfree(send_buf); kfree(send_buf);
return err; return err;

View File

@ -49,15 +49,59 @@
static u8 user_rmmod; static u8 user_rmmod;
static u8 sdio_ireg; static u8 sdio_ireg;
static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
.cfg = 0x03,
.host_int_mask = 0x04,
.host_intstatus = 0x05,
.card_status = 0x20,
.sq_read_base_addr_a0 = 0x10,
.sq_read_base_addr_a1 = 0x11,
.card_fw_status0 = 0x40,
.card_fw_status1 = 0x41,
.card_rx_len = 0x42,
.card_rx_unit = 0x43,
.io_port_0 = 0x00,
.io_port_1 = 0x01,
.io_port_2 = 0x02,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
.cfg = 0x00,
.host_int_mask = 0x02,
.host_intstatus = 0x03,
.card_status = 0x30,
.sq_read_base_addr_a0 = 0x40,
.sq_read_base_addr_a1 = 0x41,
.card_revision = 0x5c,
.card_fw_status0 = 0x60,
.card_fw_status1 = 0x61,
.card_rx_len = 0x62,
.card_rx_unit = 0x63,
.io_port_0 = 0x78,
.io_port_1 = 0x79,
.io_port_2 = 0x7a,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
.helper = "sd8688_helper.bin", .helper = "sd8688_helper.bin",
.firmware = "sd8688.bin", .firmware = "sd8688.bin",
.reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
.helper = NULL,
.firmware = "mrvl/sd8787_uapsta.bin",
.reg = &btmrvl_reg_8787,
.sd_blksz_fw_dl = 256,
}; };
static const struct sdio_device_id btmrvl_sdio_ids[] = { static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */ /* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
.driver_data = (unsigned long) &btmrvl_sdio_sd6888 }, .driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
/* Marvell SD8787 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
u8 reg; u8 reg;
int ret; int ret;
reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret);
if (!ret) if (!ret)
card->rx_unit = reg; card->rx_unit = reg;
@ -83,11 +127,11 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
*dat = 0; *dat = 0;
fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret) if (ret)
return -EIO; return -EIO;
fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret);
if (ret) if (ret)
return -EIO; return -EIO;
@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
u8 reg; u8 reg;
int ret; int ret;
reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); reg = sdio_readb(card->func, card->reg->card_rx_len, &ret);
if (!ret) if (!ret)
*dat = (u16) reg << card->rx_unit; *dat = (u16) reg << card->rx_unit;
@ -113,7 +157,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
{ {
int ret; int ret;
sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
if (ret) { if (ret) {
BT_ERR("Unable to enable the host interrupt!"); BT_ERR("Unable to enable the host interrupt!");
ret = -EIO; ret = -EIO;
@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
u8 host_int_mask; u8 host_int_mask;
int ret; int ret;
host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret);
if (ret) if (ret)
return -EIO; return -EIO;
host_int_mask &= ~mask; host_int_mask &= ~mask;
sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
if (ret < 0) { if (ret < 0) {
BT_ERR("Unable to disable the host interrupt!"); BT_ERR("Unable to disable the host interrupt!");
return -EIO; return -EIO;
@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
int ret; int ret;
for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
status = sdio_readb(card->func, CARD_STATUS_REG, &ret); status = sdio_readb(card->func, card->reg->card_status, &ret);
if (ret) if (ret)
goto failed; goto failed;
if ((status & bits) == bits) if ((status & bits) == bits)
@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
u8 base0, base1; u8 base0, base1;
void *tmpfwbuf = NULL; void *tmpfwbuf = NULL;
u8 *fwbuf; u8 *fwbuf;
u16 len; u16 len, blksz_dl = card->sd_blksz_fw_dl;
int txlen = 0, tx_blocks = 0, count = 0; int txlen = 0, tx_blocks = 0, count = 0;
ret = request_firmware(&fw_firmware, card->firmware, ret = request_firmware(&fw_firmware, card->firmware,
@ -345,7 +389,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
for (tries = 0; tries < MAX_POLL_TRIES; tries++) { for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
base0 = sdio_readb(card->func, base0 = sdio_readb(card->func,
SQ_READ_BASE_ADDRESS_A0_REG, &ret); card->reg->sq_read_base_addr_a0, &ret);
if (ret) { if (ret) {
BT_ERR("BASE0 register read failed:" BT_ERR("BASE0 register read failed:"
" base0 = 0x%04X(%d)." " base0 = 0x%04X(%d)."
@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
goto done; goto done;
} }
base1 = sdio_readb(card->func, base1 = sdio_readb(card->func,
SQ_READ_BASE_ADDRESS_A1_REG, &ret); card->reg->sq_read_base_addr_a1, &ret);
if (ret) { if (ret) {
BT_ERR("BASE1 register read failed:" BT_ERR("BASE1 register read failed:"
" base1 = 0x%04X(%d)." " base1 = 0x%04X(%d)."
@ -403,20 +447,19 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
if (firmwarelen - offset < txlen) if (firmwarelen - offset < txlen)
txlen = firmwarelen - offset; txlen = firmwarelen - offset;
tx_blocks = tx_blocks = (txlen + blksz_dl - 1) / blksz_dl;
(txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
memcpy(fwbuf, &firmware[offset], txlen); memcpy(fwbuf, &firmware[offset], txlen);
} }
ret = sdio_writesb(card->func, card->ioport, fwbuf, ret = sdio_writesb(card->func, card->ioport, fwbuf,
tx_blocks * SDIO_BLOCK_SIZE); tx_blocks * blksz_dl);
if (ret < 0) { if (ret < 0) {
BT_ERR("FW download, writesb(%d) failed @%d", BT_ERR("FW download, writesb(%d) failed @%d",
count, offset); count, offset);
sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, sdio_writeb(card->func, HOST_CMD53_FIN,
&ret); card->reg->cfg, &ret);
if (ret) if (ret)
BT_ERR("writeb failed (CFG)"); BT_ERR("writeb failed (CFG)");
} }
@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
priv = card->priv; priv = card->priv;
ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
if (ret) { if (ret) {
BT_ERR("sdio_readb: read int status register failed"); BT_ERR("sdio_readb: read int status register failed");
return; return;
@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
UP_LD_HOST_INT_STATUS), UP_LD_HOST_INT_STATUS),
HOST_INTSTATUS_REG, &ret); card->reg->host_intstatus, &ret);
if (ret) { if (ret) {
BT_ERR("sdio_writeb: clear int status register failed"); BT_ERR("sdio_writeb: clear int status register failed");
return; return;
@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
goto release_irq; goto release_irq;
} }
reg = sdio_readb(func, IO_PORT_0_REG, &ret); reg = sdio_readb(func, card->reg->io_port_0, &ret);
if (ret < 0) { if (ret < 0) {
ret = -EIO; ret = -EIO;
goto release_irq; goto release_irq;
@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
card->ioport = reg; card->ioport = reg;
reg = sdio_readb(func, IO_PORT_1_REG, &ret); reg = sdio_readb(func, card->reg->io_port_1, &ret);
if (ret < 0) { if (ret < 0) {
ret = -EIO; ret = -EIO;
goto release_irq; goto release_irq;
@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
card->ioport |= (reg << 8); card->ioport |= (reg << 8);
reg = sdio_readb(func, IO_PORT_2_REG, &ret); reg = sdio_readb(func, card->reg->io_port_2, &ret);
if (ret < 0) { if (ret < 0) {
ret = -EIO; ret = -EIO;
goto release_irq; goto release_irq;
@ -815,6 +858,8 @@ exit:
static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
{ {
int ret = 0; int ret = 0;
u8 fws0;
int pollnum = MAX_POLL_TRIES;
if (!card || !card->func) { if (!card || !card->func) {
BT_ERR("card or function is NULL!"); BT_ERR("card or function is NULL!");
@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
goto done; goto done;
} }
ret = btmrvl_sdio_download_helper(card); /* Check if other function driver is downloading the firmware */
fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret) { if (ret) {
BT_ERR("Failed to download helper!"); BT_ERR("Failed to read FW downloading status!");
ret = -EIO; ret = -EIO;
goto done; goto done;
} }
if (fws0) {
BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
if (btmrvl_sdio_download_fw_w_helper(card)) { /* Give other function more time to download the firmware */
BT_ERR("Failed to download firmware!"); pollnum *= 10;
ret = -EIO; } else {
goto done; if (card->helper) {
ret = btmrvl_sdio_download_helper(card);
if (ret) {
BT_ERR("Failed to download helper!");
ret = -EIO;
goto done;
}
}
if (btmrvl_sdio_download_fw_w_helper(card)) {
BT_ERR("Failed to download firmware!");
ret = -EIO;
goto done;
}
} }
if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) { if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
BT_ERR("FW failed to be active in time!"); BT_ERR("FW failed to be active in time!");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto done; goto done;
@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
sdio_claim_host(card->func); sdio_claim_host(card->func);
sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret); sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret);
sdio_release_host(card->func); sdio_release_host(card->func);
@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
if (id->driver_data) { if (id->driver_data) {
struct btmrvl_sdio_device *data = (void *) id->driver_data; struct btmrvl_sdio_device *data = (void *) id->driver_data;
card->helper = data->helper; card->helper = data->helper;
card->firmware = data->firmware; card->firmware = data->firmware;
card->reg = data->reg;
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
} }
if (btmrvl_sdio_register_dev(card) < 0) { if (btmrvl_sdio_register_dev(card) < 0) {
@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE("sd8688_helper.bin"); MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin"); MODULE_FIRMWARE("sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");

View File

@ -47,44 +47,46 @@
/* Max retry number of CMD53 write */ /* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2 #define MAX_WRITE_IOMEM_RETRY 2
/* Host Control Registers */ /* register bitmasks */
#define IO_PORT_0_REG 0x00 #define HOST_POWER_UP BIT(1)
#define IO_PORT_1_REG 0x01 #define HOST_CMD53_FIN BIT(2)
#define IO_PORT_2_REG 0x02
#define CONFIG_REG 0x03 #define HIM_DISABLE 0xff
#define HOST_POWER_UP BIT(1) #define HIM_ENABLE (BIT(0) | BIT(1))
#define HOST_CMD53_FIN BIT(2)
#define HOST_INT_MASK_REG 0x04 #define UP_LD_HOST_INT_STATUS BIT(0)
#define HIM_DISABLE 0xff #define DN_LD_HOST_INT_STATUS BIT(1)
#define HIM_ENABLE (BIT(0) | BIT(1))
#define HOST_INTSTATUS_REG 0x05 #define DN_LD_CARD_RDY BIT(0)
#define UP_LD_HOST_INT_STATUS BIT(0) #define CARD_IO_READY BIT(3)
#define DN_LD_HOST_INT_STATUS BIT(1)
/* Card Control Registers */ #define FIRMWARE_READY 0xfedc
#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
#define CARD_STATUS_REG 0x20
#define DN_LD_CARD_RDY BIT(0)
#define CARD_IO_READY BIT(3)
#define CARD_FW_STATUS0_REG 0x40
#define CARD_FW_STATUS1_REG 0x41
#define FIRMWARE_READY 0xfedc
#define CARD_RX_LEN_REG 0x42
#define CARD_RX_UNIT_REG 0x43
struct btmrvl_sdio_card_reg {
u8 cfg;
u8 host_int_mask;
u8 host_intstatus;
u8 card_status;
u8 sq_read_base_addr_a0;
u8 sq_read_base_addr_a1;
u8 card_revision;
u8 card_fw_status0;
u8 card_fw_status1;
u8 card_rx_len;
u8 card_rx_unit;
u8 io_port_0;
u8 io_port_1;
u8 io_port_2;
};
struct btmrvl_sdio_card { struct btmrvl_sdio_card {
struct sdio_func *func; struct sdio_func *func;
u32 ioport; u32 ioport;
const char *helper; const char *helper;
const char *firmware; const char *firmware;
const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl;
u8 rx_unit; u8 rx_unit;
struct btmrvl_private *priv; struct btmrvl_private *priv;
}; };
@ -92,6 +94,8 @@ struct btmrvl_sdio_card {
struct btmrvl_sdio_device { struct btmrvl_sdio_device {
const char *helper; const char *helper;
const char *firmware; const char *firmware;
const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl;
}; };

View File

@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
/* Recv data */ /* Recv data */
static int ath_recv(struct hci_uart *hu, void *data, int count) static int ath_recv(struct hci_uart *hu, void *data, int count)
{ {
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) int ret;
ret = hci_recv_stream_fragment(hu->hdev, data, count);
if (ret < 0) {
BT_ERR("Frame Reassembly Failed"); BT_ERR("Frame Reassembly Failed");
return ret;
}
return count; return count;
} }

View File

@ -151,8 +151,13 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
/* Recv data */ /* Recv data */
static int h4_recv(struct hci_uart *hu, void *data, int count) static int h4_recv(struct hci_uart *hu, void *data, int count)
{ {
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) int ret;
ret = hci_recv_stream_fragment(hu->hdev, data, count);
if (ret < 0) {
BT_ERR("Frame Reassembly Failed"); BT_ERR("Frame Reassembly Failed");
return ret;
}
return count; return count;
} }

View File

@ -359,6 +359,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
*/ */
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{ {
int ret;
struct hci_uart *hu = (void *)tty->disc_data; struct hci_uart *hu = (void *)tty->disc_data;
if (!hu || tty != hu->tty) if (!hu || tty != hu->tty)
@ -368,8 +369,9 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
return; return;
spin_lock(&hu->rx_lock); spin_lock(&hu->rx_lock);
hu->proto->recv(hu, (void *) data, count); ret = hu->proto->recv(hu, (void *) data, count);
hu->hdev->stat.byte_rx += count; if (ret > 0)
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock); spin_unlock(&hu->rx_lock);
tty_unthrottle(tty); tty_unthrottle(tty);

View File

@ -123,14 +123,7 @@ struct ath_ops {
}; };
struct ath_common; struct ath_common;
struct ath_bus_ops;
struct ath_bus_ops {
enum ath_bus_type ath_bus_type;
void (*read_cachesize)(struct ath_common *common, int *csz);
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
void (*bt_coex_prep)(struct ath_common *common);
void (*extn_synch_en)(struct ath_common *common);
};
struct ath_common { struct ath_common {
void *ah; void *ah;

View File

@ -18,6 +18,7 @@
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <ar231x_platform.h> #include <ar231x_platform.h>
#include "ath5k.h" #include "ath5k.h"
#include "debug.h" #include "debug.h"
@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
return 0; return 0;
} }
static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
{
struct ath5k_softc *sc = ah->ah_sc;
struct platform_device *pdev = to_platform_device(sc->dev);
struct ar231x_board_config *bcfg = pdev->dev.platform_data;
u8 *cfg_mac;
if (to_platform_device(sc->dev)->id == 0)
cfg_mac = bcfg->config->wlan0_mac;
else
cfg_mac = bcfg->config->wlan1_mac;
memcpy(mac, cfg_mac, ETH_ALEN);
return 0;
}
static const struct ath_bus_ops ath_ahb_bus_ops = { static const struct ath_bus_ops ath_ahb_bus_ops = {
.ath_bus_type = ATH_AHB, .ath_bus_type = ATH_AHB,
.read_cachesize = ath5k_ahb_read_cachesize, .read_cachesize = ath5k_ahb_read_cachesize,
.eeprom_read = ath5k_ahb_eeprom_read, .eeprom_read = ath5k_ahb_eeprom_read,
.eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
}; };
/*Initialization*/ /*Initialization*/
@ -142,6 +160,16 @@ static int ath_ahb_probe(struct platform_device *pdev)
else else
reg |= AR5K_AR5312_ENABLE_WLAN1; reg |= AR5K_AR5312_ENABLE_WLAN1;
__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
/*
* On a dual-band AR5312, the multiband radio is only
* used as pass-through. Disable 2 GHz support in the
* driver for it
*/
if (to_platform_device(sc->dev)->id == 0 &&
(bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) ==
(BD_WLAN1|BD_WLAN0))
__set_bit(ATH_STAT_2G_DISABLED, sc->status);
} }
ret = ath5k_init_softc(sc, &ath_ahb_bus_ops); ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);

View File

@ -224,8 +224,7 @@
/* SIFS */ /* SIFS */
#define AR5K_INIT_SIFS_TURBO 6 #define AR5K_INIT_SIFS_TURBO 6
/* XXX: 8 from initvals 10 from standard */ #define AR5K_INIT_SIFS_DEFAULT_BG 10
#define AR5K_INIT_SIFS_DEFAULT_BG 8
#define AR5K_INIT_SIFS_DEFAULT_A 16 #define AR5K_INIT_SIFS_DEFAULT_A 16
#define AR5K_INIT_SIFS_HALF_RATE 32 #define AR5K_INIT_SIFS_HALF_RATE 32
#define AR5K_INIT_SIFS_QUARTER_RATE 64 #define AR5K_INIT_SIFS_QUARTER_RATE 64
@ -453,12 +452,10 @@ struct ath5k_tx_status {
u16 ts_seqnum; u16 ts_seqnum;
u16 ts_tstamp; u16 ts_tstamp;
u8 ts_status; u8 ts_status;
u8 ts_rate[4];
u8 ts_retry[4];
u8 ts_final_idx; u8 ts_final_idx;
u8 ts_final_retry;
s8 ts_rssi; s8 ts_rssi;
u8 ts_shortretry; u8 ts_shortretry;
u8 ts_longretry;
u8 ts_virtcol; u8 ts_virtcol;
u8 ts_antenna; u8 ts_antenna;
}; };
@ -875,6 +872,19 @@ enum ath5k_int {
AR5K_INT_QTRIG = 0x40000000, /* Non common */ AR5K_INT_QTRIG = 0x40000000, /* Non common */
AR5K_INT_GLOBAL = 0x80000000, AR5K_INT_GLOBAL = 0x80000000,
AR5K_INT_TX_ALL = AR5K_INT_TXOK
| AR5K_INT_TXDESC
| AR5K_INT_TXERR
| AR5K_INT_TXEOL
| AR5K_INT_TXURN,
AR5K_INT_RX_ALL = AR5K_INT_RXOK
| AR5K_INT_RXDESC
| AR5K_INT_RXERR
| AR5K_INT_RXNOFRM
| AR5K_INT_RXEOL
| AR5K_INT_RXORN,
AR5K_INT_COMMON = AR5K_INT_RXOK AR5K_INT_COMMON = AR5K_INT_RXOK
| AR5K_INT_RXDESC | AR5K_INT_RXDESC
| AR5K_INT_RXERR | AR5K_INT_RXERR
@ -1058,6 +1068,7 @@ struct ath5k_hw {
u8 ah_coverage_class; u8 ah_coverage_class;
bool ah_ack_bitrate_high; bool ah_ack_bitrate_high;
u8 ah_bwmode; u8 ah_bwmode;
bool ah_short_slot;
/* Antenna Control */ /* Antenna Control */
u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@ -1144,6 +1155,13 @@ struct ath5k_hw {
struct ath5k_rx_status *); struct ath5k_rx_status *);
}; };
struct ath_bus_ops {
enum ath_bus_type ath_bus_type;
void (*read_cachesize)(struct ath_common *common, int *csz);
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac);
};
/* /*
* Prototypes * Prototypes
*/ */
@ -1227,13 +1245,12 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah);
/* EEPROM access functions */ /* EEPROM access functions */
int ath5k_eeprom_init(struct ath5k_hw *ah); int ath5k_eeprom_init(struct ath5k_hw *ah);
void ath5k_eeprom_detach(struct ath5k_hw *ah); void ath5k_eeprom_detach(struct ath5k_hw *ah);
int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
/* Protocol Control Unit Functions */ /* Protocol Control Unit Functions */
/* Helpers */ /* Helpers */
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
int len, struct ieee80211_rate *rate); int len, struct ieee80211_rate *rate, bool shortpre);
unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);

View File

@ -313,12 +313,17 @@ int ath5k_hw_init(struct ath5k_softc *sc)
goto err; goto err;
} }
if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) {
__clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
__clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
}
/* Crypto settings */ /* Crypto settings */
common->keymax = (sc->ah->ah_version == AR5K_AR5210 ? common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
if (srev >= AR5K_SREV_AR5212_V4 && if (srev >= AR5K_SREV_AR5212_V4 &&
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
!AR5K_EEPROM_AES_DIS(ee->ee_misc5))) !AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;

View File

@ -1443,6 +1443,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
return true; return true;
} }
static void
ath5k_set_current_imask(struct ath5k_softc *sc)
{
enum ath5k_int imask = sc->imask;
unsigned long flags;
spin_lock_irqsave(&sc->irqlock, flags);
if (sc->rx_pending)
imask &= ~AR5K_INT_RX_ALL;
if (sc->tx_pending)
imask &= ~AR5K_INT_TX_ALL;
ath5k_hw_set_imr(sc->ah, imask);
spin_unlock_irqrestore(&sc->irqlock, flags);
}
static void static void
ath5k_tasklet_rx(unsigned long data) ath5k_tasklet_rx(unsigned long data)
{ {
@ -1506,6 +1521,8 @@ next:
} while (ath5k_rxbuf_setup(sc, bf) == 0); } while (ath5k_rxbuf_setup(sc, bf) == 0);
unlock: unlock:
spin_unlock(&sc->rxbuflock); spin_unlock(&sc->rxbuflock);
sc->rx_pending = false;
ath5k_set_current_imask(sc);
} }
@ -1573,28 +1590,28 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
struct ath5k_txq *txq, struct ath5k_tx_status *ts) struct ath5k_txq *txq, struct ath5k_tx_status *ts)
{ {
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
u8 tries[3];
int i; int i;
sc->stats.tx_all_count++; sc->stats.tx_all_count++;
sc->stats.tx_bytes_count += skb->len; sc->stats.tx_bytes_count += skb->len;
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
tries[0] = info->status.rates[0].count;
tries[1] = info->status.rates[1].count;
tries[2] = info->status.rates[2].count;
ieee80211_tx_info_clear_status(info); ieee80211_tx_info_clear_status(info);
for (i = 0; i < 4; i++) {
for (i = 0; i < ts->ts_final_idx; i++) {
struct ieee80211_tx_rate *r = struct ieee80211_tx_rate *r =
&info->status.rates[i]; &info->status.rates[i];
if (ts->ts_rate[i]) { r->count = tries[i];
r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]);
r->count = ts->ts_retry[i];
} else {
r->idx = -1;
r->count = 0;
}
} }
/* count the successful attempt as well */ info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry;
info->status.rates[ts->ts_final_idx].count++; info->status.rates[ts->ts_final_idx + 1].idx = -1;
if (unlikely(ts->ts_status)) { if (unlikely(ts->ts_status)) {
sc->stats.ack_fail++; sc->stats.ack_fail++;
@ -1609,6 +1626,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
} else { } else {
info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts->ts_rssi; info->status.ack_signal = ts->ts_rssi;
/* count the successful attempt as well */
info->status.rates[ts->ts_final_idx].count++;
} }
/* /*
@ -1690,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
for (i=0; i < AR5K_NUM_TX_QUEUES; i++) for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
ath5k_tx_processq(sc, &sc->txqs[i]); ath5k_tx_processq(sc, &sc->txqs[i]);
sc->tx_pending = false;
ath5k_set_current_imask(sc);
} }
@ -2119,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
* AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
} }
static void
ath5k_schedule_rx(struct ath5k_softc *sc)
{
sc->rx_pending = true;
tasklet_schedule(&sc->rxtq);
}
static void
ath5k_schedule_tx(struct ath5k_softc *sc)
{
sc->tx_pending = true;
tasklet_schedule(&sc->txtq);
}
irqreturn_t irqreturn_t
ath5k_intr(int irq, void *dev_id) ath5k_intr(int irq, void *dev_id)
{ {
@ -2161,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
ieee80211_queue_work(sc->hw, &sc->reset_work); ieee80211_queue_work(sc->hw, &sc->reset_work);
} }
else else
tasklet_schedule(&sc->rxtq); ath5k_schedule_rx(sc);
} else { } else {
if (status & AR5K_INT_SWBA) { if (status & AR5K_INT_SWBA) {
tasklet_hi_schedule(&sc->beacontq); tasklet_hi_schedule(&sc->beacontq);
@ -2179,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
ath5k_hw_update_tx_triglevel(ah, true); ath5k_hw_update_tx_triglevel(ah, true);
} }
if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
tasklet_schedule(&sc->rxtq); ath5k_schedule_rx(sc);
if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
| AR5K_INT_TXERR | AR5K_INT_TXEOL)) | AR5K_INT_TXERR | AR5K_INT_TXEOL))
tasklet_schedule(&sc->txtq); ath5k_schedule_tx(sc);
if (status & AR5K_INT_BMISS) { if (status & AR5K_INT_BMISS) {
/* TODO */ /* TODO */
} }
@ -2201,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
} while (ath5k_hw_is_intr_pending(ah) && --counter > 0); } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
if (sc->rx_pending || sc->tx_pending)
ath5k_set_current_imask(sc);
if (unlikely(!counter)) if (unlikely(!counter))
ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
@ -2572,6 +2612,8 @@ done:
static void stop_tasklets(struct ath5k_softc *sc) static void stop_tasklets(struct ath5k_softc *sc)
{ {
sc->rx_pending = false;
sc->tx_pending = false;
tasklet_kill(&sc->rxtq); tasklet_kill(&sc->rxtq);
tasklet_kill(&sc->txtq); tasklet_kill(&sc->txtq);
tasklet_kill(&sc->calib); tasklet_kill(&sc->calib);
@ -2838,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw)
INIT_WORK(&sc->reset_work, ath5k_reset_work); INIT_WORK(&sc->reset_work, ath5k_reset_work);
INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
ret = ath5k_eeprom_read_mac(ah, mac); ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);
if (ret) { if (ret) {
ATH5K_ERR(sc, "unable to read address from EEPROM\n"); ATH5K_ERR(sc, "unable to read address from EEPROM\n");
goto err_queues; goto err_queues;
@ -2898,7 +2940,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc)
* XXX: ??? detach ath5k_hw ??? * XXX: ??? detach ath5k_hw ???
* Other than that, it's straightforward... * Other than that, it's straightforward...
*/ */
ath5k_debug_finish_device(sc);
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
ath5k_desc_free(sc); ath5k_desc_free(sc);
ath5k_txq_release(sc); ath5k_txq_release(sc);

View File

@ -193,12 +193,13 @@ struct ath5k_softc {
dma_addr_t desc_daddr; /* DMA (physical) address */ dma_addr_t desc_daddr; /* DMA (physical) address */
size_t desc_len; /* size of TX/RX descriptors */ size_t desc_len; /* size of TX/RX descriptors */
DECLARE_BITMAP(status, 5); DECLARE_BITMAP(status, 6);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_INVALID 0 /* disable hardware accesses */
#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
#define ATH_STAT_PROMISC 2 #define ATH_STAT_PROMISC 2
#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
#define ATH_STAT_STARTED 4 /* opened & irqs enabled */ #define ATH_STAT_STARTED 4 /* opened & irqs enabled */
#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
struct ieee80211_channel *curchan; /* current h/w channel */ struct ieee80211_channel *curchan; /* current h/w channel */
@ -207,6 +208,10 @@ struct ath5k_softc {
enum ath5k_int imask; /* interrupt mask copy */ enum ath5k_int imask; /* interrupt mask copy */
spinlock_t irqlock;
bool rx_pending; /* rx tasklet pending */
bool tx_pending; /* tx tasklet pending */
u8 lladdr[ETH_ALEN]; u8 lladdr[ETH_ALEN];
u8 bssidmask[ETH_ALEN]; u8 bssidmask[ETH_ALEN];

View File

@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
} }
} }
if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112)
__clear_bit(AR5K_MODE_11A, caps->cap_mode);
/* Set number of supported TX queues */ /* Set number of supported TX queues */
if (ah->ah_version == AR5K_AR5210) if (ah->ah_version == AR5K_AR5210)
caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU;

View File

@ -888,65 +888,38 @@ static const struct file_operations fops_queue = {
void void
ath5k_debug_init_device(struct ath5k_softc *sc) ath5k_debug_init_device(struct ath5k_softc *sc)
{ {
struct dentry *phydir;
sc->debug.level = ath5k_debug; sc->debug.level = ath5k_debug;
sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir);
sc->hw->wiphy->debugfsdir); if (!phydir)
return;
sc->debug.debugfs_debug = debugfs_create_file("debug", debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc,
S_IWUSR | S_IRUSR, &fops_debug);
sc->debug.debugfs_phydir, sc, &fops_debug);
sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers);
sc->debug.debugfs_phydir, sc, &fops_registers);
sc->debug.debugfs_beacon = debugfs_create_file("beacon", debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc,
S_IWUSR | S_IRUSR, &fops_beacon);
sc->debug.debugfs_phydir, sc, &fops_beacon);
sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset);
sc->debug.debugfs_phydir, sc, &fops_reset);
sc->debug.debugfs_antenna = debugfs_create_file("antenna", debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc,
S_IWUSR | S_IRUSR, &fops_antenna);
sc->debug.debugfs_phydir, sc, &fops_antenna);
sc->debug.debugfs_misc = debugfs_create_file("misc", debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc);
S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_misc);
sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc,
S_IWUSR | S_IRUSR, &fops_frameerrors);
sc->debug.debugfs_phydir, sc,
&fops_frameerrors);
sc->debug.debugfs_ani = debugfs_create_file("ani", debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani);
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc,
&fops_ani);
sc->debug.debugfs_queue = debugfs_create_file("queue", debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc,
S_IWUSR | S_IRUSR, &fops_queue);
sc->debug.debugfs_phydir, sc,
&fops_queue);
} }
void
ath5k_debug_finish_device(struct ath5k_softc *sc)
{
debugfs_remove(sc->debug.debugfs_debug);
debugfs_remove(sc->debug.debugfs_registers);
debugfs_remove(sc->debug.debugfs_beacon);
debugfs_remove(sc->debug.debugfs_reset);
debugfs_remove(sc->debug.debugfs_antenna);
debugfs_remove(sc->debug.debugfs_misc);
debugfs_remove(sc->debug.debugfs_frameerrors);
debugfs_remove(sc->debug.debugfs_ani);
debugfs_remove(sc->debug.debugfs_queue);
debugfs_remove(sc->debug.debugfs_phydir);
}
/* functions used in other places */ /* functions used in other places */
void void

View File

@ -68,17 +68,6 @@ struct ath5k_buf;
struct ath5k_dbg_info { struct ath5k_dbg_info {
unsigned int level; /* debug level */ unsigned int level; /* debug level */
/* debugfs entries */
struct dentry *debugfs_phydir;
struct dentry *debugfs_debug;
struct dentry *debugfs_registers;
struct dentry *debugfs_beacon;
struct dentry *debugfs_reset;
struct dentry *debugfs_antenna;
struct dentry *debugfs_misc;
struct dentry *debugfs_frameerrors;
struct dentry *debugfs_ani;
struct dentry *debugfs_queue;
}; };
/** /**
@ -140,9 +129,6 @@ enum ath5k_debug_level {
void void
ath5k_debug_init_device(struct ath5k_softc *sc); ath5k_debug_init_device(struct ath5k_softc *sc);
void
ath5k_debug_finish_device(struct ath5k_softc *sc);
void void
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
@ -166,9 +152,6 @@ ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...)
static inline void static inline void
ath5k_debug_init_device(struct ath5k_softc *sc) {} ath5k_debug_init_device(struct ath5k_softc *sc) {}
static inline void
ath5k_debug_finish_device(struct ath5k_softc *sc) {}
static inline void static inline void
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}

View File

@ -185,6 +185,12 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len; unsigned int frame_len;
/*
* Use local variables for these to reduce load/store access on
* uncached memory
*/
u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
/* /*
@ -208,8 +214,9 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (tx_power > AR5K_TUNE_MAX_TXPOWER) if (tx_power > AR5K_TUNE_MAX_TXPOWER)
tx_power = AR5K_TUNE_MAX_TXPOWER; tx_power = AR5K_TUNE_MAX_TXPOWER;
/* Clear descriptor */ /* Clear descriptor status area */
memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); memset(&desc->ud.ds_tx5212.tx_stat, 0,
sizeof(desc->ud.ds_tx5212.tx_stat));
/* Setup control descriptor */ /* Setup control descriptor */
@ -221,7 +228,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL; return -EINVAL;
tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */ /* Verify and set buffer length */
@ -232,21 +239,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL; return -EINVAL;
tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
tx_ctl->tx_control_0 |= txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
tx_ctl->tx_control_1 |= AR5K_REG_SM(type, txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
#define _TX_FLAGS(_c, _flag) \ #define _TX_FLAGS(_c, _flag) \
if (flags & AR5K_TXDESC_##_flag) { \ if (flags & AR5K_TXDESC_##_flag) { \
tx_ctl->tx_control_##_c |= \ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
} }
_TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, CLRDMASK);
@ -262,8 +265,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
* WEP crap * WEP crap
*/ */
if (key_index != AR5K_TXKEYIX_INVALID) { if (key_index != AR5K_TXKEYIX_INVALID) {
tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, txctl1 |= AR5K_REG_SM(key_index,
AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
} }
@ -274,12 +277,16 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if ((flags & AR5K_TXDESC_RTSENA) && if ((flags & AR5K_TXDESC_RTSENA) &&
(flags & AR5K_TXDESC_CTSENA)) (flags & AR5K_TXDESC_CTSENA))
return -EINVAL; return -EINVAL;
tx_ctl->tx_control_2 |= rtscts_duration & txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
AR5K_4W_TX_DESC_CTL2_RTS_DURATION; txctl3 |= AR5K_REG_SM(rtscts_rate,
tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
} }
tx_ctl->tx_control_0 = txctl0;
tx_ctl->tx_control_1 = txctl1;
tx_ctl->tx_control_2 = txctl2;
tx_ctl->tx_control_3 = txctl3;
return 0; return 0;
} }
@ -364,7 +371,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
/*TODO: ts->ts_virtcol + test*/ /*TODO: ts->ts_virtcol + test*/
ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
@ -373,9 +380,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
ts->ts_antenna = 1; ts->ts_antenna = 1;
ts->ts_status = 0; ts->ts_status = 0;
ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
ts->ts_retry[0] = ts->ts_longretry;
ts->ts_final_idx = 0; ts->ts_final_idx = 0;
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
@ -401,81 +405,48 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
{ {
struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_4w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status; struct ath5k_hw_tx_status *tx_status;
u32 txstat0, txstat1;
tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
tx_status = &desc->ud.ds_tx5212.tx_stat; tx_status = &desc->ud.ds_tx5212.tx_stat;
txstat1 = ACCESS_ONCE(tx_status->tx_status_1);
/* No frame has been send or error */ /* No frame has been send or error */
if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
return -EINPROGRESS; return -EINPROGRESS;
txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
/* /*
* Get descriptor status * Get descriptor status
*/ */
ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, ts->ts_tstamp = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, ts->ts_shortretry = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, ts->ts_final_retry = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, ts->ts_seqnum = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_SEQ_NUM); AR5K_DESC_TX_STATUS1_SEQ_NUM);
ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, ts->ts_rssi = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
ts->ts_antenna = (tx_status->tx_status_1 & ts->ts_antenna = (txstat1 &
AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
ts->ts_status = 0; ts->ts_status = 0;
ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, ts->ts_final_idx = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
/* The longretry counter has the number of un-acked retries
* for the final rate. To get the total number of retries
* we have to add the retry counters for the other rates
* as well
*/
ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
switch (ts->ts_final_idx) {
case 3:
ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
ts->ts_longretry += ts->ts_retry[2];
/* fall through */
case 2:
ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
ts->ts_longretry += ts->ts_retry[1];
/* fall through */
case 1:
ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
ts->ts_longretry += ts->ts_retry[0];
/* fall through */
case 0:
ts->ts_rate[0] = tx_ctl->tx_control_3 &
AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
break;
}
/* TX error */ /* TX error */
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
if (tx_status->tx_status_0 & if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
ts->ts_status |= AR5K_TXERR_XRETRY; ts->ts_status |= AR5K_TXERR_XRETRY;
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
ts->ts_status |= AR5K_TXERR_FIFO; ts->ts_status |= AR5K_TXERR_FIFO;
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
ts->ts_status |= AR5K_TXERR_FILT; ts->ts_status |= AR5K_TXERR_FILT;
} }
@ -609,37 +580,37 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_rx_status *rs) struct ath5k_rx_status *rs)
{ {
struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_status *rx_status;
u32 rxstat0, rxstat1;
rx_status = &desc->ud.ds_rx.rx_stat; rx_status = &desc->ud.ds_rx.rx_stat;
rxstat1 = ACCESS_ONCE(rx_status->rx_status_1);
/* No frame received / not ready */ /* No frame received / not ready */
if (unlikely(!(rx_status->rx_status_1 & if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
AR5K_5212_RX_DESC_STATUS1_DONE)))
return -EINPROGRESS; return -EINPROGRESS;
memset(rs, 0, sizeof(struct ath5k_rx_status)); memset(rs, 0, sizeof(struct ath5k_rx_status));
rxstat0 = ACCESS_ONCE(rx_status->rx_status_0);
/* /*
* Frame receive status * Frame receive status
*/ */
rs->rs_datalen = rx_status->rx_status_0 & rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
AR5K_5212_RX_DESC_STATUS0_DATA_LEN; rs->rs_rssi = AR5K_REG_MS(rxstat0,
rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, rs->rs_rate = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, rs->rs_antenna = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
rs->rs_more = !!(rx_status->rx_status_0 & rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
AR5K_5212_RX_DESC_STATUS0_MORE); rs->rs_tstamp = AR5K_REG_MS(rxstat1,
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
/* /*
* Key table status * Key table status
*/ */
if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, rs->rs_keyix = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
else else
rs->rs_keyix = AR5K_RXKEYIX_INVALID; rs->rs_keyix = AR5K_RXKEYIX_INVALID;
@ -647,27 +618,22 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
/* /*
* Receive/descriptor errors * Receive/descriptor errors
*/ */
if (!(rx_status->rx_status_1 & if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
if (rx_status->rx_status_1 &
AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_CRC; rs->rs_status |= AR5K_RXERR_CRC;
if (rx_status->rx_status_1 & if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY; rs->rs_status |= AR5K_RXERR_PHY;
rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, rs->rs_phyerr = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
if (!ah->ah_capabilities.cap_has_phyerr_counters) if (!ah->ah_capabilities.cap_has_phyerr_counters)
ath5k_ani_phy_error_report(ah, rs->rs_phyerr); ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
} }
if (rx_status->rx_status_1 & if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_DECRYPT; rs->rs_status |= AR5K_RXERR_DECRYPT;
if (rx_status->rx_status_1 & if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
rs->rs_status |= AR5K_RXERR_MIC; rs->rs_status |= AR5K_RXERR_MIC;
} }
return 0; return 0;

View File

@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
} }
static int
ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
struct ath5k_chan_pcal_info *chinfo;
u8 pier, pdg;
switch (mode) {
case AR5K_EEPROM_MODE_11A:
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_a;
break;
case AR5K_EEPROM_MODE_11B:
if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_b;
break;
case AR5K_EEPROM_MODE_11G:
if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_g;
break;
default:
return -EINVAL;
}
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
if (!chinfo[pier].pd_curves)
continue;
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
struct ath5k_pdgain_info *pd =
&chinfo[pier].pd_curves[pdg];
if (pd != NULL) {
kfree(pd->pd_step);
kfree(pd->pd_pwr);
}
}
kfree(chinfo[pier].pd_curves);
}
return 0;
}
/* Convert RF5111 specific data to generic raw data /* Convert RF5111 specific data to generic raw data
* used by interpolation code */ * used by interpolation code */
static int static int
@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
GFP_KERNEL); GFP_KERNEL);
if (!chinfo[pier].pd_curves) if (!chinfo[pier].pd_curves)
return -ENOMEM; goto err_out;
/* Only one curve for RF5111 /* Only one curve for RF5111
* find out which one and place * find out which one and place
@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* (convert power to 0.25dB units * (convert power to 0.25dB units
@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
} }
return 0; return 0;
err_out:
ath5k_eeprom_free_pcal_info(ah, mode);
return -ENOMEM;
} }
/* Parse EEPROM data */ /* Parse EEPROM data */
@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
GFP_KERNEL); GFP_KERNEL);
if (!chinfo[pier].pd_curves) if (!chinfo[pier].pd_curves)
return -ENOMEM; goto err_out;
/* Fill pd_curves */ /* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points, pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* (all power levels are in 0.25dB units) */ * (all power levels are in 0.25dB units) */
@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points, pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* (all power levels are in 0.25dB units) */ * (all power levels are in 0.25dB units) */
@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
} }
return 0; return 0;
err_out:
ath5k_eeprom_free_pcal_info(ah, mode);
return -ENOMEM;
} }
/* Parse EEPROM data */ /* Parse EEPROM data */
@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
GFP_KERNEL); GFP_KERNEL);
if (!chinfo[pier].pd_curves) if (!chinfo[pier].pd_curves)
return -ENOMEM; goto err_out;
/* Fill pd_curves */ /* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points, pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* convert all pwr levels to * convert all pwr levels to
@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
} }
return 0; return 0;
err_out:
ath5k_eeprom_free_pcal_info(ah, mode);
return -ENOMEM;
} }
/* Parse EEPROM data */ /* Parse EEPROM data */
@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
return 0; return 0;
} }
static int
ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
struct ath5k_chan_pcal_info *chinfo;
u8 pier, pdg;
switch (mode) {
case AR5K_EEPROM_MODE_11A:
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_a;
break;
case AR5K_EEPROM_MODE_11B:
if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_b;
break;
case AR5K_EEPROM_MODE_11G:
if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_g;
break;
default:
return -EINVAL;
}
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
if (!chinfo[pier].pd_curves)
continue;
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
struct ath5k_pdgain_info *pd =
&chinfo[pier].pd_curves[pdg];
if (pd != NULL) {
kfree(pd->pd_step);
kfree(pd->pd_pwr);
}
}
kfree(chinfo[pier].pd_curves);
}
return 0;
}
/* Read conformance test limits used for regulatory control */ /* Read conformance test limits used for regulatory control */
static int static int
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
@ -1721,35 +1732,6 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)
return ret; return ret;
} }
/*
* Read the MAC address from eeprom
*/
int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
{
u8 mac_d[ETH_ALEN] = {};
u32 total, offset;
u16 data;
int octet;
AR5K_EEPROM_READ(0x20, data);
for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
AR5K_EEPROM_READ(offset, data);
total += data;
mac_d[octet + 1] = data & 0xff;
mac_d[octet] = data >> 8;
octet += 2;
}
if (!total || total == 3 * 0xffff)
return -EINVAL;
memcpy(mac, mac_d, ETH_ALEN);
return 0;
}
/***********************\ /***********************\
* Init/Detach functions * * Init/Detach functions *

View File

@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changes & BSS_CHANGED_BEACON_INT) if (changes & BSS_CHANGED_BEACON_INT)
sc->bintval = bss_conf->beacon_int; sc->bintval = bss_conf->beacon_int;
if (changes & BSS_CHANGED_ERP_SLOT) {
int slot_time;
ah->ah_short_slot = bss_conf->use_short_slot;
slot_time = ath5k_hw_get_default_slottime(ah) +
3 * ah->ah_coverage_class;
ath5k_hw_set_ifs_intervals(ah, slot_time);
}
if (changes & BSS_CHANGED_ASSOC) { if (changes & BSS_CHANGED_ASSOC) {
avf->assoc = bss_conf->assoc; avf->assoc = bss_conf->assoc;
if (bss_conf->assoc) if (bss_conf->assoc)

View File

@ -17,6 +17,7 @@
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include <linux/etherdevice.h>
#include "../ath.h" #include "../ath.h"
#include "ath5k.h" #include "ath5k.h"
#include "debug.h" #include "debug.h"
@ -108,11 +109,42 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
return 0; return 0;
} }
/*
* Read the MAC address from eeprom or platform_data
*/
static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
{
u8 mac_d[ETH_ALEN] = {};
u32 total, offset;
u16 data;
int octet;
AR5K_EEPROM_READ(0x20, data);
for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
AR5K_EEPROM_READ(offset, data);
total += data;
mac_d[octet + 1] = data & 0xff;
mac_d[octet] = data >> 8;
octet += 2;
}
if (!total || total == 3 * 0xffff)
return -EINVAL;
memcpy(mac, mac_d, ETH_ALEN);
return 0;
}
/* Common ath_bus_opts structure */ /* Common ath_bus_opts structure */
static const struct ath_bus_ops ath_pci_bus_ops = { static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI, .ath_bus_type = ATH_PCI,
.read_cachesize = ath5k_pci_read_cachesize, .read_cachesize = ath5k_pci_read_cachesize,
.eeprom_read = ath5k_pci_eeprom_read, .eeprom_read = ath5k_pci_eeprom_read,
.eeprom_read_mac = ath5k_pci_eeprom_read_mac,
}; };
/********************\ /********************\

View File

@ -75,7 +75,7 @@ static const unsigned int ack_rates_high[] =
* bwmodes. * bwmodes.
*/ */
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
int len, struct ieee80211_rate *rate) int len, struct ieee80211_rate *rate, bool shortpre)
{ {
struct ath5k_softc *sc = ah->ah_sc; struct ath5k_softc *sc = ah->ah_sc;
int sifs, preamble, plcp_bits, sym_time; int sifs, preamble, plcp_bits, sym_time;
@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
/* Fallback */ /* Fallback */
if (!ah->ah_bwmode) { if (!ah->ah_bwmode) {
dur = ieee80211_generic_frame_duration(sc->hw, __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw,
NULL, len, rate); NULL, len, rate);
return le16_to_cpu(dur);
/* subtract difference between long and short preamble */
dur = le16_to_cpu(raw_dur);
if (shortpre)
dur -= 96;
return dur;
} }
bitrate = rate->bitrate; bitrate = rate->bitrate;
@ -145,9 +151,9 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
break; break;
case AR5K_BWMODE_DEFAULT: case AR5K_BWMODE_DEFAULT:
slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
default: default:
if (channel->hw_value & CHANNEL_CCK) slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
slot_time = AR5K_INIT_SLOT_TIME_B; slot_time = AR5K_INIT_SLOT_TIME_B;
break; break;
} }
@ -263,27 +269,14 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
* actual rate for this rate. See mac80211 tx.c * actual rate for this rate. See mac80211 tx.c
* ieee80211_duration() for a brief description of * ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */ * what rate we should choose to TX ACKs. */
tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
ath5k_hw_reg_write(ah, tx_time, reg); ath5k_hw_reg_write(ah, tx_time, reg);
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
continue; continue;
/* tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true);
* We're not distinguishing short preamble here,
* This is true, all we'll get is a longer value here
* which is not necessarilly bad. We could use
* export ieee80211_frame_duration() but that needs to be
* fixed first to be properly used by mac802111 drivers:
*
* - remove erp stuff and let the routine figure ofdm
* erp rates
* - remove passing argument ieee80211_local as
* drivers don't have access to it
* - move drivers using ieee80211_generic_frame_duration()
* to this
*/
ath5k_hw_reg_write(ah, tx_time, ath5k_hw_reg_write(ah, tx_time,
reg + (AR5K_SET_SHORT_PREAMBLE << 2)); reg + (AR5K_SET_SHORT_PREAMBLE << 2));
} }

View File

@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
return -EINVAL; return -EINVAL;
sifs = ath5k_hw_get_default_sifs(ah); sifs = ath5k_hw_get_default_sifs(ah);
sifs_clock = ath5k_hw_htoclock(ah, sifs); sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
/* EIFS /* EIFS
* Txtime of ack at lowest rate + SIFS + DIFS * Txtime of ack at lowest rate + SIFS + DIFS
@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
else else
rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
/* ack_tx_time includes an SIFS already */ /* ack_tx_time includes an SIFS already */
eifs = ack_tx_time + sifs + 2 * slot_time; eifs = ack_tx_time + sifs + 2 * slot_time;

View File

@ -5,7 +5,7 @@ config ATH9K_COMMON
config ATH9K config ATH9K
tristate "Atheros 802.11n wireless cards support" tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 depends on MAC80211
select ATH9K_HW select ATH9K_HW
select MAC80211_LEDS select MAC80211_LEDS
select LEDS_CLASS select LEDS_CLASS
@ -23,6 +23,25 @@ config ATH9K
If you choose to build a module, it'll be called ath9k. If you choose to build a module, it'll be called ath9k.
config ATH9K_PCI
bool "Atheros ath9k PCI/PCIe bus support"
depends on ATH9K && PCI
default PCI
---help---
This option enables the PCI bus support in ath9k.
Say Y, if you have a compatible PCI/PCIe wireless card.
config ATH9K_AHB
bool "Atheros ath9k AHB bus support"
depends on ATH9K
default n
---help---
This option enables the AHB bus support in ath9k.
Say Y, if you have a SoC with a compatible built-in
wireless MAC. Say N if unsure.
config ATH9K_DEBUGFS config ATH9K_DEBUGFS
bool "Atheros ath9k debugging" bool "Atheros ath9k debugging"
depends on ATH9K && DEBUG_FS depends on ATH9K && DEBUG_FS

View File

@ -6,8 +6,8 @@ ath9k-y += beacon.o \
xmit.o \ xmit.o \
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_PCI) += pci.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o obj-$(CONFIG_ATH9K) += ath9k.o
@ -48,4 +48,6 @@ ath9k_htc-y += htc_hst.o \
htc_drv_init.o \ htc_drv_init.o \
htc_drv_gpio.o htc_drv_gpio.o
ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o

View File

@ -21,6 +21,14 @@
#include <linux/ath9k_platform.h> #include <linux/ath9k_platform.h>
#include "ath9k.h" #include "ath9k.h"
const struct platform_device_id ath9k_platform_id_table[] = {
{
.name = "ath9k",
.driver_data = AR5416_AR9100_DEVID,
},
{},
};
/* return bus cachesize in 4B word units */ /* return bus cachesize in 4B word units */
static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
{ {
@ -57,6 +65,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
struct ath_softc *sc; struct ath_softc *sc;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct resource *res; struct resource *res;
const struct platform_device_id *id = platform_get_device_id(pdev);
int irq; int irq;
int ret = 0; int ret = 0;
struct ath_hw *ah; struct ath_hw *ah;
@ -116,7 +125,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
goto err_free_hw; goto err_free_hw;
} }
ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n"); dev_err(&pdev->dev, "failed to initialize device\n");
goto err_irq; goto err_irq;
@ -165,8 +174,11 @@ static struct platform_driver ath_ahb_driver = {
.name = "ath9k", .name = "ath9k",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.id_table = ath9k_platform_id_table,
}; };
MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table);
int ath_ahb_init(void) int ath_ahb_init(void)
{ {
return platform_driver_register(&ath_ahb_driver); return platform_driver_register(&ath_ahb_driver);

View File

@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(txPower, AR_XmitPower) | SM(txPower, AR_XmitPower)
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
} }
} }
static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
struct ar5416_desc *ads = AR5416DESC(ds);
if (val)
ads->ds_ctl0 |= AR_ClrDestMask;
else
ads->ds_ctl0 &= ~AR_ClrDestMask;
}
static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
void *lastds, void *lastds,
u32 durUpdateEn, u32 rtsctsRate, u32 durUpdateEn, u32 rtsctsRate,
@ -448,4 +457,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9002_hw_clr11n_aggr; ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
ops->set11n_burstduration = ar9002_hw_set11n_burstduration; ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
ops->set_clrdmask = ar9002_hw_set_clrdmask;
} }

View File

@ -483,7 +483,11 @@
#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000
#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19
#define AR_PHY_TX_PWRCTRL8 0xa278
#define AR_PHY_TX_PWRCTRL9 0xa27C #define AR_PHY_TX_PWRCTRL9 0xa27C
#define AR_PHY_TX_PWRCTRL10 0xa394
#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00
#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10
#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000
@ -495,6 +499,8 @@
#define AR_PHY_CH0_TX_PWRCTRL11 0xa398 #define AR_PHY_CH0_TX_PWRCTRL11 0xa398
#define AR_PHY_CH1_TX_PWRCTRL11 0xb398 #define AR_PHY_CH1_TX_PWRCTRL11 0xb398
#define AR_PHY_CH0_TX_PWRCTRL12 0xa3dc
#define AR_PHY_CH0_TX_PWRCTRL13 0xa3e0
#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00
#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10

View File

@ -34,10 +34,10 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {
static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@ -119,14 +119,14 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@ -835,10 +835,10 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@ -920,14 +920,14 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@ -941,10 +941,10 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@ -1026,14 +1026,14 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@ -1307,10 +1307,10 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@ -1329,21 +1329,21 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@ -1361,45 +1361,45 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},

View File

@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(txpower, AR_XmitPower) | SM(txpower, AR_XmitPower)
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
ads->ctl22 = 0; ads->ctl22 = 0;
} }
static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
struct ar9003_txc *ads = (struct ar9003_txc *) ds;
if (val)
ads->ctl11 |= AR_ClrDestMask;
else
ads->ctl11 &= ~AR_ClrDestMask;
}
static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
void *lastds, void *lastds,
u32 durUpdateEn, u32 rtsctsRate, u32 durUpdateEn, u32 rtsctsRate,
@ -510,6 +519,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9003_hw_clr11n_aggr; ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
ops->set11n_burstduration = ar9003_hw_set11n_burstduration; ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
ops->set_clrdmask = ar9003_hw_set_clrdmask;
} }
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)

View File

@ -75,9 +75,18 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
freq = centers.synth_center; freq = centers.synth_center;
if (freq < 4800) { /* 2 GHz, fractional mode */ if (freq < 4800) { /* 2 GHz, fractional mode */
if (AR_SREV_9485(ah)) if (AR_SREV_9485(ah)) {
channelSel = CHANSEL_2G_9485(freq); u32 chan_frac;
else
/*
* freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
* ndiv = ((chan_mhz * 4) / 3) / freq_ref;
* chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
*/
channelSel = (freq * 4) / 120;
chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
channelSel = (channelSel << 17) | chan_frac;
} else
channelSel = CHANSEL_2G(freq); channelSel = CHANSEL_2G(freq);
/* Set to 2G mode */ /* Set to 2G mode */
bMode = 1; bMode = 1;
@ -401,7 +410,7 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
ar9003_hw_spur_ofdm_clear(ah); ar9003_hw_spur_ofdm_clear(ah);
for (i = 0; spurChansPtr[i] && i < 5; i++) { for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) {
freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq;
if (abs(freq_offset) < range) { if (abs(freq_offset) < range) {
ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);

View File

@ -396,7 +396,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@ -469,7 +469,7 @@ static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@ -635,7 +635,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@ -728,7 +728,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@ -827,7 +827,7 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},

View File

@ -200,6 +200,7 @@ struct ath_atx_ac {
int sched; int sched;
struct list_head list; struct list_head list;
struct list_head tid_q; struct list_head tid_q;
bool clear_ps_filter;
}; };
struct ath_frame_info { struct ath_frame_info {
@ -255,8 +256,12 @@ struct ath_node {
#endif #endif
struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC]; struct ath_atx_ac ac[WME_NUM_AC];
int ps_key;
u16 maxampdu; u16 maxampdu;
u8 mpdudensity; u8 mpdudensity;
bool sleeping;
}; };
#define AGGR_CLEANUP BIT(1) #define AGGR_CLEANUP BIT(1)
@ -338,6 +343,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); 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 ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
/********/ /********/
/* VIFs */ /* VIFs */
/********/ /********/
@ -665,7 +673,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
bool ath9k_uses_beacons(int type); bool ath9k_uses_beacons(int type);
#ifdef CONFIG_PCI #ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void); int ath_pci_init(void);
void ath_pci_exit(void); void ath_pci_exit(void);
#else #else
@ -673,7 +681,7 @@ static inline int ath_pci_init(void) { return 0; };
static inline void ath_pci_exit(void) {}; static inline void ath_pci_exit(void) {};
#endif #endif
#ifdef CONFIG_ATHEROS_AR71XX #ifdef CONFIG_ATH9K_AHB
int ath_ahb_init(void); int ath_ahb_init(void);
void ath_ahb_exit(void); void ath_ahb_exit(void);
#else #else

View File

@ -320,6 +320,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
if (avp->av_bcbuf != NULL) { if (avp->av_bcbuf != NULL) {
struct ath_buf *bf; struct ath_buf *bf;
avp->is_bslot_active = false;
if (avp->av_bslot != -1) { if (avp->av_bslot != -1) {
sc->beacon.bslot[avp->av_bslot] = NULL; sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--; sc->nbcnvifs--;
@ -743,37 +744,10 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
cur_conf->dtim_period = 1; cur_conf->dtim_period = 1;
ath_set_beacon(sc); ath_set_beacon(sc);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
} }
void ath_set_beacon(struct ath_softc *sc) static bool ath_has_valid_bslot(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath_beacon_config_adhoc(sc, cur_conf);
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, cur_conf);
break;
default:
ath_dbg(common, ATH_DBG_CONFIG,
"Unsupported beaconing mode\n");
return;
}
sc->sc_flags |= SC_OP_BEACONS;
}
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_vif *avp; struct ath_vif *avp;
int slot; int slot;
bool found = false; bool found = false;
@ -787,7 +761,47 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
} }
} }
} }
if (!found) return found;
}
void ath_set_beacon(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
if (ath_has_valid_bslot(sc))
ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath_beacon_config_adhoc(sc, cur_conf);
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, cur_conf);
/*
* Request a re-configuration of Beacon related timers
* on the receipt of the first Beacon frame (i.e.,
* after time sync with the AP).
*/
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
break;
default:
ath_dbg(common, ATH_DBG_CONFIG,
"Unsupported beaconing mode\n");
return;
}
sc->sc_flags |= SC_OP_BEACONS;
}
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
struct ath_hw *ah = sc->sc_ah;
if (!ath_has_valid_bslot(sc))
return; return;
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);

View File

@ -845,7 +845,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
char *buf; char *buf;
unsigned int len = 0, size = 1152; unsigned int len = 0, size = 1400;
ssize_t retval = 0; ssize_t retval = 0;
buf = kzalloc(size, GFP_KERNEL); buf = kzalloc(size, GFP_KERNEL);
@ -874,6 +874,34 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
"%18s : %10u\n", "DECRYPT BUSY ERR", "%18s : %10u\n", "DECRYPT BUSY ERR",
sc->debug.stats.rxstats.decrypt_busy_err); sc->debug.stats.rxstats.decrypt_busy_err);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "RSSI-CTL0",
sc->debug.stats.rxstats.rs_rssi_ctl0);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "RSSI-CTL1",
sc->debug.stats.rxstats.rs_rssi_ctl1);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "RSSI-CTL2",
sc->debug.stats.rxstats.rs_rssi_ctl2);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "RSSI-EXT0",
sc->debug.stats.rxstats.rs_rssi_ext0);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "RSSI-EXT1",
sc->debug.stats.rxstats.rs_rssi_ext1);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "RSSI-EXT2",
sc->debug.stats.rxstats.rs_rssi_ext2);
len += snprintf(buf + len, size - len,
"%18s : %10d\n", "Rx Antenna",
sc->debug.stats.rxstats.rs_antenna);
PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
@ -948,6 +976,16 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
RX_PHY_ERR_INC(phyerr); RX_PHY_ERR_INC(phyerr);
} }
sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0;
sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1;
sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2;
sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0;
sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1;
sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2;
sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna;
#undef RX_STAT_INC #undef RX_STAT_INC
#undef RX_PHY_ERR_INC #undef RX_PHY_ERR_INC
} }

View File

@ -157,6 +157,13 @@ struct ath_rx_stats {
u32 post_delim_crc_err; u32 post_delim_crc_err;
u32 decrypt_busy_err; u32 decrypt_busy_err;
u32 phy_err_stats[ATH9K_PHYERR_MAX]; u32 phy_err_stats[ATH9K_PHYERR_MAX];
int8_t rs_rssi_ctl0;
int8_t rs_rssi_ctl1;
int8_t rs_rssi_ctl2;
int8_t rs_rssi_ext0;
int8_t rs_rssi_ext1;
int8_t rs_rssi_ext2;
u8 rs_antenna;
}; };
struct ath_stats { struct ath_stats {

View File

@ -436,7 +436,11 @@ struct modal_eep_4k_header {
u8 db2_2:4, db2_3:4; u8 db2_2:4, db2_3:4;
u8 db2_4:4, reserved:4; u8 db2_4:4, reserved:4;
#endif #endif
u8 futureModal[4]; u8 tx_diversity;
u8 flc_pwr_thresh;
u8 bb_scale_smrt_antenna;
#define EEP_4K_BB_DESIRED_SCALE_MASK 0x1f
u8 futureModal[1];
struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS]; struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
} __packed; } __packed;

View File

@ -781,6 +781,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
{ {
struct modal_eep_4k_header *pModal; struct modal_eep_4k_header *pModal;
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
struct base_eep_header_4k *pBase = &eep->baseEepHeader;
u8 txRxAttenLocal; u8 txRxAttenLocal;
u8 ob[5], db1[5], db2[5]; u8 ob[5], db1[5], db2[5];
u8 ant_div_control1, ant_div_control2; u8 ant_div_control1, ant_div_control2;
@ -1003,6 +1004,31 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
AR_PHY_SETTLING_SWITCH, AR_PHY_SETTLING_SWITCH,
pModal->swSettleHt40); pModal->swSettleHt40);
} }
if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
EEP_4K_BB_DESIRED_SCALE_MASK);
if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
u32 pwrctrl, mask, clr;
mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
pwrctrl = mask * bb_desired_scale;
clr = mask * 0x1f;
REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
mask = BIT(0)|BIT(5)|BIT(15);
pwrctrl = mask * bb_desired_scale;
clr = mask * 0x1f;
REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
mask = BIT(0)|BIT(5);
pwrctrl = mask * bb_desired_scale;
clr = mask * 0x1f;
REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
}
}
} }
static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)

View File

@ -858,35 +858,12 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
{ {
struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader; struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
u16 antWrites[AR9287_ANT_16S];
u32 regChainOffset, regval; u32 regChainOffset, regval;
u8 txRxAttenLocal; u8 txRxAttenLocal;
int i, j, offset_num; int i;
pModal = &eep->modalHeader; pModal = &eep->modalHeader;
antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF);
antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
offset_num = 8;
for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
antWrites[j++] = 0;
antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
}
REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
for (i = 0; i < AR9287_MAX_CHAINS; i++) { for (i = 0; i < AR9287_MAX_CHAINS; i++) {

View File

@ -17,11 +17,9 @@
#include "htc.h" #include "htc.h"
/* identify firmware images */ /* identify firmware images */
#define FIRMWARE_AR7010 "ar7010.fw" #define FIRMWARE_AR7010_1_1 "htc_7010.fw"
#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw" #define FIRMWARE_AR9271 "htc_9271.fw"
#define FIRMWARE_AR9271 "ar9271.fw"
MODULE_FIRMWARE(FIRMWARE_AR7010);
MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
MODULE_FIRMWARE(FIRMWARE_AR9271); MODULE_FIRMWARE(FIRMWARE_AR9271);
@ -80,7 +78,7 @@ static void hif_usb_regout_cb(struct urb *urb)
if (cmd) { if (cmd) {
ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
cmd->skb, 1); cmd->skb, true);
kfree(cmd); kfree(cmd);
} }
@ -126,6 +124,90 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
return ret; return ret;
} }
static void hif_usb_mgmt_cb(struct urb *urb)
{
struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
struct hif_device_usb *hif_dev = cmd->hif_dev;
bool txok = true;
if (!cmd || !cmd->skb || !cmd->hif_dev)
return;
switch (urb->status) {
case 0:
break;
case -ENOENT:
case -ECONNRESET:
case -ENODEV:
case -ESHUTDOWN:
txok = false;
/*
* If the URBs are being flushed, no need to complete
* this packet.
*/
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
spin_unlock(&hif_dev->tx.tx_lock);
dev_kfree_skb_any(cmd->skb);
kfree(cmd);
return;
}
spin_unlock(&hif_dev->tx.tx_lock);
break;
default:
txok = false;
break;
}
skb_pull(cmd->skb, 4);
ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
cmd->skb, txok);
kfree(cmd);
}
static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
struct sk_buff *skb)
{
struct urb *urb;
struct cmd_buf *cmd;
int ret = 0;
__le16 *hdr;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (urb == NULL)
return -ENOMEM;
cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
if (cmd == NULL) {
usb_free_urb(urb);
return -ENOMEM;
}
cmd->skb = skb;
cmd->hif_dev = hif_dev;
hdr = (__le16 *) skb_push(skb, 4);
*hdr++ = cpu_to_le16(skb->len - 4);
*hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
usb_fill_bulk_urb(urb, hif_dev->udev,
usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
skb->data, skb->len,
hif_usb_mgmt_cb, cmd);
usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
usb_unanchor_urb(urb);
kfree(cmd);
}
usb_free_urb(urb);
return ret;
}
static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
struct sk_buff_head *list) struct sk_buff_head *list)
{ {
@ -133,7 +215,22 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
while ((skb = __skb_dequeue(list)) != NULL) { while ((skb = __skb_dequeue(list)) != NULL) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
TX_STAT_INC(skb_dropped); }
}
static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
struct sk_buff_head *queue,
bool txok)
{
struct sk_buff *skb;
while ((skb = __skb_dequeue(queue)) != NULL) {
ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
skb, txok);
if (txok)
TX_STAT_INC(skb_success);
else
TX_STAT_INC(skb_failed);
} }
} }
@ -141,7 +238,7 @@ static void hif_usb_tx_cb(struct urb *urb)
{ {
struct tx_buf *tx_buf = (struct tx_buf *) urb->context; struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
struct hif_device_usb *hif_dev; struct hif_device_usb *hif_dev;
struct sk_buff *skb; bool txok = true;
if (!tx_buf || !tx_buf->hif_dev) if (!tx_buf || !tx_buf->hif_dev)
return; return;
@ -155,10 +252,7 @@ static void hif_usb_tx_cb(struct urb *urb)
case -ECONNRESET: case -ECONNRESET:
case -ENODEV: case -ENODEV:
case -ESHUTDOWN: case -ESHUTDOWN:
/* txok = false;
* The URB has been killed, free the SKBs.
*/
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
/* /*
* If the URBs are being flushed, no need to add this * If the URBs are being flushed, no need to add this
@ -167,41 +261,19 @@ static void hif_usb_tx_cb(struct urb *urb)
spin_lock(&hif_dev->tx.tx_lock); spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
spin_unlock(&hif_dev->tx.tx_lock); spin_unlock(&hif_dev->tx.tx_lock);
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
return; return;
} }
spin_unlock(&hif_dev->tx.tx_lock); spin_unlock(&hif_dev->tx.tx_lock);
/* break;
* In the stop() case, this URB has to be added to
* the free list.
*/
goto add_free;
default: default:
txok = false;
break; break;
} }
/* ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok);
* Check if TX has been stopped, this is needed because
* this CB could have been invoked just after the TX lock
* was released in hif_stop() and kill_urb() hasn't been
* called yet.
*/
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
spin_unlock(&hif_dev->tx.tx_lock);
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
goto add_free;
}
spin_unlock(&hif_dev->tx.tx_lock);
/* Complete the queued SKBs. */
while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
skb, 1);
TX_STAT_INC(skb_completed);
}
add_free:
/* Re-initialize the SKB queue */ /* Re-initialize the SKB queue */
tx_buf->len = tx_buf->offset = 0; tx_buf->len = tx_buf->offset = 0;
__skb_queue_head_init(&tx_buf->skb_queue); __skb_queue_head_init(&tx_buf->skb_queue);
@ -274,7 +346,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
if (ret) { if (ret) {
tx_buf->len = tx_buf->offset = 0; tx_buf->len = tx_buf->offset = 0;
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false);
__skb_queue_head_init(&tx_buf->skb_queue); __skb_queue_head_init(&tx_buf->skb_queue);
list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
hif_dev->tx.tx_buf_cnt++; hif_dev->tx.tx_buf_cnt++;
@ -286,10 +358,11 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
return ret; return ret;
} }
static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
struct ath9k_htc_tx_ctl *tx_ctl)
{ {
struct ath9k_htc_tx_ctl *tx_ctl;
unsigned long flags; unsigned long flags;
int ret = 0;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
@ -304,26 +377,36 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
return -ENOMEM; return -ENOMEM;
} }
__skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
hif_dev->tx.tx_skb_cnt++;
/* Send normal frames immediately */ tx_ctl = HTC_SKB_CB(skb);
if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL)))
__hif_usb_tx(hif_dev); /* Mgmt/Beacon frames don't use the TX buffer pool */
if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
(tx_ctl->type == ATH9K_HTC_BEACON)) {
ret = hif_usb_send_mgmt(hif_dev, skb);
}
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
(tx_ctl->type == ATH9K_HTC_AMPDU)) {
__skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
hif_dev->tx.tx_skb_cnt++;
}
/* Check if AMPDUs have to be sent immediately */ /* Check if AMPDUs have to be sent immediately */
if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) && if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
(hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
(hif_dev->tx.tx_skb_cnt < 2)) { (hif_dev->tx.tx_skb_cnt < 2)) {
__hif_usb_tx(hif_dev); __hif_usb_tx(hif_dev);
} }
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
return 0; return ret;
} }
static void hif_usb_start(void *hif_handle, u8 pipe_id) static void hif_usb_start(void *hif_handle)
{ {
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
unsigned long flags; unsigned long flags;
@ -335,14 +418,14 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
} }
static void hif_usb_stop(void *hif_handle, u8 pipe_id) static void hif_usb_stop(void *hif_handle)
{ {
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue); ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false);
hif_dev->tx.tx_skb_cnt = 0; hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP; hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
@ -352,17 +435,18 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
&hif_dev->tx.tx_pending, list) { &hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb); usb_kill_urb(tx_buf->urb);
} }
usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
} }
static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
struct ath9k_htc_tx_ctl *tx_ctl)
{ {
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
int ret = 0; int ret = 0;
switch (pipe_id) { switch (pipe_id) {
case USB_WLAN_TX_PIPE: case USB_WLAN_TX_PIPE:
ret = hif_usb_send_tx(hif_dev, skb, tx_ctl); ret = hif_usb_send_tx(hif_dev, skb);
break; break;
case USB_REG_OUT_PIPE: case USB_REG_OUT_PIPE:
ret = hif_usb_send_regout(hif_dev, skb); ret = hif_usb_send_regout(hif_dev, skb);
@ -377,6 +461,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
return ret; return ret;
} }
static inline bool check_index(struct sk_buff *skb, u8 idx)
{
struct ath9k_htc_tx_ctl *tx_ctl;
tx_ctl = HTC_SKB_CB(skb);
if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
(tx_ctl->sta_idx == idx))
return true;
return false;
}
static void hif_usb_sta_drain(void *hif_handle, u8 idx)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct sk_buff *skb, *tmp;
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
if (check_index(skb, idx)) {
__skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
skb, false);
hif_dev->tx.tx_skb_cnt--;
TX_STAT_INC(skb_failed);
}
}
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
}
static struct ath9k_htc_hif hif_usb = { static struct ath9k_htc_hif hif_usb = {
.transport = ATH9K_HIF_USB, .transport = ATH9K_HIF_USB,
.name = "ath9k_hif_usb", .name = "ath9k_hif_usb",
@ -386,6 +504,7 @@ static struct ath9k_htc_hif hif_usb = {
.start = hif_usb_start, .start = hif_usb_start,
.stop = hif_usb_stop, .stop = hif_usb_stop,
.sta_drain = hif_usb_sta_drain,
.send = hif_usb_send, .send = hif_usb_send,
}; };
@ -567,6 +686,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
case -ESHUTDOWN: case -ESHUTDOWN:
goto free; goto free;
default: default:
skb_reset_tail_pointer(skb);
skb_trim(skb, 0);
goto resubmit; goto resubmit;
} }
@ -591,23 +713,15 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
USB_REG_IN_PIPE), USB_REG_IN_PIPE),
nskb->data, MAX_REG_IN_BUF_SIZE, nskb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, nskb); ath9k_hif_usb_reg_in_cb, nskb);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
kfree_skb(nskb);
urb->context = NULL;
}
return;
} }
resubmit: resubmit:
skb_reset_tail_pointer(skb); usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
skb_trim(skb, 0);
ret = usb_submit_urb(urb, GFP_ATOMIC); ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) if (ret) {
usb_unanchor_urb(urb);
goto free; goto free;
}
return; return;
free: free:
@ -641,6 +755,8 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
kfree(tx_buf->buf); kfree(tx_buf->buf);
kfree(tx_buf); kfree(tx_buf);
} }
usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
} }
static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
@ -652,6 +768,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
INIT_LIST_HEAD(&hif_dev->tx.tx_pending); INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
spin_lock_init(&hif_dev->tx.tx_lock); spin_lock_init(&hif_dev->tx.tx_lock);
__skb_queue_head_init(&hif_dev->tx.tx_skb_queue); __skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
init_usb_anchor(&hif_dev->mgmt_submitted);
for (i = 0; i < MAX_TX_URB_NUM; i++) { for (i = 0; i < MAX_TX_URB_NUM; i++) {
tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
@ -748,43 +865,67 @@ err_urb:
return ret; return ret;
} }
static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
{ {
if (hif_dev->reg_in_urb) { usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
usb_kill_urb(hif_dev->reg_in_urb);
if (hif_dev->reg_in_urb->context)
kfree_skb((void *)hif_dev->reg_in_urb->context);
usb_free_urb(hif_dev->reg_in_urb);
hif_dev->reg_in_urb = NULL;
}
} }
static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
{ {
struct sk_buff *skb; struct urb *urb = NULL;
struct sk_buff *skb = NULL;
int i, ret;
hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL); init_usb_anchor(&hif_dev->reg_in_submitted);
if (hif_dev->reg_in_urb == NULL)
return -ENOMEM;
skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
if (!skb)
goto err;
usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev, /* Allocate URB */
usb_rcvbulkpipe(hif_dev->udev, urb = usb_alloc_urb(0, GFP_KERNEL);
USB_REG_IN_PIPE), if (urb == NULL) {
skb->data, MAX_REG_IN_BUF_SIZE, ret = -ENOMEM;
ath9k_hif_usb_reg_in_cb, skb); goto err_urb;
}
if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) /* Allocate buffer */
goto err; skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
if (!skb) {
ret = -ENOMEM;
goto err_skb;
}
usb_fill_bulk_urb(urb, hif_dev->udev,
usb_rcvbulkpipe(hif_dev->udev,
USB_REG_IN_PIPE),
skb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, skb);
/* Anchor URB */
usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
/* Submit URB */
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
usb_unanchor_urb(urb);
goto err_submit;
}
/*
* Drop reference count.
* This ensures that the URB is freed when killing them.
*/
usb_free_urb(urb);
}
return 0; return 0;
err: err_submit:
ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); kfree_skb(skb);
return -ENOMEM; err_skb:
usb_free_urb(urb);
err_urb:
ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
return ret;
} }
static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
@ -801,7 +942,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
goto err_rx; goto err_rx;
/* Register Read */ /* Register Read */
if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0)
goto err_reg; goto err_reg;
return 0; return 0;
@ -816,7 +957,7 @@ err:
static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
{ {
usb_kill_anchored_urbs(&hif_dev->regout_submitted); usb_kill_anchored_urbs(&hif_dev->regout_submitted);
ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
ath9k_hif_usb_dealloc_tx_urbs(hif_dev); ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
ath9k_hif_usb_dealloc_rx_urbs(hif_dev); ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
} }
@ -1026,10 +1167,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
/* Find out which firmware to load */ /* Find out which firmware to load */
if (IS_AR7010_DEVICE(id->driver_info)) if (IS_AR7010_DEVICE(id->driver_info))
if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1;
hif_dev->fw_name = FIRMWARE_AR7010_1_1;
else
hif_dev->fw_name = FIRMWARE_AR7010;
else else
hif_dev->fw_name = FIRMWARE_AR9271; hif_dev->fw_name = FIRMWARE_AR9271;

View File

@ -31,7 +31,7 @@
/* FIXME: Verify these numbers (with Windows) */ /* FIXME: Verify these numbers (with Windows) */
#define MAX_TX_URB_NUM 8 #define MAX_TX_URB_NUM 8
#define MAX_TX_BUF_NUM 1024 #define MAX_TX_BUF_NUM 256
#define MAX_TX_BUF_SIZE 32768 #define MAX_TX_BUF_SIZE 32768
#define MAX_TX_AGGR_NUM 20 #define MAX_TX_AGGR_NUM 20
@ -40,7 +40,7 @@
#define MAX_PKT_NUM_IN_TRANSFER 10 #define MAX_PKT_NUM_IN_TRANSFER 10
#define MAX_REG_OUT_URB_NUM 1 #define MAX_REG_OUT_URB_NUM 1
#define MAX_REG_OUT_BUF_NUM 8 #define MAX_REG_IN_URB_NUM 64
#define MAX_REG_IN_BUF_SIZE 64 #define MAX_REG_IN_BUF_SIZE 64
@ -90,9 +90,10 @@ struct hif_device_usb {
const struct firmware *firmware; const struct firmware *firmware;
struct htc_target *htc_handle; struct htc_target *htc_handle;
struct hif_usb_tx tx; struct hif_usb_tx tx;
struct urb *reg_in_urb;
struct usb_anchor regout_submitted; struct usb_anchor regout_submitted;
struct usb_anchor rx_submitted; struct usb_anchor rx_submitted;
struct usb_anchor reg_in_submitted;
struct usb_anchor mgmt_submitted;
struct sk_buff *remain_skb; struct sk_buff *remain_skb;
const char *fw_name; const char *fw_name;
int rx_remain_len; int rx_remain_len;

View File

@ -67,8 +67,11 @@ enum htc_opmode {
}; };
#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) #define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr)
#define ATH9K_HTC_AMPDU 1
#define ATH9K_HTC_AMPDU 1
#define ATH9K_HTC_NORMAL 2 #define ATH9K_HTC_NORMAL 2
#define ATH9K_HTC_BEACON 3
#define ATH9K_HTC_MGMT 4
#define ATH9K_HTC_TX_CTSONLY 0x1 #define ATH9K_HTC_TX_CTSONLY 0x1
#define ATH9K_HTC_TX_RTSCTS 0x2 #define ATH9K_HTC_TX_RTSCTS 0x2
@ -82,7 +85,8 @@ struct tx_frame_hdr {
__be32 flags; /* ATH9K_HTC_TX_* */ __be32 flags; /* ATH9K_HTC_TX_* */
u8 key_type; u8 key_type;
u8 keyix; u8 keyix;
u8 reserved[26]; u8 cookie;
u8 pad;
} __packed; } __packed;
struct tx_mgmt_hdr { struct tx_mgmt_hdr {
@ -92,26 +96,16 @@ struct tx_mgmt_hdr {
u8 flags; u8 flags;
u8 key_type; u8 key_type;
u8 keyix; u8 keyix;
u16 reserved; u8 cookie;
u8 pad;
} __packed; } __packed;
struct tx_beacon_header { struct tx_beacon_header {
u8 len_changed;
u8 vif_index; u8 vif_index;
u8 len_changed;
u16 rev; u16 rev;
} __packed; } __packed;
struct ath9k_htc_target_hw {
u32 flags;
u32 flags_ext;
u32 ampdu_limit;
u8 ampdu_subframes;
u8 tx_chainmask;
u8 tx_chainmask_legacy;
u8 rtscts_ratecode;
u8 protmode;
} __packed;
struct ath9k_htc_cap_target { struct ath9k_htc_cap_target {
u32 flags; u32 flags;
u32 flags_ext; u32 flags_ext;
@ -121,21 +115,16 @@ struct ath9k_htc_cap_target {
u8 tx_chainmask_legacy; u8 tx_chainmask_legacy;
u8 rtscts_ratecode; u8 rtscts_ratecode;
u8 protmode; u8 protmode;
u8 pad;
} __packed; } __packed;
struct ath9k_htc_target_vif { struct ath9k_htc_target_vif {
u8 index; u8 index;
u8 des_bssid[ETH_ALEN]; u8 opmode;
__be32 opmode;
u8 myaddr[ETH_ALEN]; u8 myaddr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u32 flags;
u32 flags_ext;
u16 ps_sta;
__be16 rtsthreshold;
u8 ath_cap; u8 ath_cap;
u8 node; __be16 rtsthreshold;
s8 mcast_rate; u8 pad;
} __packed; } __packed;
#define ATH_HTC_STA_AUTH 0x0001 #define ATH_HTC_STA_AUTH 0x0001
@ -143,27 +132,16 @@ struct ath9k_htc_target_vif {
#define ATH_HTC_STA_ERP 0x0004 #define ATH_HTC_STA_ERP 0x0004
#define ATH_HTC_STA_HT 0x0008 #define ATH_HTC_STA_HT 0x0008
/* FIXME: UAPSD variables */
struct ath9k_htc_target_sta { struct ath9k_htc_target_sta {
u16 associd;
u16 txpower;
u32 ucastkey;
u8 macaddr[ETH_ALEN]; u8 macaddr[ETH_ALEN];
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
u8 sta_index; u8 sta_index;
u8 vif_index; u8 vif_index;
u8 vif_sta;
__be16 flags; /* ATH_HTC_STA_* */
u16 htcap;
u8 valid;
u16 capinfo;
struct ath9k_htc_target_hw *hw;
struct ath9k_htc_target_vif *vif;
u16 txseqmgmt;
u8 is_vif_sta; u8 is_vif_sta;
u16 maxampdu; __be16 flags; /* ATH_HTC_STA_* */
u16 iv16; __be16 htcap;
u32 iv32; __be16 maxampdu;
u8 pad;
} __packed; } __packed;
struct ath9k_htc_target_aggr { struct ath9k_htc_target_aggr {
@ -197,12 +175,31 @@ struct ath9k_htc_target_rate {
struct ath9k_htc_rate rates; struct ath9k_htc_rate rates;
}; };
struct ath9k_htc_target_stats { struct ath9k_htc_target_int_stats {
__be32 tx_shortretry; __be32 rx;
__be32 tx_longretry; __be32 rxorn;
__be32 tx_xretries; __be32 rxeol;
__be32 ht_txunaggr_xretry; __be32 txurn;
__be32 ht_tx_xretries; __be32 txto;
__be32 cst;
} __packed;
struct ath9k_htc_target_tx_stats {
__be32 xretries;
__be32 fifoerr;
__be32 filtered;
__be32 timer_exp;
__be32 shortretries;
__be32 longretries;
__be32 qnull;
__be32 encap_fail;
__be32 nobuf;
} __packed;
struct ath9k_htc_target_rx_stats {
__be32 nobuf;
__be32 host_send;
__be32 host_done;
} __packed; } __packed;
#define ATH9K_HTC_MAX_VIF 2 #define ATH9K_HTC_MAX_VIF 2
@ -244,6 +241,8 @@ struct ath9k_htc_vif {
u8 index; u8 index;
u16 seq_no; u16 seq_no;
bool beacon_configured; bool beacon_configured;
int bslot;
__le64 tsfadjust;
}; };
struct ath9k_vif_iter_data { struct ath9k_vif_iter_data {
@ -282,23 +281,65 @@ struct ath9k_htc_rx {
spinlock_t rxbuflock; spinlock_t rxbuflock;
}; };
#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */
#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */
#define ATH9K_HTC_TX_RESERVE 10
#define ATH9K_HTC_TX_TIMEOUT_COUNT 20
#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
#define ATH9K_HTC_OP_TX_DRAIN BIT(1)
struct ath9k_htc_tx {
u8 flags;
int queued_cnt;
struct sk_buff_head mgmt_ep_queue;
struct sk_buff_head cab_ep_queue;
struct sk_buff_head data_be_queue;
struct sk_buff_head data_bk_queue;
struct sk_buff_head data_vi_queue;
struct sk_buff_head data_vo_queue;
struct sk_buff_head tx_failed;
DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM);
struct timer_list cleanup_timer;
spinlock_t tx_lock;
};
struct ath9k_htc_tx_ctl { struct ath9k_htc_tx_ctl {
u8 type; /* ATH9K_HTC_* */ u8 type; /* ATH9K_HTC_* */
u8 epid;
u8 txok;
u8 sta_idx;
unsigned long timestamp;
}; };
static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) >
IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data;
}
#ifdef CONFIG_ATH9K_HTC_DEBUGFS #ifdef CONFIG_ATH9K_HTC_DEBUGFS
#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++
#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
struct ath_htc_rx_status *rxs);
struct ath_tx_stats { struct ath_tx_stats {
u32 buf_queued; u32 buf_queued;
u32 buf_completed; u32 buf_completed;
u32 skb_queued; u32 skb_queued;
u32 skb_completed; u32 skb_success;
u32 skb_dropped; u32 skb_failed;
u32 cab_queued;
u32 queue_stats[WME_NUM_AC]; u32 queue_stats[WME_NUM_AC];
}; };
@ -306,25 +347,35 @@ struct ath_rx_stats {
u32 skb_allocated; u32 skb_allocated;
u32 skb_completed; u32 skb_completed;
u32 skb_dropped; u32 skb_dropped;
u32 err_crc;
u32 err_decrypt_crc;
u32 err_mic;
u32 err_pre_delim;
u32 err_post_delim;
u32 err_decrypt_busy;
u32 err_phy;
u32 err_phy_stats[ATH9K_PHYERR_MAX];
}; };
struct ath9k_debug { struct ath9k_debug {
struct dentry *debugfs_phy; struct dentry *debugfs_phy;
struct dentry *debugfs_tgt_stats;
struct dentry *debugfs_xmit;
struct dentry *debugfs_recv;
struct ath_tx_stats tx_stats; struct ath_tx_stats tx_stats;
struct ath_rx_stats rx_stats; struct ath_rx_stats rx_stats;
u32 txrate;
}; };
#else #else
#define TX_STAT_INC(c) do { } while (0) #define TX_STAT_INC(c) do { } while (0)
#define RX_STAT_INC(c) do { } while (0) #define RX_STAT_INC(c) do { } while (0)
#define CAB_STAT_INC do { } while (0)
#define TX_QSTAT_INC(c) do { } while (0) #define TX_QSTAT_INC(c) do { } while (0)
static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
struct ath_htc_rx_status *rxs)
{
}
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#define ATH_LED_PIN_DEF 1 #define ATH_LED_PIN_DEF 1
@ -351,10 +402,21 @@ struct ath_led {
int brightness; int brightness;
}; };
#define BSTUCK_THRESHOLD 10
/*
* Adjust these when the max. no of beaconing interfaces is
* increased.
*/
#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */
#define MIN_SWBA_RESPONSE 10 /* in TUs */
struct htc_beacon_config { struct htc_beacon_config {
struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
u16 beacon_interval; u16 beacon_interval;
u16 dtim_period; u16 dtim_period;
u16 bmiss_timeout; u16 bmiss_timeout;
u32 bmiss_cnt;
}; };
struct ath_btcoex { struct ath_btcoex {
@ -388,6 +450,9 @@ struct ath9k_htc_priv {
struct htc_target *htc; struct htc_target *htc;
struct wmi *wmi; struct wmi *wmi;
u16 fw_version_major;
u16 fw_version_minor;
enum htc_endpoint_id wmi_cmd_ep; enum htc_endpoint_id wmi_cmd_ep;
enum htc_endpoint_id beacon_ep; enum htc_endpoint_id beacon_ep;
enum htc_endpoint_id cab_ep; enum htc_endpoint_id cab_ep;
@ -411,27 +476,23 @@ struct ath9k_htc_priv {
u16 txpowlimit; u16 txpowlimit;
u16 nvifs; u16 nvifs;
u16 nstations; u16 nstations;
u32 bmiss_cnt;
bool rearm_ani; bool rearm_ani;
bool reconfig_beacon; bool reconfig_beacon;
unsigned int rxfilter;
struct ath9k_hw_cal_data caldata; struct ath9k_hw_cal_data caldata;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
spinlock_t beacon_lock; spinlock_t beacon_lock;
bool tx_queues_stop;
spinlock_t tx_lock;
struct ieee80211_vif *vif;
struct htc_beacon_config cur_beacon_conf; struct htc_beacon_config cur_beacon_conf;
unsigned int rxfilter;
struct ath9k_htc_rx rx;
struct ath9k_htc_tx tx;
struct tasklet_struct swba_tasklet; struct tasklet_struct swba_tasklet;
struct tasklet_struct rx_tasklet; struct tasklet_struct rx_tasklet;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ath9k_htc_rx rx;
struct tasklet_struct tx_tasklet;
struct sk_buff_head tx_queue;
struct delayed_work ani_work; struct delayed_work ani_work;
struct tasklet_struct tx_failed_tasklet;
struct work_struct ps_work; struct work_struct ps_work;
struct work_struct fatal_work; struct work_struct fatal_work;
@ -470,11 +531,18 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
void ath9k_htc_reset(struct ath9k_htc_priv *priv); void ath9k_htc_reset(struct ath9k_htc_priv *priv);
void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv); void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv);
void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); void ath9k_htc_swba(struct ath9k_htc_priv *priv,
struct wmi_event_swba *swba);
void ath9k_htc_rxep(void *priv, struct sk_buff *skb, void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id); enum htc_endpoint_id ep_id);
@ -491,14 +559,23 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
int ath9k_tx_init(struct ath9k_htc_priv *priv); int ath9k_tx_init(struct ath9k_htc_priv *priv);
void ath9k_tx_tasklet(unsigned long data); int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); struct sk_buff *skb, u8 slot, bool is_cab);
void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
int get_hw_qnum(u16 queue, int *hwq_map); int get_hw_qnum(u16 queue, int *hwq_map);
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo); struct ath9k_tx_queue_info *qinfo);
void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv);
void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv);
int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
void ath9k_tx_failed_tasklet(unsigned long data);
void ath9k_htc_tx_cleanup_timer(unsigned long data);
int ath9k_rx_init(struct ath9k_htc_priv *priv); int ath9k_rx_init(struct ath9k_htc_priv *priv);
void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
@ -528,15 +605,9 @@ void ath9k_htc_suspend(struct htc_target *htc_handle);
int ath9k_htc_resume(struct htc_target *htc_handle); int ath9k_htc_resume(struct htc_target *htc_handle);
#endif #endif
#ifdef CONFIG_ATH9K_HTC_DEBUGFS #ifdef CONFIG_ATH9K_HTC_DEBUGFS
int ath9k_htc_debug_create_root(void);
void ath9k_htc_debug_remove_root(void);
int ath9k_htc_init_debug(struct ath_hw *ah); int ath9k_htc_init_debug(struct ath_hw *ah);
void ath9k_htc_exit_debug(struct ath_hw *ah);
#else #else
static inline int ath9k_htc_debug_create_root(void) { return 0; };
static inline void ath9k_htc_debug_remove_root(void) {};
static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; };
static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {};
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#endif /* HTC_H */ #endif /* HTC_H */

View File

@ -18,6 +18,50 @@
#define FUDGE 2 #define FUDGE 2
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
{
struct ath_hw *ah = priv->ah;
struct ath9k_tx_queue_info qi, qi_be;
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
if (priv->ah->opmode == NL80211_IFTYPE_AP) {
qi.tqi_aifs = 1;
qi.tqi_cwmin = 0;
qi.tqi_cwmax = 0;
} else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
int qnum = priv->hwq_map[WME_AC_BE];
ath9k_hw_get_txq_props(ah, qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
/*
* For WIFI Beacon Distribution
* Long slot time : 2x cwmin
* Short slot time : 4x cwmin
*/
if (ah->slottime == ATH9K_SLOT_TIME_20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
}
if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
ath_err(ath9k_hw_common(ah),
"Unable to update beacon queue %u!\n", priv->beaconq);
} else {
ath9k_hw_resettxqueue(ah, priv->beaconq);
}
}
static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
struct htc_beacon_config *bss_conf) struct htc_beacon_config *bss_conf)
{ {
@ -154,6 +198,15 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
intval /= ATH9K_HTC_MAX_BCN_VIF; intval /= ATH9K_HTC_MAX_BCN_VIF;
nexttbtt = intval; nexttbtt = intval;
/*
* To reduce beacon misses under heavy TX load,
* set the beacon response time to a larger value.
*/
if (intval > DEFAULT_SWBA_RESPONSE)
priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
else
priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
if (priv->op_flags & OP_TSF_RESET) { if (priv->op_flags & OP_TSF_RESET) {
ath9k_hw_reset_tsf(priv->ah); ath9k_hw_reset_tsf(priv->ah);
priv->op_flags &= ~OP_TSF_RESET; priv->op_flags &= ~OP_TSF_RESET;
@ -172,12 +225,16 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
imask |= ATH9K_INT_SWBA; imask |= ATH9K_INT_SWBA;
ath_dbg(common, ATH_DBG_CONFIG, ath_dbg(common, ATH_DBG_CONFIG,
"AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n", "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d "
bss_conf->beacon_interval, nexttbtt, imask); "imask: 0x%x\n",
bss_conf->beacon_interval, nexttbtt,
priv->ah->config.sw_beacon_response_time, imask);
ath9k_htc_beaconq_config(priv);
WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DISABLE_INTR_CMDID);
ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
priv->bmiss_cnt = 0; priv->cur_beacon_conf.bmiss_cnt = 0;
htc_imask = cpu_to_be32(imask); htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
} }
@ -205,16 +262,26 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
nexttbtt += intval; nexttbtt += intval;
} while (nexttbtt < tsftu); } while (nexttbtt < tsftu);
/*
* Only one IBSS interfce is allowed.
*/
if (intval > DEFAULT_SWBA_RESPONSE)
priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
else
priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
if (priv->op_flags & OP_ENABLE_BEACON) if (priv->op_flags & OP_ENABLE_BEACON)
imask |= ATH9K_INT_SWBA; imask |= ATH9K_INT_SWBA;
ath_dbg(common, ATH_DBG_CONFIG, ath_dbg(common, ATH_DBG_CONFIG,
"IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n", "IBSS Beacon config, intval: %d, nexttbtt: %u, "
bss_conf->beacon_interval, nexttbtt, imask); "resp_time: %d, imask: 0x%x\n",
bss_conf->beacon_interval, nexttbtt,
priv->ah->config.sw_beacon_response_time, imask);
WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DISABLE_INTR_CMDID);
ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
priv->bmiss_cnt = 0; priv->cur_beacon_conf.bmiss_cnt = 0;
htc_imask = cpu_to_be32(imask); htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
} }
@ -225,38 +292,101 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
int slot)
{ {
struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; struct ath_common *common = ath9k_hw_common(priv->ah);
struct tx_beacon_header beacon_hdr; struct ieee80211_vif *vif;
struct ath9k_htc_tx_ctl tx_ctl; struct sk_buff *skb;
struct ieee80211_tx_info *info; struct ieee80211_hdr *hdr;
struct sk_buff *beacon; int padpos, padsize, ret, tx_slot;
u8 *tx_fhdr;
memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
/* FIXME: Handle BMISS */
if (beacon_pending != 0) {
priv->bmiss_cnt++;
return;
}
spin_lock_bh(&priv->beacon_lock); spin_lock_bh(&priv->beacon_lock);
vif = priv->cur_beacon_conf.bslot[slot];
skb = ieee80211_get_buffered_bc(priv->hw, vif);
while(skb) {
hdr = (struct ieee80211_hdr *) skb->data;
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos) {
if (skb_headroom(skb) < padsize) {
dev_kfree_skb_any(skb);
goto next;
}
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, padpos);
}
tx_slot = ath9k_htc_tx_get_slot(priv);
if (tx_slot < 0) {
ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n");
dev_kfree_skb_any(skb);
goto next;
}
ret = ath9k_htc_tx_start(priv, skb, tx_slot, true);
if (ret != 0) {
ath9k_htc_tx_clear_slot(priv, tx_slot);
dev_kfree_skb_any(skb);
ath_dbg(common, ATH_DBG_XMIT,
"Failed to send CAB frame\n");
} else {
spin_lock_bh(&priv->tx.tx_lock);
priv->tx.queued_cnt++;
spin_unlock_bh(&priv->tx.tx_lock);
}
next:
skb = ieee80211_get_buffered_bc(priv->hw, vif);
}
spin_unlock_bh(&priv->beacon_lock);
}
static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
int slot)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ieee80211_vif *vif;
struct ath9k_htc_vif *avp;
struct tx_beacon_header beacon_hdr;
struct ath9k_htc_tx_ctl *tx_ctl;
struct ieee80211_tx_info *info;
struct ieee80211_mgmt *mgmt;
struct sk_buff *beacon;
u8 *tx_fhdr;
int ret;
memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
spin_lock_bh(&priv->beacon_lock);
vif = priv->cur_beacon_conf.bslot[slot];
avp = (struct ath9k_htc_vif *)vif->drv_priv;
if (unlikely(priv->op_flags & OP_SCANNING)) { if (unlikely(priv->op_flags & OP_SCANNING)) {
spin_unlock_bh(&priv->beacon_lock); spin_unlock_bh(&priv->beacon_lock);
return; return;
} }
/* Get a new beacon */ /* Get a new beacon */
beacon = ieee80211_beacon_get(priv->hw, priv->vif); beacon = ieee80211_beacon_get(priv->hw, vif);
if (!beacon) { if (!beacon) {
spin_unlock_bh(&priv->beacon_lock); spin_unlock_bh(&priv->beacon_lock);
return; return;
} }
/*
* Update the TSF adjust value here, the HW will
* add this value for every beacon.
*/
mgmt = (struct ieee80211_mgmt *)beacon->data;
mgmt->u.beacon.timestamp = avp->tsfadjust;
info = IEEE80211_SKB_CB(beacon); info = IEEE80211_SKB_CB(beacon);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr = struct ieee80211_hdr *hdr =
@ -266,45 +396,149 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
} }
tx_ctl.type = ATH9K_HTC_NORMAL; tx_ctl = HTC_SKB_CB(beacon);
memset(tx_ctl, 0, sizeof(*tx_ctl));
tx_ctl->type = ATH9K_HTC_BEACON;
tx_ctl->epid = priv->beacon_ep;
beacon_hdr.vif_index = avp->index; beacon_hdr.vif_index = avp->index;
tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); ret = htc_send(priv->htc, beacon);
if (ret != 0) {
if (ret == -ENOMEM) {
ath_dbg(common, ATH_DBG_BSTUCK,
"Failed to send beacon, no free TX buffer\n");
}
dev_kfree_skb_any(beacon);
}
spin_unlock_bh(&priv->beacon_lock); spin_unlock_bh(&priv->beacon_lock);
} }
/* Currently, only for IBSS */ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) struct wmi_event_swba *swba)
{ {
struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_tx_queue_info qi, qi_be; u64 tsf;
int qnum = priv->hwq_map[WME_AC_BE]; u32 tsftu;
u16 intval;
int slot;
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;
memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
ath9k_hw_get_txq_props(ah, qnum, &qi_be); tsf = be64_to_cpu(swba->tsf);
tsftu = TSF_TO_TU(tsf >> 32, tsf);
slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
qi.tqi_aifs = qi_be.tqi_aifs; ath_dbg(common, ATH_DBG_BEACON,
/* For WIFI Beacon Distribution "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
* Long slot time : 2x cwmin slot, tsf, tsftu, intval);
* Short slot time : 4x cwmin
*/
if (ah->slottime == ATH9K_SLOT_TIME_20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { return slot;
ath_err(ath9k_hw_common(ah), }
"Unable to update beacon queue %u!\n", qnum);
} else { void ath9k_htc_swba(struct ath9k_htc_priv *priv,
ath9k_hw_resettxqueue(ah, priv->beaconq); struct wmi_event_swba *swba)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
int slot;
if (swba->beacon_pending != 0) {
priv->cur_beacon_conf.bmiss_cnt++;
if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
ath_dbg(common, ATH_DBG_BSTUCK,
"Beacon stuck, HW reset\n");
ieee80211_queue_work(priv->hw,
&priv->fatal_work);
}
return;
} }
if (priv->cur_beacon_conf.bmiss_cnt) {
ath_dbg(common, ATH_DBG_BSTUCK,
"Resuming beacon xmit after %u misses\n",
priv->cur_beacon_conf.bmiss_cnt);
priv->cur_beacon_conf.bmiss_cnt = 0;
}
slot = ath9k_htc_choose_bslot(priv, swba);
spin_lock_bh(&priv->beacon_lock);
if (priv->cur_beacon_conf.bslot[slot] == NULL) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
spin_unlock_bh(&priv->beacon_lock);
ath9k_htc_send_buffered(priv, slot);
ath9k_htc_send_beacon(priv, slot);
}
void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
int i = 0;
spin_lock_bh(&priv->beacon_lock);
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
if (priv->cur_beacon_conf.bslot[i] == NULL) {
avp->bslot = i;
break;
}
}
priv->cur_beacon_conf.bslot[avp->bslot] = vif;
spin_unlock_bh(&priv->beacon_lock);
ath_dbg(common, ATH_DBG_CONFIG,
"Added interface at beacon slot: %d\n", avp->bslot);
}
void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
spin_lock_bh(&priv->beacon_lock);
priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
spin_unlock_bh(&priv->beacon_lock);
ath_dbg(common, ATH_DBG_CONFIG,
"Removed interface at beacon slot: %d\n", avp->bslot);
}
/*
* Calculate the TSF adjustment value for all slots
* other than zero.
*/
void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
u64 tsfadjust;
if (avp->bslot == 0)
return;
/*
* The beacon interval cannot be different for multi-AP mode,
* and we reach here only for VIF slots greater than zero,
* so beacon_interval is guaranteed to be set in cur_conf.
*/
tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF;
avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
ath_dbg(common, ATH_DBG_CONFIG,
"tsfadjust is: %llu for bslot: %d\n",
(unsigned long long)tsfadjust, avp->bslot);
} }
static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)

View File

@ -0,0 +1,505 @@
/*
* Copyright (c) 2010-2011 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 "htc.h"
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
struct ath9k_htc_target_int_stats cmd_rsp;
char buf[512];
unsigned int len = 0;
int ret = 0;
memset(&cmd_rsp, 0, sizeof(cmd_rsp));
WMI_CMD(WMI_INT_STATS_CMDID);
if (ret)
return -EINVAL;
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "RX",
be32_to_cpu(cmd_rsp.rx));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "RXORN",
be32_to_cpu(cmd_rsp.rxorn));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "RXEOL",
be32_to_cpu(cmd_rsp.rxeol));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "TXURN",
be32_to_cpu(cmd_rsp.txurn));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "TXTO",
be32_to_cpu(cmd_rsp.txto));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "CST",
be32_to_cpu(cmd_rsp.cst));
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_tgt_int_stats = {
.read = read_file_tgt_int_stats,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
struct ath9k_htc_target_tx_stats cmd_rsp;
char buf[512];
unsigned int len = 0;
int ret = 0;
memset(&cmd_rsp, 0, sizeof(cmd_rsp));
WMI_CMD(WMI_TX_STATS_CMDID);
if (ret)
return -EINVAL;
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "Xretries",
be32_to_cpu(cmd_rsp.xretries));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "FifoErr",
be32_to_cpu(cmd_rsp.fifoerr));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "Filtered",
be32_to_cpu(cmd_rsp.filtered));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "TimerExp",
be32_to_cpu(cmd_rsp.timer_exp));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "ShortRetries",
be32_to_cpu(cmd_rsp.shortretries));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "LongRetries",
be32_to_cpu(cmd_rsp.longretries));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "QueueNull",
be32_to_cpu(cmd_rsp.qnull));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "EncapFail",
be32_to_cpu(cmd_rsp.encap_fail));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "NoBuf",
be32_to_cpu(cmd_rsp.nobuf));
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_tgt_tx_stats = {
.read = read_file_tgt_tx_stats,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
struct ath9k_htc_target_rx_stats cmd_rsp;
char buf[512];
unsigned int len = 0;
int ret = 0;
memset(&cmd_rsp, 0, sizeof(cmd_rsp));
WMI_CMD(WMI_RX_STATS_CMDID);
if (ret)
return -EINVAL;
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "NoBuf",
be32_to_cpu(cmd_rsp.nobuf));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "HostSend",
be32_to_cpu(cmd_rsp.host_send));
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "HostDone",
be32_to_cpu(cmd_rsp.host_done));
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_tgt_rx_stats = {
.read = read_file_tgt_rx_stats,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "Buffers queued",
priv->debug.tx_stats.buf_queued);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "Buffers completed",
priv->debug.tx_stats.buf_completed);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs queued",
priv->debug.tx_stats.skb_queued);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs success",
priv->debug.tx_stats.skb_success);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs failed",
priv->debug.tx_stats.skb_failed);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "CAB queued",
priv->debug.tx_stats.cab_queued);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BE queued",
priv->debug.tx_stats.queue_stats[WME_AC_BE]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BK queued",
priv->debug.tx_stats.queue_stats[WME_AC_BK]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "VI queued",
priv->debug.tx_stats.queue_stats[WME_AC_VI]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "VO queued",
priv->debug.tx_stats.queue_stats[WME_AC_VO]);
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_xmit = {
.read = read_file_xmit,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
struct ath_htc_rx_status *rxs)
{
#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++
if (rxs->rs_status & ATH9K_RXERR_CRC)
priv->debug.rx_stats.err_crc++;
if (rxs->rs_status & ATH9K_RXERR_DECRYPT)
priv->debug.rx_stats.err_decrypt_crc++;
if (rxs->rs_status & ATH9K_RXERR_MIC)
priv->debug.rx_stats.err_mic++;
if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
priv->debug.rx_stats.err_pre_delim++;
if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST)
priv->debug.rx_stats.err_post_delim++;
if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY)
priv->debug.rx_stats.err_decrypt_busy++;
if (rxs->rs_status & ATH9K_RXERR_PHY) {
priv->debug.rx_stats.err_phy++;
if (rxs->rs_phyerr < ATH9K_PHYERR_MAX)
RX_PHY_ERR_INC(rxs->rs_phyerr);
}
#undef RX_PHY_ERR_INC
}
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
#define PHY_ERR(s, p) \
len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \
priv->debug.rx_stats.err_phy_stats[p]);
struct ath9k_htc_priv *priv = file->private_data;
char *buf;
unsigned int len = 0, size = 1500;
ssize_t retval = 0;
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "SKBs allocated",
priv->debug.rx_stats.skb_allocated);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "SKBs completed",
priv->debug.rx_stats.skb_completed);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "SKBs Dropped",
priv->debug.rx_stats.skb_dropped);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "CRC ERR",
priv->debug.rx_stats.err_crc);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "DECRYPT CRC ERR",
priv->debug.rx_stats.err_decrypt_crc);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "MIC ERR",
priv->debug.rx_stats.err_mic);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "PRE-DELIM CRC ERR",
priv->debug.rx_stats.err_pre_delim);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "POST-DELIM CRC ERR",
priv->debug.rx_stats.err_post_delim);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "DECRYPT BUSY ERR",
priv->debug.rx_stats.err_decrypt_busy);
len += snprintf(buf + len, size - len,
"%20s : %10u\n", "TOTAL PHY ERR",
priv->debug.rx_stats.err_phy);
PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
PHY_ERR("RATE", ATH9K_PHYERR_RATE);
PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
PHY_ERR("TOR", ATH9K_PHYERR_TOR);
PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
if (len > size)
len = size;
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
#undef PHY_ERR
}
static const struct file_operations fops_recv = {
.read = read_file_recv,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_slot(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
spin_lock_bh(&priv->tx.tx_lock);
len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
priv->tx.tx_slot, MAX_TX_BUF_NUM);
len += snprintf(buf + len, sizeof(buf) - len, "\n");
len += snprintf(buf + len, sizeof(buf) - len,
"Used slots : %d\n",
bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
spin_unlock_bh(&priv->tx.tx_lock);
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_slot = {
.read = read_file_slot,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_queue(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Failed queue", skb_queue_len(&priv->tx.tx_failed));
spin_lock_bh(&priv->tx.tx_lock);
len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
"Queued count", priv->tx.queued_cnt);
spin_unlock_bh(&priv->tx.tx_lock);
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_queue = {
.read = read_file_queue,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_debug(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
struct ath_common *common = ath9k_hw_common(priv->ah);
char buf[32];
unsigned int len;
len = sprintf(buf, "0x%08x\n", common->debug_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
struct ath_common *common = ath9k_hw_common(priv->ah);
unsigned long mask;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
common->debug_mask = mask;
return count;
}
static const struct file_operations fops_debug = {
.read = read_file_debug,
.write = write_file_debug,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath9k_htc_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
priv->hw->wiphy->debugfsdir);
if (!priv->debug.debugfs_phy)
return -ENOMEM;
debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_tgt_int_stats);
debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_tgt_tx_stats);
debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_tgt_rx_stats);
debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_xmit);
debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_recv);
debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_slot);
debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
priv, &fops_queue);
debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
priv, &fops_debug);
return 0;
}

View File

@ -398,9 +398,9 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
/* Start TX */ /* Start TX */
htc_start(priv->htc); htc_start(priv->htc);
spin_lock_bh(&priv->tx_lock); spin_lock_bh(&priv->tx.tx_lock);
priv->tx_queues_stop = false; priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
spin_unlock_bh(&priv->tx_lock); spin_unlock_bh(&priv->tx.tx_lock);
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
WMI_CMD(WMI_ENABLE_INTR_CMDID); WMI_CMD(WMI_ENABLE_INTR_CMDID);
@ -429,13 +429,15 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
/* Stop TX */ /* Stop TX */
ieee80211_stop_queues(hw); ieee80211_stop_queues(hw);
htc_stop(priv->htc); ath9k_htc_tx_drain(priv);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
skb_queue_purge(&priv->tx_queue);
/* Stop RX */ /* Stop RX */
WMI_CMD(WMI_STOP_RECV_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID);
/* Clear the WMI event queue */
ath9k_wmi_event_drain(priv);
/* /*
* The MIB counters have to be disabled here, * The MIB counters have to be disabled here,
* since the target doesn't do it. * since the target doesn't do it.

View File

@ -140,7 +140,6 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
{ {
ath9k_htc_exit_debug(priv->ah);
ath9k_hw_deinit(priv->ah); ath9k_hw_deinit(priv->ah);
kfree(priv->ah); kfree(priv->ah);
priv->ah = NULL; priv->ah = NULL;
@ -643,7 +642,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
{ {
struct ath_hw *ah = NULL; struct ath_hw *ah = NULL;
struct ath_common *common; struct ath_common *common;
int ret = 0, csz = 0; int i, ret = 0, csz = 0;
priv->op_flags |= OP_INVALID; priv->op_flags |= OP_INVALID;
@ -671,20 +670,19 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
common->priv = priv; common->priv = priv;
common->debug_mask = ath9k_debug; common->debug_mask = ath9k_debug;
spin_lock_init(&priv->wmi->wmi_lock);
spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->beacon_lock);
spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->tx.tx_lock);
mutex_init(&priv->mutex); mutex_init(&priv->mutex);
mutex_init(&priv->htc_pm_lock); mutex_init(&priv->htc_pm_lock);
tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
(unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv); (unsigned long)priv);
tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
(unsigned long)priv); (unsigned long)priv);
INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work); INIT_WORK(&priv->ps_work, ath9k_ps_work);
INIT_WORK(&priv->fatal_work, ath9k_fatal_work); INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
(unsigned long)priv);
/* /*
* Cache line size is used to size and align various * Cache line size is used to size and align various
@ -701,16 +699,13 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
goto err_hw; goto err_hw;
} }
ret = ath9k_htc_init_debug(ah);
if (ret) {
ath_err(common, "Unable to create debugfs files\n");
goto err_debug;
}
ret = ath9k_init_queues(priv); ret = ath9k_init_queues(priv);
if (ret) if (ret)
goto err_queues; goto err_queues;
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
priv->cur_beacon_conf.bslot[i] = NULL;
ath9k_init_crypto(priv); ath9k_init_crypto(priv);
ath9k_init_channels_rates(priv); ath9k_init_channels_rates(priv);
ath9k_init_misc(priv); ath9k_init_misc(priv);
@ -723,8 +718,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
return 0; return 0;
err_queues: err_queues:
ath9k_htc_exit_debug(ah);
err_debug:
ath9k_hw_deinit(ah); ath9k_hw_deinit(ah);
err_hw: err_hw:
@ -745,11 +738,15 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK; IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
hw->wiphy->interface_modes = hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT);
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
@ -782,6 +779,32 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
SET_IEEE80211_PERM_ADDR(hw, common->macaddr); SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
} }
static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
{
struct ieee80211_hw *hw = priv->hw;
struct wmi_fw_version cmd_rsp;
int ret;
memset(&cmd_rsp, 0, sizeof(cmd_rsp));
WMI_CMD(WMI_GET_FW_VERSION);
if (ret)
return -EINVAL;
priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
priv->fw_version_major,
priv->fw_version_minor);
dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
priv->fw_version_major,
priv->fw_version_minor);
return 0;
}
static int ath9k_init_device(struct ath9k_htc_priv *priv, static int ath9k_init_device(struct ath9k_htc_priv *priv,
u16 devid, char *product, u32 drv_info) u16 devid, char *product, u32 drv_info)
{ {
@ -801,6 +824,10 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
common = ath9k_hw_common(ah); common = ath9k_hw_common(ah);
ath9k_set_hw_capab(priv, hw); ath9k_set_hw_capab(priv, hw);
error = ath9k_init_firmware_version(priv);
if (error != 0)
goto err_fw;
/* Initialize regulatory */ /* Initialize regulatory */
error = ath_regd_init(&common->regulatory, priv->hw->wiphy, error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
ath9k_reg_notifier); ath9k_reg_notifier);
@ -831,6 +858,12 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
goto err_world; goto err_world;
} }
error = ath9k_htc_init_debug(priv->ah);
if (error) {
ath_err(common, "Unable to create debugfs files\n");
goto err_world;
}
ath_dbg(common, ATH_DBG_CONFIG, ath_dbg(common, ATH_DBG_CONFIG,
"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, " "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
"BE:%d, BK:%d, VI:%d, VO:%d\n", "BE:%d, BK:%d, VI:%d, VO:%d\n",
@ -861,6 +894,8 @@ err_rx:
err_tx: err_tx:
/* Nothing */ /* Nothing */
err_regd: err_regd:
/* Nothing */
err_fw:
ath9k_deinit_priv(priv); ath9k_deinit_priv(priv);
err_init: err_init:
return error; return error;
@ -949,38 +984,20 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
static int __init ath9k_htc_init(void) static int __init ath9k_htc_init(void)
{ {
int error; if (ath9k_hif_usb_init() < 0) {
error = ath9k_htc_debug_create_root();
if (error < 0) {
printk(KERN_ERR
"ath9k_htc: Unable to create debugfs root: %d\n",
error);
goto err_dbg;
}
error = ath9k_hif_usb_init();
if (error < 0) {
printk(KERN_ERR printk(KERN_ERR
"ath9k_htc: No USB devices found," "ath9k_htc: No USB devices found,"
" driver not installed.\n"); " driver not installed.\n");
error = -ENODEV; return -ENODEV;
goto err_usb;
} }
return 0; return 0;
err_usb:
ath9k_htc_debug_remove_root();
err_dbg:
return error;
} }
module_init(ath9k_htc_init); module_init(ath9k_htc_init);
static void __exit ath9k_htc_exit(void) static void __exit ath9k_htc_exit(void)
{ {
ath9k_hif_usb_exit(); ath9k_hif_usb_exit();
ath9k_htc_debug_remove_root();
printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
} }
module_exit(ath9k_htc_exit); module_exit(ath9k_htc_exit);

View File

@ -16,10 +16,6 @@
#include "htc.h" #include "htc.h"
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
static struct dentry *ath9k_debugfs_root;
#endif
/*************/ /*************/
/* Utilities */ /* Utilities */
/*************/ /*************/
@ -197,11 +193,16 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
ath9k_htc_stop_ani(priv); ath9k_htc_stop_ani(priv);
ieee80211_stop_queues(priv->hw); ieee80211_stop_queues(priv->hw);
htc_stop(priv->htc);
del_timer_sync(&priv->tx.cleanup_timer);
ath9k_htc_tx_drain(priv);
WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID);
ath9k_wmi_event_drain(priv);
caldata = &priv->caldata; caldata = &priv->caldata;
ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
if (ret) { if (ret) {
@ -225,6 +226,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
ath9k_htc_vif_reconfig(priv); ath9k_htc_vif_reconfig(priv);
ieee80211_wake_queues(priv->hw); ieee80211_wake_queues(priv->hw);
mod_timer(&priv->tx.cleanup_timer,
jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
ath9k_htc_ps_restore(priv); ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
} }
@ -250,11 +254,16 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
ath9k_htc_ps_wakeup(priv); ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
del_timer_sync(&priv->tx.cleanup_timer);
ath9k_htc_tx_drain(priv);
WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID);
ath9k_wmi_event_drain(priv);
ath_dbg(common, ATH_DBG_CONFIG, ath_dbg(common, ATH_DBG_CONFIG,
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
priv->ah->curchan->channel, priv->ah->curchan->channel,
@ -263,6 +272,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (!fastcc) if (!fastcc)
caldata = &priv->caldata; caldata = &priv->caldata;
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (ret) { if (ret) {
ath_err(common, ath_err(common,
@ -296,6 +306,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
ath9k_htc_vif_reconfig(priv); ath9k_htc_vif_reconfig(priv);
mod_timer(&priv->tx.cleanup_timer,
jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
err: err:
ath9k_htc_ps_restore(priv); ath9k_htc_ps_restore(priv);
return ret; return ret;
@ -349,7 +362,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
hvif.opmode = cpu_to_be32(HTC_M_MONITOR); hvif.opmode = HTC_M_MONITOR;
hvif.index = ffz(priv->vif_slot); hvif.index = ffz(priv->vif_slot);
WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
@ -382,7 +395,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
tsta.is_vif_sta = 1; tsta.is_vif_sta = 1;
tsta.sta_index = sta_idx; tsta.sta_index = sta_idx;
tsta.vif_index = hvif.index; tsta.vif_index = hvif.index;
tsta.maxampdu = 0xffff; tsta.maxampdu = cpu_to_be16(0xffff);
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
if (ret) { if (ret) {
@ -463,9 +476,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
ista = (struct ath9k_htc_sta *) sta->drv_priv; ista = (struct ath9k_htc_sta *) sta->drv_priv;
memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
tsta.associd = common->curaid;
tsta.is_vif_sta = 0; tsta.is_vif_sta = 0;
tsta.valid = true;
ista->index = sta_idx; ista->index = sta_idx;
} else { } else {
memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
@ -474,7 +485,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
tsta.sta_index = sta_idx; tsta.sta_index = sta_idx;
tsta.vif_index = avp->index; tsta.vif_index = avp->index;
tsta.maxampdu = 0xffff; tsta.maxampdu = cpu_to_be16(0xffff);
if (sta && sta->ht_cap.ht_supported) if (sta && sta->ht_cap.ht_supported)
tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
@ -709,218 +720,13 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
(aggr.aggr_enable) ? "Starting" : "Stopping", (aggr.aggr_enable) ? "Starting" : "Stopping",
sta->addr, tid); sta->addr, tid);
spin_lock_bh(&priv->tx_lock); spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP; ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
spin_unlock_bh(&priv->tx_lock); spin_unlock_bh(&priv->tx.tx_lock);
return ret; return ret;
} }
/*********/
/* DEBUG */
/*********/
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
struct ath9k_htc_target_stats cmd_rsp;
char buf[512];
unsigned int len = 0;
int ret = 0;
memset(&cmd_rsp, 0, sizeof(cmd_rsp));
WMI_CMD(WMI_TGT_STATS_CMDID);
if (ret)
return -EINVAL;
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Short Retries",
be32_to_cpu(cmd_rsp.tx_shortretry));
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Long Retries",
be32_to_cpu(cmd_rsp.tx_longretry));
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Xretries",
be32_to_cpu(cmd_rsp.tx_xretries));
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Unaggr. Xretries",
be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Xretries (HT)",
be32_to_cpu(cmd_rsp.ht_tx_xretries));
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Rate", priv->debug.txrate);
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_tgt_stats = {
.read = read_file_tgt_stats,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "Buffers queued",
priv->debug.tx_stats.buf_queued);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "Buffers completed",
priv->debug.tx_stats.buf_completed);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs queued",
priv->debug.tx_stats.skb_queued);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs completed",
priv->debug.tx_stats.skb_completed);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs dropped",
priv->debug.tx_stats.skb_dropped);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BE queued",
priv->debug.tx_stats.queue_stats[WME_AC_BE]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BK queued",
priv->debug.tx_stats.queue_stats[WME_AC_BK]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "VI queued",
priv->debug.tx_stats.queue_stats[WME_AC_VI]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "VO queued",
priv->debug.tx_stats.queue_stats[WME_AC_VO]);
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_xmit = {
.read = read_file_xmit,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs allocated",
priv->debug.rx_stats.skb_allocated);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs completed",
priv->debug.rx_stats.skb_completed);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs Dropped",
priv->debug.rx_stats.skb_dropped);
if (len > sizeof(buf))
len = sizeof(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_recv = {
.read = read_file_recv,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath9k_htc_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
if (!ath9k_debugfs_root)
return -ENOENT;
priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
ath9k_debugfs_root);
if (!priv->debug.debugfs_phy)
goto err;
priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
priv->debug.debugfs_phy,
priv, &fops_tgt_stats);
if (!priv->debug.debugfs_tgt_stats)
goto err;
priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
priv->debug.debugfs_phy,
priv, &fops_xmit);
if (!priv->debug.debugfs_xmit)
goto err;
priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
priv->debug.debugfs_phy,
priv, &fops_recv);
if (!priv->debug.debugfs_recv)
goto err;
return 0;
err:
ath9k_htc_exit_debug(ah);
return -ENOMEM;
}
void ath9k_htc_exit_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
debugfs_remove(priv->debug.debugfs_recv);
debugfs_remove(priv->debug.debugfs_xmit);
debugfs_remove(priv->debug.debugfs_tgt_stats);
debugfs_remove(priv->debug.debugfs_phy);
}
int ath9k_htc_debug_create_root(void)
{
ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (!ath9k_debugfs_root)
return -ENOENT;
return 0;
}
void ath9k_htc_debug_remove_root(void)
{
debugfs_remove(ath9k_debugfs_root);
ath9k_debugfs_root = NULL;
}
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
/*******/ /*******/
/* ANI */ /* ANI */
/*******/ /*******/
@ -1040,7 +846,8 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_priv *priv = hw->priv;
int padpos, padsize, ret; struct ath_common *common = ath9k_hw_common(priv->ah);
int padpos, padsize, ret, slot;
hdr = (struct ieee80211_hdr *) skb->data; hdr = (struct ieee80211_hdr *) skb->data;
@ -1048,30 +855,32 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
padpos = ath9k_cmn_padpos(hdr->frame_control); padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3; padsize = padpos & 3;
if (padsize && skb->len > padpos) { if (padsize && skb->len > padpos) {
if (skb_headroom(skb) < padsize) if (skb_headroom(skb) < padsize) {
ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n");
goto fail_tx; goto fail_tx;
}
skb_push(skb, padsize); skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, padpos); memmove(skb->data, skb->data + padsize, padpos);
} }
ret = ath9k_htc_tx_start(priv, skb); slot = ath9k_htc_tx_get_slot(priv);
if (ret != 0) { if (slot < 0) {
if (ret == -ENOMEM) { ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n");
ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
"Stopping TX queues\n");
ieee80211_stop_queues(hw);
spin_lock_bh(&priv->tx_lock);
priv->tx_queues_stop = true;
spin_unlock_bh(&priv->tx_lock);
} else {
ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
"Tx failed\n");
}
goto fail_tx; goto fail_tx;
} }
ret = ath9k_htc_tx_start(priv, skb, slot, false);
if (ret != 0) {
ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n");
goto clear_slot;
}
ath9k_htc_check_stop_queues(priv);
return; return;
clear_slot:
ath9k_htc_tx_clear_slot(priv, slot);
fail_tx: fail_tx:
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
@ -1130,12 +939,15 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
priv->op_flags &= ~OP_INVALID; priv->op_flags &= ~OP_INVALID;
htc_start(priv->htc); htc_start(priv->htc);
spin_lock_bh(&priv->tx_lock); spin_lock_bh(&priv->tx.tx_lock);
priv->tx_queues_stop = false; priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
spin_unlock_bh(&priv->tx_lock); spin_unlock_bh(&priv->tx.tx_lock);
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
mod_timer(&priv->tx.cleanup_timer,
jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
AR_STOMP_LOW_WLAN_WGHT); AR_STOMP_LOW_WLAN_WGHT);
@ -1164,16 +976,16 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
} }
ath9k_htc_ps_wakeup(priv); ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID);
tasklet_kill(&priv->swba_tasklet);
tasklet_kill(&priv->rx_tasklet); tasklet_kill(&priv->rx_tasklet);
tasklet_kill(&priv->tx_tasklet);
skb_queue_purge(&priv->tx_queue); del_timer_sync(&priv->tx.cleanup_timer);
ath9k_htc_tx_drain(priv);
ath9k_wmi_event_drain(priv);
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
@ -1245,13 +1057,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
hvif.opmode = cpu_to_be32(HTC_M_STA); hvif.opmode = HTC_M_STA;
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
hvif.opmode = cpu_to_be32(HTC_M_IBSS); hvif.opmode = HTC_M_IBSS;
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
hvif.opmode = cpu_to_be32(HTC_M_HOSTAP); hvif.opmode = HTC_M_HOSTAP;
break; break;
default: default:
ath_err(common, ath_err(common,
@ -1281,14 +1093,20 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
priv->vif_slot |= (1 << avp->index); priv->vif_slot |= (1 << avp->index);
priv->nvifs++; priv->nvifs++;
priv->vif = vif;
INC_VIF(priv, vif->type); INC_VIF(priv, vif->type);
if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_ADHOC))
ath9k_htc_assign_bslot(priv, vif);
ath9k_htc_set_opmode(priv); ath9k_htc_set_opmode(priv);
if ((priv->ah->opmode == NL80211_IFTYPE_AP) && if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
!(priv->op_flags & OP_ANI_RUNNING)) !(priv->op_flags & OP_ANI_RUNNING)) {
ath9k_hw_set_tsfadjust(priv->ah, 1);
ath9k_htc_start_ani(priv); ath9k_htc_start_ani(priv);
}
ath_dbg(common, ATH_DBG_CONFIG, ath_dbg(common, ATH_DBG_CONFIG,
"Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index);
@ -1321,9 +1139,13 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
priv->vif_slot &= ~(1 << avp->index); priv->vif_slot &= ~(1 << avp->index);
ath9k_htc_remove_station(priv, vif, NULL); ath9k_htc_remove_station(priv, vif, NULL);
priv->vif = NULL;
DEC_VIF(priv, vif->type); DEC_VIF(priv, vif->type);
if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_ADHOC))
ath9k_htc_remove_bslot(priv, vif);
ath9k_htc_set_opmode(priv); ath9k_htc_set_opmode(priv);
/* /*
@ -1493,10 +1315,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_priv *priv = hw->priv;
struct ath9k_htc_sta *ista;
int ret; int ret;
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv); ath9k_htc_ps_wakeup(priv);
ista = (struct ath9k_htc_sta *) sta->drv_priv;
htc_sta_drain(priv->htc, ista->index);
ret = ath9k_htc_remove_station(priv, vif, sta); ret = ath9k_htc_remove_station(priv, vif, sta);
ath9k_htc_ps_restore(priv); ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
@ -1644,6 +1469,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
ath_dbg(common, ATH_DBG_CONFIG, ath_dbg(common, ATH_DBG_CONFIG,
"Beacon enabled for BSS: %pM\n", bss_conf->bssid); "Beacon enabled for BSS: %pM\n", bss_conf->bssid);
ath9k_htc_set_tsfadjust(priv, vif);
priv->op_flags |= OP_ENABLE_BEACON; priv->op_flags |= OP_ENABLE_BEACON;
ath9k_htc_beacon_config(priv, vif); ath9k_htc_beacon_config(priv, vif);
} }
@ -1758,9 +1584,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
break; break;
case IEEE80211_AMPDU_TX_OPERATIONAL: case IEEE80211_AMPDU_TX_OPERATIONAL:
ista = (struct ath9k_htc_sta *) sta->drv_priv; ista = (struct ath9k_htc_sta *) sta->drv_priv;
spin_lock_bh(&priv->tx_lock); spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = AGGR_OPERATIONAL; ista->tid_state[tid] = AGGR_OPERATIONAL;
spin_unlock_bh(&priv->tx_lock); spin_unlock_bh(&priv->tx.tx_lock);
break; break;
default: default:
ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");

View File

@ -53,6 +53,138 @@ int get_hw_qnum(u16 queue, int *hwq_map)
} }
} }
void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv)
{
spin_lock_bh(&priv->tx.tx_lock);
priv->tx.queued_cnt++;
if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) &&
!(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP;
ieee80211_stop_queues(priv->hw);
}
spin_unlock_bh(&priv->tx.tx_lock);
}
void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv)
{
spin_lock_bh(&priv->tx.tx_lock);
if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) &&
(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
ieee80211_wake_queues(priv->hw);
}
spin_unlock_bh(&priv->tx.tx_lock);
}
int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv)
{
int slot;
spin_lock_bh(&priv->tx.tx_lock);
slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM);
if (slot >= MAX_TX_BUF_NUM) {
spin_unlock_bh(&priv->tx.tx_lock);
return -ENOBUFS;
}
__set_bit(slot, priv->tx.tx_slot);
spin_unlock_bh(&priv->tx.tx_lock);
return slot;
}
void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot)
{
spin_lock_bh(&priv->tx.tx_lock);
__clear_bit(slot, priv->tx.tx_slot);
spin_unlock_bh(&priv->tx.tx_lock);
}
static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
u16 qnum)
{
enum htc_endpoint_id epid;
switch (qnum) {
case 0:
TX_QSTAT_INC(WME_AC_VO);
epid = priv->data_vo_ep;
break;
case 1:
TX_QSTAT_INC(WME_AC_VI);
epid = priv->data_vi_ep;
break;
case 2:
TX_QSTAT_INC(WME_AC_BE);
epid = priv->data_be_ep;
break;
case 3:
default:
TX_QSTAT_INC(WME_AC_BK);
epid = priv->data_bk_ep;
break;
}
return epid;
}
static inline struct sk_buff_head*
get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct sk_buff_head *epid_queue = NULL;
if (epid == priv->mgmt_ep)
epid_queue = &priv->tx.mgmt_ep_queue;
else if (epid == priv->cab_ep)
epid_queue = &priv->tx.cab_ep_queue;
else if (epid == priv->data_be_ep)
epid_queue = &priv->tx.data_be_queue;
else if (epid == priv->data_bk_ep)
epid_queue = &priv->tx.data_bk_queue;
else if (epid == priv->data_vi_ep)
epid_queue = &priv->tx.data_vi_queue;
else if (epid == priv->data_vo_ep)
epid_queue = &priv->tx.data_vo_queue;
else
ath_err(common, "Invalid EPID: %d\n", epid);
return epid_queue;
}
/*
* Removes the driver header and returns the TX slot number
*/
static inline int strip_drv_header(struct ath9k_htc_priv *priv,
struct sk_buff *skb)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_tx_ctl *tx_ctl;
int slot;
tx_ctl = HTC_SKB_CB(skb);
if (tx_ctl->epid == priv->mgmt_ep) {
struct tx_mgmt_hdr *tx_mhdr =
(struct tx_mgmt_hdr *)skb->data;
slot = tx_mhdr->cookie;
skb_pull(skb, sizeof(struct tx_mgmt_hdr));
} else if ((tx_ctl->epid == priv->data_bk_ep) ||
(tx_ctl->epid == priv->data_be_ep) ||
(tx_ctl->epid == priv->data_vi_ep) ||
(tx_ctl->epid == priv->data_vo_ep) ||
(tx_ctl->epid == priv->cab_ep)) {
struct tx_frame_hdr *tx_fhdr =
(struct tx_frame_hdr *)skb->data;
slot = tx_fhdr->cookie;
skb_pull(skb, sizeof(struct tx_frame_hdr));
} else {
ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid);
slot = -EINVAL;
}
return slot;
}
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo) struct ath9k_tx_queue_info *qinfo)
{ {
@ -79,23 +211,140 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
return error; return error;
} }
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv,
struct ath9k_htc_vif *avp,
struct sk_buff *skb,
u8 sta_idx, u8 vif_idx, u8 slot)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_mgmt *mgmt;
struct ieee80211_hdr *hdr;
struct tx_mgmt_hdr mgmt_hdr;
struct ath9k_htc_tx_ctl *tx_ctl;
u8 *tx_fhdr;
tx_ctl = HTC_SKB_CB(skb);
hdr = (struct ieee80211_hdr *) skb->data;
memset(tx_ctl, 0, sizeof(*tx_ctl));
memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
/*
* Set the TSF adjust value for probe response
* frame also.
*/
if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
mgmt = (struct ieee80211_mgmt *)skb->data;
mgmt->u.probe_resp.timestamp = avp->tsfadjust;
}
tx_ctl->type = ATH9K_HTC_MGMT;
mgmt_hdr.node_idx = sta_idx;
mgmt_hdr.vif_idx = vif_idx;
mgmt_hdr.tidno = 0;
mgmt_hdr.flags = 0;
mgmt_hdr.cookie = slot;
mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
else
mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
tx_ctl->epid = priv->mgmt_ep;
}
static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif,
struct sk_buff *skb,
u8 sta_idx, u8 vif_idx, u8 slot,
bool is_cab)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
struct ath9k_htc_tx_ctl *tx_ctl;
struct tx_frame_hdr tx_hdr;
u32 flags = 0;
u8 *qc, *tx_fhdr;
u16 qnum;
tx_ctl = HTC_SKB_CB(skb);
hdr = (struct ieee80211_hdr *) skb->data;
memset(tx_ctl, 0, sizeof(*tx_ctl));
memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
tx_hdr.node_idx = sta_idx;
tx_hdr.vif_idx = vif_idx;
tx_hdr.cookie = slot;
/*
* This is a bit redundant but it helps to get
* the per-packet index quickly when draining the
* TX queue in the HIF layer. Otherwise we would
* have to parse the packet contents ...
*/
tx_ctl->sta_idx = sta_idx;
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
tx_ctl->type = ATH9K_HTC_AMPDU;
tx_hdr.data_type = ATH9K_HTC_AMPDU;
} else {
tx_ctl->type = ATH9K_HTC_NORMAL;
tx_hdr.data_type = ATH9K_HTC_NORMAL;
}
if (ieee80211_is_data_qos(hdr->frame_control)) {
qc = ieee80211_get_qos_ctl(hdr);
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}
/* Check for RTS protection */
if (priv->hw->wiphy->rts_threshold != (u32) -1)
if (skb->len > priv->hw->wiphy->rts_threshold)
flags |= ATH9K_HTC_TX_RTSCTS;
/* CTS-to-self */
if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
(vif && vif->bss_conf.use_cts_prot))
flags |= ATH9K_HTC_TX_CTSONLY;
tx_hdr.flags = cpu_to_be32(flags);
tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
else
tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
tx_fhdr = skb_push(skb, sizeof(tx_hdr));
memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
if (is_cab) {
CAB_STAT_INC;
tx_ctl->epid = priv->cab_ep;
return;
}
qnum = skb_get_queue_mapping(skb);
tx_ctl->epid = get_htc_epid(priv, qnum);
}
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
struct sk_buff *skb,
u8 slot, bool is_cab)
{ {
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_sta *sta = tx_info->control.sta;
struct ieee80211_vif *vif = tx_info->control.vif; struct ieee80211_vif *vif = tx_info->control.vif;
struct ath9k_htc_sta *ista; struct ath9k_htc_sta *ista;
struct ath9k_htc_vif *avp; struct ath9k_htc_vif *avp = NULL;
struct ath9k_htc_tx_ctl tx_ctl;
enum htc_endpoint_id epid;
u16 qnum;
__le16 fc;
u8 *tx_fhdr;
u8 sta_idx, vif_idx; u8 sta_idx, vif_idx;
hdr = (struct ieee80211_hdr *) skb->data; hdr = (struct ieee80211_hdr *) skb->data;
fc = hdr->frame_control;
/* /*
* Find out on which interface this packet has to be * Find out on which interface this packet has to be
@ -124,218 +373,432 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
sta_idx = priv->vif_sta_pos[vif_idx]; sta_idx = priv->vif_sta_pos[vif_idx];
} }
memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); if (ieee80211_is_data(hdr->frame_control))
ath9k_htc_tx_data(priv, vif, skb,
sta_idx, vif_idx, slot, is_cab);
else
ath9k_htc_tx_mgmt(priv, avp, skb,
sta_idx, vif_idx, slot);
if (ieee80211_is_data(fc)) {
struct tx_frame_hdr tx_hdr;
u32 flags = 0;
u8 *qc;
memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); return htc_send(priv->htc, skb);
tx_hdr.node_idx = sta_idx;
tx_hdr.vif_idx = vif_idx;
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
tx_ctl.type = ATH9K_HTC_AMPDU;
tx_hdr.data_type = ATH9K_HTC_AMPDU;
} else {
tx_ctl.type = ATH9K_HTC_NORMAL;
tx_hdr.data_type = ATH9K_HTC_NORMAL;
}
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}
/* Check for RTS protection */
if (priv->hw->wiphy->rts_threshold != (u32) -1)
if (skb->len > priv->hw->wiphy->rts_threshold)
flags |= ATH9K_HTC_TX_RTSCTS;
/* CTS-to-self */
if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
(vif && vif->bss_conf.use_cts_prot))
flags |= ATH9K_HTC_TX_CTSONLY;
tx_hdr.flags = cpu_to_be32(flags);
tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
else
tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
tx_fhdr = skb_push(skb, sizeof(tx_hdr));
memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
qnum = skb_get_queue_mapping(skb);
switch (qnum) {
case 0:
TX_QSTAT_INC(WME_AC_VO);
epid = priv->data_vo_ep;
break;
case 1:
TX_QSTAT_INC(WME_AC_VI);
epid = priv->data_vi_ep;
break;
case 2:
TX_QSTAT_INC(WME_AC_BE);
epid = priv->data_be_ep;
break;
case 3:
default:
TX_QSTAT_INC(WME_AC_BK);
epid = priv->data_bk_ep;
break;
}
} else {
struct tx_mgmt_hdr mgmt_hdr;
memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
tx_ctl.type = ATH9K_HTC_NORMAL;
mgmt_hdr.node_idx = sta_idx;
mgmt_hdr.vif_idx = vif_idx;
mgmt_hdr.tidno = 0;
mgmt_hdr.flags = 0;
mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
else
mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
epid = priv->mgmt_ep;
}
return htc_send(priv->htc, skb, epid, &tx_ctl);
} }
static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
struct ath9k_htc_sta *ista, u8 tid) struct ath9k_htc_sta *ista, u8 tid)
{ {
bool ret = false; bool ret = false;
spin_lock_bh(&priv->tx_lock); spin_lock_bh(&priv->tx.tx_lock);
if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
ret = true; ret = true;
spin_unlock_bh(&priv->tx_lock); spin_unlock_bh(&priv->tx.tx_lock);
return ret; return ret;
} }
void ath9k_tx_tasklet(unsigned long data) static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif,
struct sk_buff *skb)
{ {
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
struct ieee80211_vif *vif;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct sk_buff *skb = NULL;
__le16 fc; __le16 fc;
while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { hdr = (struct ieee80211_hdr *) skb->data;
fc = hdr->frame_control;
hdr = (struct ieee80211_hdr *) skb->data; rcu_read_lock();
fc = hdr->frame_control;
tx_info = IEEE80211_SKB_CB(skb);
vif = tx_info->control.vif;
memset(&tx_info->status, 0, sizeof(tx_info->status)); sta = ieee80211_find_sta(vif, hdr->addr1);
if (!sta) {
rcu_read_unlock();
return;
}
if (!vif) if (sta && conf_is_ht(&priv->hw->conf) &&
goto send_mac80211; !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) {
u8 *qc, tid;
struct ath9k_htc_sta *ista;
rcu_read_lock(); qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
ista = (struct ath9k_htc_sta *)sta->drv_priv;
if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) {
ieee80211_start_tx_ba_session(sta, tid, 0);
spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = AGGR_PROGRESS;
spin_unlock_bh(&priv->tx.tx_lock);
}
}
}
rcu_read_unlock();
}
static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
struct sk_buff *skb,
struct __wmi_event_txstatus *txs)
{
struct ieee80211_vif *vif;
struct ath9k_htc_tx_ctl *tx_ctl;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rate;
struct ieee80211_conf *cur_conf = &priv->hw->conf;
struct ieee80211_supported_band *sband;
bool txok;
int slot;
slot = strip_drv_header(priv, skb);
if (slot < 0) {
dev_kfree_skb_any(skb);
return;
}
tx_ctl = HTC_SKB_CB(skb);
txok = tx_ctl->txok;
tx_info = IEEE80211_SKB_CB(skb);
vif = tx_info->control.vif;
rate = &tx_info->status.rates[0];
sband = priv->hw->wiphy->bands[cur_conf->channel->band];
memset(&tx_info->status, 0, sizeof(tx_info->status));
/*
* URB submission failed for this frame, it never reached
* the target.
*/
if (!txok || !vif || !txs)
goto send_mac80211;
if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK)
tx_info->flags |= IEEE80211_TX_STAT_ACK;
if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT)
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS)
rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
rate->count = 1;
rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE);
if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) {
rate->flags |= IEEE80211_TX_RC_MCS;
if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40)
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI)
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
} else {
if (cur_conf->channel->band == IEEE80211_BAND_5GHZ)
rate->idx += 4; /* No CCK rates */
}
ath9k_htc_check_tx_aggr(priv, vif, skb);
send_mac80211:
spin_lock_bh(&priv->tx.tx_lock);
if (WARN_ON(--priv->tx.queued_cnt < 0))
priv->tx.queued_cnt = 0;
spin_unlock_bh(&priv->tx.tx_lock);
ath9k_htc_tx_clear_slot(priv, slot);
/* Send status to mac80211 */
ieee80211_tx_status(priv->hw, skb);
}
static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv,
struct sk_buff_head *queue)
{
struct sk_buff *skb;
while ((skb = skb_dequeue(queue)) != NULL) {
ath9k_htc_tx_process(priv, skb, NULL);
}
}
void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv)
{
struct ath9k_htc_tx_event *event, *tmp;
spin_lock_bh(&priv->tx.tx_lock);
priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN;
spin_unlock_bh(&priv->tx.tx_lock);
/*
* Ensure that all pending TX frames are flushed,
* and that the TX completion/failed tasklets is killed.
*/
htc_stop(priv->htc);
tasklet_kill(&priv->wmi->wmi_event_tasklet);
tasklet_kill(&priv->tx_failed_tasklet);
ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue);
ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue);
ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue);
ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue);
ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue);
ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue);
ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
/*
* The TX cleanup timer has already been killed.
*/
spin_lock_bh(&priv->wmi->event_lock);
list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
list_del(&event->list);
kfree(event);
}
spin_unlock_bh(&priv->wmi->event_lock);
spin_lock_bh(&priv->tx.tx_lock);
priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN;
spin_unlock_bh(&priv->tx.tx_lock);
}
void ath9k_tx_failed_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
spin_lock_bh(&priv->tx.tx_lock);
if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
spin_unlock_bh(&priv->tx.tx_lock);
return;
}
spin_unlock_bh(&priv->tx.tx_lock);
ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
}
static inline bool check_cookie(struct ath9k_htc_priv *priv,
struct sk_buff *skb,
u8 cookie, u8 epid)
{
u8 fcookie = 0;
if (epid == priv->mgmt_ep) {
struct tx_mgmt_hdr *hdr;
hdr = (struct tx_mgmt_hdr *) skb->data;
fcookie = hdr->cookie;
} else if ((epid == priv->data_bk_ep) ||
(epid == priv->data_be_ep) ||
(epid == priv->data_vi_ep) ||
(epid == priv->data_vo_ep) ||
(epid == priv->cab_ep)) {
struct tx_frame_hdr *hdr;
hdr = (struct tx_frame_hdr *) skb->data;
fcookie = hdr->cookie;
}
if (fcookie == cookie)
return true;
return false;
}
static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv,
struct __wmi_event_txstatus *txs)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct sk_buff_head *epid_queue;
struct sk_buff *skb, *tmp;
unsigned long flags;
u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID);
epid_queue = get_htc_epid_queue(priv, epid);
if (!epid_queue)
return NULL;
spin_lock_irqsave(&epid_queue->lock, flags);
skb_queue_walk_safe(epid_queue, skb, tmp) {
if (check_cookie(priv, skb, txs->cookie, epid)) {
__skb_unlink(skb, epid_queue);
spin_unlock_irqrestore(&epid_queue->lock, flags);
return skb;
}
}
spin_unlock_irqrestore(&epid_queue->lock, flags);
ath_dbg(common, ATH_DBG_XMIT,
"No matching packet for cookie: %d, epid: %d\n",
txs->cookie, epid);
return NULL;
}
void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event)
{
struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event;
struct __wmi_event_txstatus *__txs;
struct sk_buff *skb;
struct ath9k_htc_tx_event *tx_pend;
int i;
for (i = 0; i < txs->cnt; i++) {
WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
__txs = &txs->txstatus[i];
skb = ath9k_htc_tx_get_packet(priv, __txs);
if (!skb) {
/*
* Store this event, so that the TX cleanup
* routine can check later for the needed packet.
*/
tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event),
GFP_ATOMIC);
if (!tx_pend)
continue;
memcpy(&tx_pend->txs, __txs,
sizeof(struct __wmi_event_txstatus));
spin_lock(&priv->wmi->event_lock);
list_add_tail(&tx_pend->list,
&priv->wmi->pending_tx_events);
spin_unlock(&priv->wmi->event_lock);
sta = ieee80211_find_sta(vif, hdr->addr1);
if (!sta) {
rcu_read_unlock();
ieee80211_tx_status(priv->hw, skb);
continue; continue;
} }
/* Check if we need to start aggregation */ ath9k_htc_tx_process(priv, skb, __txs);
if (sta && conf_is_ht(&priv->hw->conf) &&
!(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) {
u8 *qc, tid;
struct ath9k_htc_sta *ista;
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
ista = (struct ath9k_htc_sta *)sta->drv_priv;
if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
ieee80211_start_tx_ba_session(sta, tid, 0);
spin_lock_bh(&priv->tx_lock);
ista->tid_state[tid] = AGGR_PROGRESS;
spin_unlock_bh(&priv->tx_lock);
}
}
}
rcu_read_unlock();
send_mac80211:
/* Send status to mac80211 */
ieee80211_tx_status(priv->hw, skb);
} }
/* Wake TX queues if needed */ /* Wake TX queues if needed */
spin_lock_bh(&priv->tx_lock); ath9k_htc_check_wake_queues(priv);
if (priv->tx_queues_stop) {
priv->tx_queues_stop = false;
spin_unlock_bh(&priv->tx_lock);
ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
"Waking up TX queues\n");
ieee80211_wake_queues(priv->hw);
return;
}
spin_unlock_bh(&priv->tx_lock);
} }
void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok) enum htc_endpoint_id ep_id, bool txok)
{ {
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_tx_ctl *tx_ctl;
struct ieee80211_tx_info *tx_info; struct sk_buff_head *epid_queue;
if (!skb) tx_ctl = HTC_SKB_CB(skb);
tx_ctl->txok = txok;
tx_ctl->timestamp = jiffies;
if (!txok) {
skb_queue_tail(&priv->tx.tx_failed, skb);
tasklet_schedule(&priv->tx_failed_tasklet);
return; return;
}
if (ep_id == priv->mgmt_ep) { epid_queue = get_htc_epid_queue(priv, ep_id);
skb_pull(skb, sizeof(struct tx_mgmt_hdr)); if (!epid_queue) {
} else if ((ep_id == priv->data_bk_ep) ||
(ep_id == priv->data_be_ep) ||
(ep_id == priv->data_vi_ep) ||
(ep_id == priv->data_vo_ep)) {
skb_pull(skb, sizeof(struct tx_frame_hdr));
} else {
ath_err(common, "Unsupported TX EPID: %d\n", ep_id);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return; return;
} }
tx_info = IEEE80211_SKB_CB(skb); skb_queue_tail(epid_queue, skb);
}
if (txok) static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb)
tx_info->flags |= IEEE80211_TX_STAT_ACK; {
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_tx_ctl *tx_ctl;
skb_queue_tail(&priv->tx_queue, skb); tx_ctl = HTC_SKB_CB(skb);
tasklet_schedule(&priv->tx_tasklet);
if (time_after(jiffies,
tx_ctl->timestamp +
msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) {
ath_dbg(common, ATH_DBG_XMIT,
"Dropping a packet due to TX timeout\n");
return true;
}
return false;
}
static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv,
struct sk_buff_head *epid_queue)
{
bool process = false;
unsigned long flags;
struct sk_buff *skb, *tmp;
struct sk_buff_head queue;
skb_queue_head_init(&queue);
spin_lock_irqsave(&epid_queue->lock, flags);
skb_queue_walk_safe(epid_queue, skb, tmp) {
if (check_packet(priv, skb)) {
__skb_unlink(skb, epid_queue);
__skb_queue_tail(&queue, skb);
process = true;
}
}
spin_unlock_irqrestore(&epid_queue->lock, flags);
if (process) {
skb_queue_walk_safe(&queue, skb, tmp) {
__skb_unlink(skb, &queue);
ath9k_htc_tx_process(priv, skb, NULL);
}
}
}
void ath9k_htc_tx_cleanup_timer(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data;
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_tx_event *event, *tmp;
struct sk_buff *skb;
spin_lock(&priv->wmi->event_lock);
list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
skb = ath9k_htc_tx_get_packet(priv, &event->txs);
if (skb) {
ath_dbg(common, ATH_DBG_XMIT,
"Found packet for cookie: %d, epid: %d\n",
event->txs.cookie,
MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID));
ath9k_htc_tx_process(priv, skb, &event->txs);
list_del(&event->list);
kfree(event);
continue;
}
if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) {
list_del(&event->list);
kfree(event);
}
}
spin_unlock(&priv->wmi->event_lock);
/*
* Check if status-pending packets have to be cleaned up.
*/
ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue);
ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue);
ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue);
ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue);
ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue);
ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue);
/* Wake TX queues if needed */
ath9k_htc_check_wake_queues(priv);
mod_timer(&priv->tx.cleanup_timer,
jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
} }
int ath9k_tx_init(struct ath9k_htc_priv *priv) int ath9k_tx_init(struct ath9k_htc_priv *priv)
{ {
skb_queue_head_init(&priv->tx_queue); skb_queue_head_init(&priv->tx.mgmt_ep_queue);
skb_queue_head_init(&priv->tx.cab_ep_queue);
skb_queue_head_init(&priv->tx.data_be_queue);
skb_queue_head_init(&priv->tx.data_bk_queue);
skb_queue_head_init(&priv->tx.data_vi_queue);
skb_queue_head_init(&priv->tx.data_vo_queue);
skb_queue_head_init(&priv->tx.tx_failed);
return 0; return 0;
} }
@ -507,8 +970,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
int last_rssi = ATH_RSSI_DUMMY_MARKER; int last_rssi = ATH_RSSI_DUMMY_MARKER;
__le16 fc; __le16 fc;
if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
ath_err(common, "Corrupted RX frame, dropping\n"); ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
skb->len);
goto rx_next; goto rx_next;
} }
@ -522,6 +986,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
goto rx_next; goto rx_next;
} }
ath9k_htc_err_stat_rx(priv, rxstatus);
/* Get the RX status information */ /* Get the RX status information */
memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);

View File

@ -17,8 +17,8 @@
#include "htc.h" #include "htc.h"
static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
u16 len, u8 flags, u8 epid, u16 len, u8 flags, u8 epid)
struct ath9k_htc_tx_ctl *tx_ctl)
{ {
struct htc_frame_hdr *hdr; struct htc_frame_hdr *hdr;
struct htc_endpoint *endpoint = &target->endpoint[epid]; struct htc_endpoint *endpoint = &target->endpoint[epid];
@ -30,8 +30,8 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
hdr->flags = flags; hdr->flags = flags;
hdr->payload_len = cpu_to_be16(len); hdr->payload_len = cpu_to_be16(len);
status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb, status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
tx_ctl);
return status; return status;
} }
@ -162,7 +162,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS; target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret) if (ret)
goto err; goto err;
@ -197,7 +197,7 @@ static int htc_setup_complete(struct htc_target *target)
target->htc_flags |= HTC_OP_START_WAIT; target->htc_flags |= HTC_OP_START_WAIT;
ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret) if (ret)
goto err; goto err;
@ -268,7 +268,7 @@ int htc_connect_service(struct htc_target *target,
conn_msg->dl_pipeid = endpoint->dl_pipeid; conn_msg->dl_pipeid = endpoint->dl_pipeid;
conn_msg->ul_pipeid = endpoint->ul_pipeid; conn_msg->ul_pipeid = endpoint->ul_pipeid;
ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret) if (ret)
goto err; goto err;
@ -286,35 +286,33 @@ err:
return ret; return ret;
} }
int htc_send(struct htc_target *target, struct sk_buff *skb, int htc_send(struct htc_target *target, struct sk_buff *skb)
enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl)
{ {
return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl); struct ath9k_htc_tx_ctl *tx_ctl;
tx_ctl = HTC_SKB_CB(skb);
return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
}
int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
enum htc_endpoint_id epid)
{
return htc_issue_send(target, skb, skb->len, 0, epid);
} }
void htc_stop(struct htc_target *target) void htc_stop(struct htc_target *target)
{ {
enum htc_endpoint_id epid; target->hif->stop(target->hif_dev);
struct htc_endpoint *endpoint;
for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
endpoint = &target->endpoint[epid];
if (endpoint->service_id != 0)
target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
}
} }
void htc_start(struct htc_target *target) void htc_start(struct htc_target *target)
{ {
enum htc_endpoint_id epid; target->hif->start(target->hif_dev);
struct htc_endpoint *endpoint; }
for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { void htc_sta_drain(struct htc_target *target, u8 idx)
endpoint = &target->endpoint[epid]; {
if (endpoint->service_id != 0) target->hif->sta_drain(target->hif_dev, idx);
target->hif->start(target->hif_dev,
endpoint->ul_pipeid);
}
} }
void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,

View File

@ -33,10 +33,10 @@ struct ath9k_htc_hif {
u8 control_dl_pipe; u8 control_dl_pipe;
u8 control_ul_pipe; u8 control_ul_pipe;
void (*start) (void *hif_handle, u8 pipe); void (*start) (void *hif_handle);
void (*stop) (void *hif_handle, u8 pipe); void (*stop) (void *hif_handle);
int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf, void (*sta_drain) (void *hif_handle, u8 idx);
struct ath9k_htc_tx_ctl *tx_ctl); int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf);
}; };
enum htc_endpoint_id { enum htc_endpoint_id {
@ -205,10 +205,12 @@ int htc_init(struct htc_target *target);
int htc_connect_service(struct htc_target *target, int htc_connect_service(struct htc_target *target,
struct htc_service_connreq *service_connreq, struct htc_service_connreq *service_connreq,
enum htc_endpoint_id *conn_rsp_eid); enum htc_endpoint_id *conn_rsp_eid);
int htc_send(struct htc_target *target, struct sk_buff *skb, int htc_send(struct htc_target *target, struct sk_buff *skb);
enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl); int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
enum htc_endpoint_id epid);
void htc_stop(struct htc_target *target); void htc_stop(struct htc_target *target);
void htc_start(struct htc_target *target); void htc_start(struct htc_target *target);
void htc_sta_drain(struct htc_target *target, u8 idx);
void ath9k_htc_rx_msg(struct htc_target *htc_handle, void ath9k_htc_rx_msg(struct htc_target *htc_handle,
struct sk_buff *skb, u32 len, u8 pipe_id); struct sk_buff *skb, u32 len, u8 pipe_id);

View File

@ -122,6 +122,11 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
} }
static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
}
/* Private hardware call ops */ /* Private hardware call ops */
/* PHY ops */ /* PHY ops */

View File

@ -676,42 +676,55 @@ unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
} }
EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
#define DPLL2_KD_VAL 0x3D #define DPLL3_PHASE_SHIFT_VAL 0x1
#define DPLL2_KI_VAL 0x06
#define DPLL3_PHASE_SHIFT_VAL 0x1
static void ath9k_hw_init_pll(struct ath_hw *ah, static void ath9k_hw_init_pll(struct ath_hw *ah,
struct ath9k_channel *chan) struct ath9k_channel *chan)
{ {
u32 pll; u32 pll;
if (AR_SREV_9485(ah)) { if (AR_SREV_9485(ah)) {
REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01);
REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_BB_DPLL2_PLL_PWD, 0x1);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_DPLL2_KD, 0x40);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_DPLL2_KI, 0x4);
REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
AR_CH0_BB_DPLL1_REFDIV, 0x5);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
AR_CH0_BB_DPLL1_NINI, 0x58);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
AR_CH0_BB_DPLL1_NFRAC, 0x0);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_BB_DPLL2_OUTDIV, 0x1);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1);
/* program BB PLL phase_shift to 0x6 */
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
udelay(1000); udelay(1000);
REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_DPLL2_KD, DPLL2_KD_VAL);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
AR_CH0_DPLL2_KI, DPLL2_KI_VAL);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
udelay(1000);
} }
pll = ath9k_hw_compute_pll_control(ah, chan); pll = ath9k_hw_compute_pll_control(ah, chan);
REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
if (AR_SREV_9485(ah))
udelay(1000);
/* Switch the core clock for ar9271 to 117Mhz */ /* Switch the core clock for ar9271 to 117Mhz */
if (AR_SREV_9271(ah)) { if (AR_SREV_9271(ah)) {
udelay(500); udelay(500);

View File

@ -626,6 +626,7 @@ struct ath_hw_ops {
void (*clr11n_aggr)(struct ath_hw *ah, void *ds); void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
void (*set11n_burstduration)(struct ath_hw *ah, void *ds, void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
u32 burstDuration); u32 burstDuration);
void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
}; };
struct ath_nf_limits { struct ath_nf_limits {
@ -846,6 +847,14 @@ struct ath_hw {
u32 ent_mode; u32 ent_mode;
}; };
struct ath_bus_ops {
enum ath_bus_type ath_bus_type;
void (*read_cachesize)(struct ath_common *common, int *csz);
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
void (*bt_coex_prep)(struct ath_common *common);
void (*extn_synch_en)(struct ath_common *common);
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
{ {
return &ah->common; return &ah->common;

View File

@ -239,7 +239,6 @@ struct ath_desc {
void *ds_vdata; void *ds_vdata;
} __packed __aligned(4); } __packed __aligned(4);
#define ATH9K_TXDESC_CLRDMASK 0x0001
#define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_NOACK 0x0002
#define ATH9K_TXDESC_RTSENA 0x0004 #define ATH9K_TXDESC_RTSENA 0x0004
#define ATH9K_TXDESC_CTSENA 0x0008 #define ATH9K_TXDESC_CTSENA 0x0008

View File

@ -1373,6 +1373,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
if ((iter_data.naps + iter_data.nadhocs) > 0) { if ((iter_data.naps + iter_data.nadhocs) > 0) {
sc->sc_flags |= SC_OP_ANI_RUN; sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common); ath_start_ani(common);
} else {
sc->sc_flags &= ~SC_OP_ANI_RUN;
del_timer_sync(&common->ani.timer);
} }
} }
@ -1733,23 +1736,63 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_node *an = (struct ath_node *) sta->drv_priv;
struct ieee80211_key_conf ps_key = { };
ath_node_attach(sc, sta); ath_node_attach(sc, sta);
an->ps_key = ath_key_config(common, vif, sta, &ps_key);
return 0; return 0;
} }
static void ath9k_del_ps_key(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_node *an = (struct ath_node *) sta->drv_priv;
struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
if (!an->ps_key)
return;
ath_key_delete(common, &ps_key);
}
static int ath9k_sta_remove(struct ieee80211_hw *hw, static int ath9k_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
ath9k_del_ps_key(sc, vif, sta);
ath_node_detach(sc, sta); ath_node_detach(sc, sta);
return 0; return 0;
} }
static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
struct ath_softc *sc = hw->priv;
struct ath_node *an = (struct ath_node *) sta->drv_priv;
switch (cmd) {
case STA_NOTIFY_SLEEP:
an->sleeping = true;
if (ath_tx_aggr_sleep(sc, an))
ieee80211_sta_set_tim(sta);
break;
case STA_NOTIFY_AWAKE:
an->sleeping = false;
ath_tx_aggr_wakeup(sc, an);
break;
}
}
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
@ -1826,6 +1869,9 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) { switch (cmd) {
case SET_KEY: case SET_KEY:
if (sta)
ath9k_del_ps_key(sc, vif, sta);
ret = ath_key_config(common, vif, sta, key); ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) { if (ret >= 0) {
key->hw_key_idx = ret; key->hw_key_idx = ret;
@ -2209,6 +2255,21 @@ out:
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
} }
static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
int i;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
continue;
if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
return true;
}
return false;
}
struct ieee80211_ops ath9k_ops = { struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx, .tx = ath9k_tx,
.start = ath9k_start, .start = ath9k_start,
@ -2220,6 +2281,7 @@ struct ieee80211_ops ath9k_ops = {
.configure_filter = ath9k_configure_filter, .configure_filter = ath9k_configure_filter,
.sta_add = ath9k_sta_add, .sta_add = ath9k_sta_add,
.sta_remove = ath9k_sta_remove, .sta_remove = ath9k_sta_remove,
.sta_notify = ath9k_sta_notify,
.conf_tx = ath9k_conf_tx, .conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed, .bss_info_changed = ath9k_bss_info_changed,
.set_key = ath9k_set_key, .set_key = ath9k_set_key,
@ -2231,4 +2293,5 @@ struct ieee80211_ops ath9k_ops = {
.rfkill_poll = ath9k_rfkill_poll_state, .rfkill_poll = ath9k_rfkill_poll_state,
.set_coverage_class = ath9k_set_coverage_class, .set_coverage_class = ath9k_set_coverage_class,
.flush = ath9k_flush, .flush = ath9k_flush,
.tx_frames_pending = ath9k_tx_frames_pending,
}; };

View File

@ -19,7 +19,6 @@
#define CHANSEL_DIV 15 #define CHANSEL_DIV 15
#define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) #define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV)
#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV)
#define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) #define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV)
#define AR_PHY_BASE 0x9800 #define AR_PHY_BASE 0x9800

View File

@ -1092,8 +1092,7 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
if (!(rate->flags & IEEE80211_TX_RC_MCS)) if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx; return rate->idx;
while (rate->idx > mcs_rix_off[i] && while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
i < ARRAY_SIZE(mcs_rix_off)) {
rix++; i++; rix++; i++;
} }

View File

@ -75,7 +75,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
*sc->rx.rxlink = bf->bf_daddr; *sc->rx.rxlink = bf->bf_daddr;
sc->rx.rxlink = &ds->ds_link; sc->rx.rxlink = &ds->ds_link;
ath9k_hw_rxena(ah);
} }
static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
@ -426,9 +425,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
else else
rfilt |= ATH9K_RX_FILTER_BEACON; rfilt |= ATH9K_RX_FILTER_BEACON;
if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) || if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
AR_SREV_9285_12_OR_LATER(sc->sc_ah)) &&
(sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
(sc->rx.rxfilter & FIF_PSPOLL)) (sc->rx.rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL; rfilt |= ATH9K_RX_FILTER_PSPOLL;
@ -1767,6 +1764,7 @@ requeue:
} else { } else {
list_move_tail(&bf->list, &sc->rx.rxbuf); list_move_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_buf_link(sc, bf); ath_rx_buf_link(sc, bf);
ath9k_hw_rxena(ah);
} }
} while (1); } while (1);

View File

@ -858,9 +858,7 @@
#define AR_SREV_9300(_ah) \ #define AR_SREV_9300(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
#define AR_SREV_9300_20_OR_LATER(_ah) \ #define AR_SREV_9300_20_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20)))
#define AR_SREV_9485(_ah) \ #define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
@ -1088,14 +1086,35 @@ enum {
#define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP 0x40d8
#define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000
#define AR_ENT_OTP_MPSD 0x00800000 #define AR_ENT_OTP_MPSD 0x00800000
#define AR_CH0_BB_DPLL2 0x16184
#define AR_CH0_BB_DPLL3 0x16188 #define AR_CH0_BB_DPLL1 0x16180
#define AR_CH0_DDR_DPLL2 0x16244 #define AR_CH0_BB_DPLL1_REFDIV 0xF8000000
#define AR_CH0_DDR_DPLL3 0x16248 #define AR_CH0_BB_DPLL1_REFDIV_S 27
#define AR_CH0_DPLL2_KD 0x03F80000 #define AR_CH0_BB_DPLL1_NINI 0x07FC0000
#define AR_CH0_DPLL2_KD_S 19 #define AR_CH0_BB_DPLL1_NINI_S 18
#define AR_CH0_BB_DPLL1_NFRAC 0x0003FFFF
#define AR_CH0_BB_DPLL1_NFRAC_S 0
#define AR_CH0_BB_DPLL2 0x16184
#define AR_CH0_BB_DPLL2_LOCAL_PLL 0x40000000
#define AR_CH0_BB_DPLL2_LOCAL_PLL_S 30
#define AR_CH0_DPLL2_KI 0x3C000000 #define AR_CH0_DPLL2_KI 0x3C000000
#define AR_CH0_DPLL2_KI_S 26 #define AR_CH0_DPLL2_KI_S 26
#define AR_CH0_DPLL2_KD 0x03F80000
#define AR_CH0_DPLL2_KD_S 19
#define AR_CH0_BB_DPLL2_EN_NEGTRIG 0x00040000
#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18
#define AR_CH0_BB_DPLL2_PLL_PWD 0x00010000
#define AR_CH0_BB_DPLL2_PLL_PWD_S 16
#define AR_CH0_BB_DPLL2_OUTDIV 0x0000E000
#define AR_CH0_BB_DPLL2_OUTDIV_S 13
#define AR_CH0_BB_DPLL3 0x16188
#define AR_CH0_BB_DPLL3_PHASE_SHIFT 0x3F800000
#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S 23
#define AR_CH0_DDR_DPLL2 0x16244
#define AR_CH0_DDR_DPLL3 0x16248
#define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000 #define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000
#define AR_CH0_DPLL3_PHASE_SHIFT_S 23 #define AR_CH0_DPLL3_PHASE_SHIFT_S 23
#define AR_PHY_CCA_NOM_VAL_2GHZ -118 #define AR_PHY_CCA_NOM_VAL_2GHZ -118

View File

@ -23,20 +23,18 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_ECHO_CMDID"; return "WMI_ECHO_CMDID";
case WMI_ACCESS_MEMORY_CMDID: case WMI_ACCESS_MEMORY_CMDID:
return "WMI_ACCESS_MEMORY_CMDID"; return "WMI_ACCESS_MEMORY_CMDID";
case WMI_GET_FW_VERSION:
return "WMI_GET_FW_VERSION";
case WMI_DISABLE_INTR_CMDID: case WMI_DISABLE_INTR_CMDID:
return "WMI_DISABLE_INTR_CMDID"; return "WMI_DISABLE_INTR_CMDID";
case WMI_ENABLE_INTR_CMDID: case WMI_ENABLE_INTR_CMDID:
return "WMI_ENABLE_INTR_CMDID"; return "WMI_ENABLE_INTR_CMDID";
case WMI_RX_LINK_CMDID:
return "WMI_RX_LINK_CMDID";
case WMI_ATH_INIT_CMDID: case WMI_ATH_INIT_CMDID:
return "WMI_ATH_INIT_CMDID"; return "WMI_ATH_INIT_CMDID";
case WMI_ABORT_TXQ_CMDID: case WMI_ABORT_TXQ_CMDID:
return "WMI_ABORT_TXQ_CMDID"; return "WMI_ABORT_TXQ_CMDID";
case WMI_STOP_TX_DMA_CMDID: case WMI_STOP_TX_DMA_CMDID:
return "WMI_STOP_TX_DMA_CMDID"; return "WMI_STOP_TX_DMA_CMDID";
case WMI_STOP_DMA_RECV_CMDID:
return "WMI_STOP_DMA_RECV_CMDID";
case WMI_ABORT_TX_DMA_CMDID: case WMI_ABORT_TX_DMA_CMDID:
return "WMI_ABORT_TX_DMA_CMDID"; return "WMI_ABORT_TX_DMA_CMDID";
case WMI_DRAIN_TXQ_CMDID: case WMI_DRAIN_TXQ_CMDID:
@ -51,8 +49,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_FLUSH_RECV_CMDID"; return "WMI_FLUSH_RECV_CMDID";
case WMI_SET_MODE_CMDID: case WMI_SET_MODE_CMDID:
return "WMI_SET_MODE_CMDID"; return "WMI_SET_MODE_CMDID";
case WMI_RESET_CMDID:
return "WMI_RESET_CMDID";
case WMI_NODE_CREATE_CMDID: case WMI_NODE_CREATE_CMDID:
return "WMI_NODE_CREATE_CMDID"; return "WMI_NODE_CREATE_CMDID";
case WMI_NODE_REMOVE_CMDID: case WMI_NODE_REMOVE_CMDID:
@ -61,8 +57,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_VAP_REMOVE_CMDID"; return "WMI_VAP_REMOVE_CMDID";
case WMI_VAP_CREATE_CMDID: case WMI_VAP_CREATE_CMDID:
return "WMI_VAP_CREATE_CMDID"; return "WMI_VAP_CREATE_CMDID";
case WMI_BEACON_UPDATE_CMDID:
return "WMI_BEACON_UPDATE_CMDID";
case WMI_REG_READ_CMDID: case WMI_REG_READ_CMDID:
return "WMI_REG_READ_CMDID"; return "WMI_REG_READ_CMDID";
case WMI_REG_WRITE_CMDID: case WMI_REG_WRITE_CMDID:
@ -71,20 +65,20 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_RC_STATE_CHANGE_CMDID"; return "WMI_RC_STATE_CHANGE_CMDID";
case WMI_RC_RATE_UPDATE_CMDID: case WMI_RC_RATE_UPDATE_CMDID:
return "WMI_RC_RATE_UPDATE_CMDID"; return "WMI_RC_RATE_UPDATE_CMDID";
case WMI_DEBUG_INFO_CMDID:
return "WMI_DEBUG_INFO_CMDID";
case WMI_HOST_ATTACH:
return "WMI_HOST_ATTACH";
case WMI_TARGET_IC_UPDATE_CMDID: case WMI_TARGET_IC_UPDATE_CMDID:
return "WMI_TARGET_IC_UPDATE_CMDID"; return "WMI_TARGET_IC_UPDATE_CMDID";
case WMI_TGT_STATS_CMDID:
return "WMI_TGT_STATS_CMDID";
case WMI_TX_AGGR_ENABLE_CMDID: case WMI_TX_AGGR_ENABLE_CMDID:
return "WMI_TX_AGGR_ENABLE_CMDID"; return "WMI_TX_AGGR_ENABLE_CMDID";
case WMI_TGT_DETACH_CMDID: case WMI_TGT_DETACH_CMDID:
return "WMI_TGT_DETACH_CMDID"; return "WMI_TGT_DETACH_CMDID";
case WMI_TGT_TXQ_ENABLE_CMDID: case WMI_NODE_UPDATE_CMDID:
return "WMI_TGT_TXQ_ENABLE_CMDID"; return "WMI_NODE_UPDATE_CMDID";
case WMI_INT_STATS_CMDID:
return "WMI_INT_STATS_CMDID";
case WMI_TX_STATS_CMDID:
return "WMI_TX_STATS_CMDID";
case WMI_RX_STATS_CMDID:
return "WMI_RX_STATS_CMDID";
case WMI_AGGR_LIMIT_CMD: case WMI_AGGR_LIMIT_CMD:
return "WMI_AGGR_LIMIT_CMD"; return "WMI_AGGR_LIMIT_CMD";
} }
@ -102,9 +96,15 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
wmi->drv_priv = priv; wmi->drv_priv = priv;
wmi->stopped = false; wmi->stopped = false;
skb_queue_head_init(&wmi->wmi_event_queue);
spin_lock_init(&wmi->wmi_lock);
spin_lock_init(&wmi->event_lock);
mutex_init(&wmi->op_mutex); mutex_init(&wmi->op_mutex);
mutex_init(&wmi->multi_write_mutex); mutex_init(&wmi->multi_write_mutex);
init_completion(&wmi->cmd_wait); init_completion(&wmi->cmd_wait);
INIT_LIST_HEAD(&wmi->pending_tx_events);
tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
(unsigned long)wmi);
return wmi; return wmi;
} }
@ -120,11 +120,65 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
kfree(priv->wmi); kfree(priv->wmi);
} }
void ath9k_swba_tasklet(unsigned long data) void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv)
{ {
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; unsigned long flags;
ath9k_htc_swba(priv, priv->wmi->beacon_pending); tasklet_kill(&priv->wmi->wmi_event_tasklet);
spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
__skb_queue_purge(&priv->wmi->wmi_event_queue);
spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
}
void ath9k_wmi_event_tasklet(unsigned long data)
{
struct wmi *wmi = (struct wmi *)data;
struct ath9k_htc_priv *priv = wmi->drv_priv;
struct wmi_cmd_hdr *hdr;
void *wmi_event;
struct wmi_event_swba *swba;
struct sk_buff *skb = NULL;
unsigned long flags;
u16 cmd_id;
do {
spin_lock_irqsave(&wmi->wmi_lock, flags);
skb = __skb_dequeue(&wmi->wmi_event_queue);
if (!skb) {
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
return;
}
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
hdr = (struct wmi_cmd_hdr *) skb->data;
cmd_id = be16_to_cpu(hdr->command_id);
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
switch (cmd_id) {
case WMI_SWBA_EVENTID:
swba = (struct wmi_event_swba *) wmi_event;
ath9k_htc_swba(priv, swba);
break;
case WMI_FATAL_EVENTID:
ieee80211_queue_work(wmi->drv_priv->hw,
&wmi->drv_priv->fatal_work);
break;
case WMI_TXSTATUS_EVENTID:
spin_lock_bh(&priv->tx.tx_lock);
if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
spin_unlock_bh(&priv->tx.tx_lock);
break;
}
spin_unlock_bh(&priv->tx.tx_lock);
ath9k_htc_txstatus(priv, wmi_event);
break;
default:
break;
}
kfree_skb(skb);
} while (1);
} }
void ath9k_fatal_work(struct work_struct *work) void ath9k_fatal_work(struct work_struct *work)
@ -153,10 +207,6 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv; struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr; struct wmi_cmd_hdr *hdr;
u16 cmd_id; u16 cmd_id;
void *wmi_event;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
__be32 txrate;
#endif
if (unlikely(wmi->stopped)) if (unlikely(wmi->stopped))
goto free_skb; goto free_skb;
@ -165,26 +215,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id); cmd_id = be16_to_cpu(hdr->command_id);
if (cmd_id & 0x1000) { if (cmd_id & 0x1000) {
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); spin_lock(&wmi->wmi_lock);
switch (cmd_id) { __skb_queue_tail(&wmi->wmi_event_queue, skb);
case WMI_SWBA_EVENTID: spin_unlock(&wmi->wmi_lock);
wmi->beacon_pending = *(u8 *)wmi_event; tasklet_schedule(&wmi->wmi_event_tasklet);
tasklet_schedule(&wmi->drv_priv->swba_tasklet);
break;
case WMI_FATAL_EVENTID:
ieee80211_queue_work(wmi->drv_priv->hw,
&wmi->drv_priv->fatal_work);
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; return;
} }
@ -243,7 +277,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
hdr->command_id = cpu_to_be16(cmd); hdr->command_id = cpu_to_be16(cmd);
hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL); return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid);
} }
int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,

View File

@ -17,7 +17,6 @@
#ifndef WMI_H #ifndef WMI_H
#define WMI_H #define WMI_H
struct wmi_event_txrate { struct wmi_event_txrate {
__be32 txrate; __be32 txrate;
struct { struct {
@ -31,18 +30,65 @@ struct wmi_cmd_hdr {
__be16 seq_no; __be16 seq_no;
} __packed; } __packed;
struct wmi_fw_version {
__be16 major;
__be16 minor;
} __packed;
struct wmi_event_swba {
__be64 tsf;
u8 beacon_pending;
};
/*
* 64 - HTC header - WMI header - 1 / txstatus
* And some other hdr. space is also accounted for.
* 12 seems to be the magic number.
*/
#define HTC_MAX_TX_STATUS 12
#define ATH9K_HTC_TXSTAT_ACK BIT(0)
#define ATH9K_HTC_TXSTAT_FILT BIT(1)
#define ATH9K_HTC_TXSTAT_RTC_CTS BIT(2)
#define ATH9K_HTC_TXSTAT_MCS BIT(3)
#define ATH9K_HTC_TXSTAT_CW40 BIT(4)
#define ATH9K_HTC_TXSTAT_SGI BIT(5)
/*
* Legacy rates are indicated as indices.
* HT rates are indicated as dot11 numbers.
* This allows us to resrict the rate field
* to 4 bits.
*/
#define ATH9K_HTC_TXSTAT_RATE 0x0f
#define ATH9K_HTC_TXSTAT_RATE_S 0
#define ATH9K_HTC_TXSTAT_EPID 0xf0
#define ATH9K_HTC_TXSTAT_EPID_S 4
struct __wmi_event_txstatus {
u8 cookie;
u8 ts_rate; /* Also holds EP ID */
u8 ts_flags;
};
struct wmi_event_txstatus {
u8 cnt;
struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS];
} __packed;
enum wmi_cmd_id { enum wmi_cmd_id {
WMI_ECHO_CMDID = 0x0001, WMI_ECHO_CMDID = 0x0001,
WMI_ACCESS_MEMORY_CMDID, WMI_ACCESS_MEMORY_CMDID,
/* Commands to Target */ /* Commands to Target */
WMI_GET_FW_VERSION,
WMI_DISABLE_INTR_CMDID, WMI_DISABLE_INTR_CMDID,
WMI_ENABLE_INTR_CMDID, WMI_ENABLE_INTR_CMDID,
WMI_RX_LINK_CMDID,
WMI_ATH_INIT_CMDID, WMI_ATH_INIT_CMDID,
WMI_ABORT_TXQ_CMDID, WMI_ABORT_TXQ_CMDID,
WMI_STOP_TX_DMA_CMDID, WMI_STOP_TX_DMA_CMDID,
WMI_STOP_DMA_RECV_CMDID,
WMI_ABORT_TX_DMA_CMDID, WMI_ABORT_TX_DMA_CMDID,
WMI_DRAIN_TXQ_CMDID, WMI_DRAIN_TXQ_CMDID,
WMI_DRAIN_TXQ_ALL_CMDID, WMI_DRAIN_TXQ_ALL_CMDID,
@ -50,23 +96,21 @@ enum wmi_cmd_id {
WMI_STOP_RECV_CMDID, WMI_STOP_RECV_CMDID,
WMI_FLUSH_RECV_CMDID, WMI_FLUSH_RECV_CMDID,
WMI_SET_MODE_CMDID, WMI_SET_MODE_CMDID,
WMI_RESET_CMDID,
WMI_NODE_CREATE_CMDID, WMI_NODE_CREATE_CMDID,
WMI_NODE_REMOVE_CMDID, WMI_NODE_REMOVE_CMDID,
WMI_VAP_REMOVE_CMDID, WMI_VAP_REMOVE_CMDID,
WMI_VAP_CREATE_CMDID, WMI_VAP_CREATE_CMDID,
WMI_BEACON_UPDATE_CMDID,
WMI_REG_READ_CMDID, WMI_REG_READ_CMDID,
WMI_REG_WRITE_CMDID, WMI_REG_WRITE_CMDID,
WMI_RC_STATE_CHANGE_CMDID, WMI_RC_STATE_CHANGE_CMDID,
WMI_RC_RATE_UPDATE_CMDID, WMI_RC_RATE_UPDATE_CMDID,
WMI_DEBUG_INFO_CMDID,
WMI_HOST_ATTACH,
WMI_TARGET_IC_UPDATE_CMDID, WMI_TARGET_IC_UPDATE_CMDID,
WMI_TGT_STATS_CMDID,
WMI_TX_AGGR_ENABLE_CMDID, WMI_TX_AGGR_ENABLE_CMDID,
WMI_TGT_DETACH_CMDID, WMI_TGT_DETACH_CMDID,
WMI_TGT_TXQ_ENABLE_CMDID, WMI_NODE_UPDATE_CMDID,
WMI_INT_STATS_CMDID,
WMI_TX_STATS_CMDID,
WMI_RX_STATS_CMDID,
WMI_AGGR_LIMIT_CMD = 0x0026, WMI_AGGR_LIMIT_CMD = 0x0026,
}; };
@ -76,9 +120,8 @@ enum wmi_event_id {
WMI_FATAL_EVENTID, WMI_FATAL_EVENTID,
WMI_TXTO_EVENTID, WMI_TXTO_EVENTID,
WMI_BMISS_EVENTID, WMI_BMISS_EVENTID,
WMI_WLAN_TXCOMP_EVENTID,
WMI_DELBA_EVENTID, WMI_DELBA_EVENTID,
WMI_TXRATE_EVENTID, WMI_TXSTATUS_EVENTID,
}; };
#define MAX_CMD_NUMBER 62 #define MAX_CMD_NUMBER 62
@ -88,6 +131,12 @@ struct register_write {
__be32 val; __be32 val;
}; };
struct ath9k_htc_tx_event {
int count;
struct __wmi_event_txstatus txs;
struct list_head list;
};
struct wmi { struct wmi {
struct ath9k_htc_priv *drv_priv; struct ath9k_htc_priv *drv_priv;
struct htc_target *htc; struct htc_target *htc;
@ -95,12 +144,16 @@ struct wmi {
struct mutex op_mutex; struct mutex op_mutex;
struct completion cmd_wait; struct completion cmd_wait;
enum wmi_cmd_id last_cmd_id; enum wmi_cmd_id last_cmd_id;
struct sk_buff_head wmi_event_queue;
struct tasklet_struct wmi_event_tasklet;
u16 tx_seq_id; u16 tx_seq_id;
u8 *cmd_rsp_buf; u8 *cmd_rsp_buf;
u32 cmd_rsp_len; u32 cmd_rsp_len;
bool stopped; bool stopped;
u8 beacon_pending; struct list_head pending_tx_events;
spinlock_t event_lock;
spinlock_t wmi_lock; spinlock_t wmi_lock;
atomic_t mwrite_cnt; atomic_t mwrite_cnt;
@ -117,8 +170,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
u8 *cmd_buf, u32 cmd_len, u8 *cmd_buf, u32 cmd_len,
u8 *rsp_buf, u32 rsp_len, u8 *rsp_buf, u32 rsp_len,
u32 timeout); u32 timeout);
void ath9k_swba_tasklet(unsigned long data); void ath9k_wmi_event_tasklet(unsigned long data);
void ath9k_fatal_work(struct work_struct *work); void ath9k_fatal_work(struct work_struct *work);
void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv);
#define WMI_CMD(_wmi_cmd) \ #define WMI_CMD(_wmi_cmd) \
do { \ do { \

View File

@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_frame_info *fi; struct ath_frame_info *fi;
int nframes; int nframes;
u8 tidno; u8 tidno;
bool clear_filter;
skb = bf->bf_mpdu; skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
@ -441,22 +442,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* transmit completion */ /* transmit completion */
acked_cnt++; acked_cnt++;
} else { } else {
if (!(tid->state & AGGR_CLEANUP) && retry) { if ((tid->state & AGGR_CLEANUP) || !retry) {
if (fi->retries < ATH_MAX_SW_RETRIES) {
ath_tx_set_retry(sc, txq, bf->bf_mpdu);
txpending = 1;
} else {
bf->bf_state.bf_type |= BUF_XRETRY;
txfail = 1;
sendbar = 1;
txfail_cnt++;
}
} else {
/* /*
* cleanup in progress, just fail * cleanup in progress, just fail
* the un-acked sub-frames * the un-acked sub-frames
*/ */
txfail = 1; txfail = 1;
} else if (fi->retries < ATH_MAX_SW_RETRIES) {
if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
!an->sleeping)
ath_tx_set_retry(sc, txq, bf->bf_mpdu);
clear_filter = true;
txpending = 1;
} else {
bf->bf_state.bf_type |= BUF_XRETRY;
txfail = 1;
sendbar = 1;
txfail_cnt++;
} }
} }
@ -496,6 +499,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!txfail, sendbar); !txfail, sendbar);
} else { } else {
/* retry the un-acked ones */ /* retry the un-acked ones */
ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
if (bf->bf_next == NULL && bf_last->bf_stale) { if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf; struct ath_buf *tbf;
@ -546,7 +550,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* prepend un-acked frames to the beginning of the pending frame queue */ /* prepend un-acked frames to the beginning of the pending frame queue */
if (!list_empty(&bf_pending)) { if (!list_empty(&bf_pending)) {
if (an->sleeping)
ieee80211_sta_set_tim(sta);
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
if (clear_filter)
tid->ac->clear_ps_filter = true;
list_splice(&bf_pending, &tid->buf_q); list_splice(&bf_pending, &tid->buf_q);
ath_tx_queue_tid(txq, tid); ath_tx_queue_tid(txq, tid);
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
@ -816,6 +825,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(&bf_q, struct ath_buf, list); bf = list_first_entry(&bf_q, struct ath_buf, list);
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
if (tid->ac->clear_ps_filter) {
tid->ac->clear_ps_filter = false;
ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
}
/* if only one frame, send as non-aggregate */ /* if only one frame, send as non-aggregate */
if (bf == bf->bf_lastbf) { if (bf == bf->bf_lastbf) {
fi = get_frame_info(bf->bf_mpdu); fi = get_frame_info(bf->bf_mpdu);
@ -896,6 +910,67 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_tx_flush_tid(sc, txtid); ath_tx_flush_tid(sc, txtid);
} }
bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
{
struct ath_atx_tid *tid;
struct ath_atx_ac *ac;
struct ath_txq *txq;
bool buffered = false;
int tidno;
for (tidno = 0, tid = &an->tid[tidno];
tidno < WME_NUM_TID; tidno++, tid++) {
if (!tid->sched)
continue;
ac = tid->ac;
txq = ac->txq;
spin_lock_bh(&txq->axq_lock);
if (!list_empty(&tid->buf_q))
buffered = true;
tid->sched = false;
list_del(&tid->list);
if (ac->sched) {
ac->sched = false;
list_del(&ac->list);
}
spin_unlock_bh(&txq->axq_lock);
}
return buffered;
}
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
{
struct ath_atx_tid *tid;
struct ath_atx_ac *ac;
struct ath_txq *txq;
int tidno;
for (tidno = 0, tid = &an->tid[tidno];
tidno < WME_NUM_TID; tidno++, tid++) {
ac = tid->ac;
txq = ac->txq;
spin_lock_bh(&txq->axq_lock);
ac->clear_ps_filter = true;
if (!list_empty(&tid->buf_q) && !tid->paused) {
ath_tx_queue_tid(txq, tid);
ath_txq_schedule(sc, txq);
}
spin_unlock_bh(&txq->axq_lock);
}
}
void ath_tx_aggr_resume(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)
{ {
struct ath_atx_tid *txtid; struct ath_atx_tid *txtid;
@ -1451,7 +1526,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ath_frame_info *fi = get_frame_info(skb); struct ath_frame_info *fi = get_frame_info(skb);
struct ath_node *an; struct ath_node *an = NULL;
struct ath_atx_tid *tid; struct ath_atx_tid *tid;
enum ath9k_key_type keytype; enum ath9k_key_type keytype;
u16 seqno = 0; u16 seqno = 0;
@ -1459,11 +1534,13 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
keytype = ath9k_cmn_get_hw_crypto_keytype(skb); keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
if (sta)
an = (struct ath_node *) sta->drv_priv;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
if (sta && ieee80211_is_data_qos(hdr->frame_control) && if (an && ieee80211_is_data_qos(hdr->frame_control) &&
conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
an = (struct ath_node *) sta->drv_priv;
tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
/* /*
@ -1479,6 +1556,8 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
memset(fi, 0, sizeof(*fi)); memset(fi, 0, sizeof(*fi));
if (hw_key) if (hw_key)
fi->keyix = hw_key->hw_key_idx; fi->keyix = hw_key->hw_key_idx;
else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
fi->keyix = an->ps_key;
else else
fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keyix = ATH9K_TXKEYIX_INVALID;
fi->keytype = keytype; fi->keytype = keytype;
@ -1491,7 +1570,6 @@ static int setup_tx_flags(struct sk_buff *skb)
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int flags = 0; int flags = 0;
flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
flags |= ATH9K_TXDESC_INTREQ; flags |= ATH9K_TXDESC_INTREQ;
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
@ -1754,6 +1832,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
if (txctl->paprd) if (txctl->paprd)
bf->bf_state.bfs_paprd_timestamp = jiffies; bf->bf_state.bfs_paprd_timestamp = jiffies;
if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
} }

View File

@ -483,6 +483,9 @@ int ath_key_config(struct ath_common *common,
memset(&hk, 0, sizeof(hk)); memset(&hk, 0, sizeof(hk));
switch (key->cipher) { switch (key->cipher) {
case 0:
hk.kv_type = ATH_CIPHER_CLR;
break;
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
hk.kv_type = ATH_CIPHER_WEP; hk.kv_type = ATH_CIPHER_WEP;
@ -498,7 +501,8 @@ int ath_key_config(struct ath_common *common,
} }
hk.kv_len = key->keylen; hk.kv_len = key->keylen;
memcpy(hk.kv_val, key->key, key->keylen); if (key->keylen)
memcpy(hk.kv_val, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
switch (vif->type) { switch (vif->type) {

View File

@ -97,8 +97,8 @@ static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
} }
}; };
/* Can be used by 0x67, 0x6A and 0x68 */ /* Can be used by 0x67, 0x68, 0x6A and 0x6C */
static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
.n_reg_rules = 4, .n_reg_rules = 4,
.alpha2 = "99", .alpha2 = "99",
.reg_rules = { .reg_rules = {
@ -151,7 +151,8 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
case 0x67: case 0x67:
case 0x68: case 0x68:
case 0x6A: case 0x6A:
return &ath_world_regdom_67_68_6A; case 0x6C:
return &ath_world_regdom_67_68_6A_6C;
default: default:
WARN_ON(1); WARN_ON(1);
return ath_default_world_regdomain(); return ath_default_world_regdomain();
@ -333,6 +334,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
case 0x63: case 0x63:
case 0x66: case 0x66:
case 0x67: case 0x67:
case 0x6C:
ath_reg_apply_beaconing_flags(wiphy, initiator); ath_reg_apply_beaconing_flags(wiphy, initiator);
break; break;
case 0x68: case 0x68:

View File

@ -86,6 +86,7 @@ enum EnumRd {
WOR9_WORLD = 0x69, WOR9_WORLD = 0x69,
WORA_WORLD = 0x6A, WORA_WORLD = 0x6A,
WORB_WORLD = 0x6B, WORB_WORLD = 0x6B,
WORC_WORLD = 0x6C,
MKK3_MKKB = 0x80, MKK3_MKKB = 0x80,
MKK3_MKKA2 = 0x81, MKK3_MKKA2 = 0x81,
@ -282,6 +283,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = {
{WOR9_WORLD, NO_CTL, NO_CTL}, {WOR9_WORLD, NO_CTL, NO_CTL},
{WORA_WORLD, NO_CTL, NO_CTL}, {WORA_WORLD, NO_CTL, NO_CTL},
{WORB_WORLD, NO_CTL, NO_CTL}, {WORB_WORLD, NO_CTL, NO_CTL},
{WORC_WORLD, NO_CTL, NO_CTL},
}; };
static struct country_code_to_enum_rd allCountries[] = { static struct country_code_to_enum_rd allCountries[] = {

View File

@ -2860,7 +2860,6 @@ static struct rate_control_ops rs_4965_ops = {
int iwl4965_rate_control_register(void) int iwl4965_rate_control_register(void)
{ {
pr_err("Registering 4965 rate control operations\n");
return ieee80211_rate_control_register(&rs_4965_ops); return ieee80211_rate_control_register(&rs_4965_ops);
} }

View File

@ -3173,7 +3173,7 @@ static void iwl4965_hw_detect(struct iwl_priv *priv)
{ {
priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV); priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV);
priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG); priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG);
pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); priv->rev_id = priv->pci_dev->revision;
IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
} }

View File

@ -1,6 +1,6 @@
# AGN # AGN
obj-$(CONFIG_IWLAGN) += iwlagn.o obj-$(CONFIG_IWLAGN) += iwlagn.o
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o
iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o
iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o

View File

@ -45,7 +45,6 @@
#include "iwl-agn.h" #include "iwl-agn.h"
#include "iwl-helpers.h" #include "iwl-helpers.h"
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
#include "iwl-agn-led.h"
#include "iwl-agn-debugfs.h" #include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
@ -57,12 +56,10 @@
#define IWL100_UCODE_API_MIN 5 #define IWL100_UCODE_API_MIN 5
#define IWL1000_FW_PRE "iwlwifi-1000-" #define IWL1000_FW_PRE "iwlwifi-1000-"
#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
#define IWL100_FW_PRE "iwlwifi-100-" #define IWL100_FW_PRE "iwlwifi-100-"
#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" #define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api)
/* /*
@ -184,10 +181,6 @@ static struct iwl_lib_ops iwl1000_lib = {
.rx_handler_setup = iwlagn_rx_handler_setup, .rx_handler_setup = iwlagn_rx_handler_setup,
.setup_deferred_work = iwlagn_setup_deferred_work, .setup_deferred_work = iwlagn_setup_deferred_work,
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.dump_fh = iwl_dump_fh,
.send_tx_power = iwlagn_send_tx_power, .send_tx_power = iwlagn_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.apm_ops = { .apm_ops = {
@ -202,7 +195,7 @@ static struct iwl_lib_ops iwl1000_lib = {
EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_4_CHANNELS,
EEPROM_REG_BAND_5_CHANNELS, EEPROM_REG_BAND_5_CHANNELS,
EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS EEPROM_REGULATORY_BAND_NO_HT40,
}, },
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore,
@ -221,19 +214,12 @@ static struct iwl_lib_ops iwl1000_lib = {
}, },
.txfifo_flush = iwlagn_txfifo_flush, .txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
.tt_ops = {
.lower_power_detection = iwl_tt_is_low_power_state,
.tt_power_mode = iwl_tt_current_power_mode,
.ct_kill_check = iwl_check_for_ct_kill,
}
}; };
static const struct iwl_ops iwl1000_ops = { static const struct iwl_ops iwl1000_ops = {
.lib = &iwl1000_lib, .lib = &iwl1000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static struct iwl_base_params iwl1000_base_params = { static struct iwl_base_params iwl1000_base_params = {
@ -241,7 +227,6 @@ static struct iwl_base_params iwl1000_base_params = {
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.max_ll_items = OTP_MAX_LL_ITEMS_1000, .max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false, .shadow_ram_support = false,
.led_compensation = 51, .led_compensation = 51,
@ -251,9 +236,6 @@ static struct iwl_base_params iwl1000_base_params = {
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT, .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 128, .max_event_log_size = 128,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
}; };
static struct iwl_ht_params iwl1000_ht_params = { static struct iwl_ht_params iwl1000_ht_params = {
.ht_greenfield_support = true, .ht_greenfield_support = true,

View File

@ -46,7 +46,6 @@
#include "iwl-helpers.h" #include "iwl-helpers.h"
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
#include "iwl-6000-hw.h" #include "iwl-6000-hw.h"
#include "iwl-agn-led.h"
#include "iwl-agn-debugfs.h" #include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
@ -60,16 +59,13 @@
#define IWL200_UCODE_API_MIN 5 #define IWL200_UCODE_API_MIN 5
#define IWL2030_FW_PRE "iwlwifi-2030-" #define IWL2030_FW_PRE "iwlwifi-2030-"
#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api)
#define IWL2000_FW_PRE "iwlwifi-2000-" #define IWL2000_FW_PRE "iwlwifi-2000-"
#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" #define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api)
#define IWL200_FW_PRE "iwlwifi-200-" #define IWL200_FW_PRE "iwlwifi-200-"
#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" #define IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode"
#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api)
static void iwl2000_set_ct_threshold(struct iwl_priv *priv) static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
{ {
@ -101,6 +97,8 @@ static void iwl2000_nic_config(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GP_DRIVER_REG, iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
if (priv->cfg->disable_otp_refresh)
iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010);
} }
static struct iwl_sensitivity_ranges iwl2000_sensitivity = { static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
@ -265,10 +263,6 @@ static struct iwl_lib_ops iwl2000_lib = {
.setup_deferred_work = iwlagn_bt_setup_deferred_work, .setup_deferred_work = iwlagn_bt_setup_deferred_work,
.cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.dump_fh = iwl_dump_fh,
.send_tx_power = iwlagn_send_tx_power, .send_tx_power = iwlagn_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl2030_hw_channel_switch, .set_channel_switch = iwl2030_hw_channel_switch,
@ -284,7 +278,7 @@ static struct iwl_lib_ops iwl2000_lib = {
EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_4_CHANNELS,
EEPROM_REG_BAND_5_CHANNELS, EEPROM_REG_BAND_5_CHANNELS,
EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS EEPROM_REGULATORY_BAND_NO_HT40,
}, },
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore,
@ -304,43 +298,30 @@ static struct iwl_lib_ops iwl2000_lib = {
}, },
.txfifo_flush = iwlagn_txfifo_flush, .txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
.tt_ops = {
.lower_power_detection = iwl_tt_is_low_power_state,
.tt_power_mode = iwl_tt_current_power_mode,
.ct_kill_check = iwl_check_for_ct_kill,
}
}; };
static const struct iwl_ops iwl2000_ops = { static const struct iwl_ops iwl2000_ops = {
.lib = &iwl2000_lib, .lib = &iwl2000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl2030_ops = { static const struct iwl_ops iwl2030_ops = {
.lib = &iwl2000_lib, .lib = &iwl2000_lib,
.hcmd = &iwlagn_bt_hcmd, .hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl200_ops = { static const struct iwl_ops iwl200_ops = {
.lib = &iwl2000_lib, .lib = &iwl2000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl230_ops = { static const struct iwl_ops iwl230_ops = {
.lib = &iwl2000_lib, .lib = &iwl2000_lib,
.hcmd = &iwlagn_bt_hcmd, .hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static struct iwl_base_params iwl2000_base_params = { static struct iwl_base_params iwl2000_base_params = {
@ -348,7 +329,6 @@ static struct iwl_base_params iwl2000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0, .pll_cfg_val = 0,
.set_l0s = true,
.max_ll_items = OTP_MAX_LL_ITEMS_2x00, .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true, .shadow_ram_support = true,
.led_compensation = 51, .led_compensation = 51,
@ -359,9 +339,6 @@ static struct iwl_base_params iwl2000_base_params = {
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT, .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512, .max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
.shadow_reg_enable = true, .shadow_reg_enable = true,
}; };
@ -371,7 +348,6 @@ static struct iwl_base_params iwl2030_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0, .pll_cfg_val = 0,
.set_l0s = true,
.max_ll_items = OTP_MAX_LL_ITEMS_2x00, .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true, .shadow_ram_support = true,
.led_compensation = 57, .led_compensation = 57,
@ -382,9 +358,6 @@ static struct iwl_base_params iwl2030_base_params = {
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT, .wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512, .max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
.shadow_reg_enable = true, .shadow_reg_enable = true,
}; };
@ -394,7 +367,6 @@ static struct iwl_ht_params iwl2000_ht_params = {
}; };
static struct iwl_bt_params iwl2030_bt_params = { static struct iwl_bt_params iwl2030_bt_params = {
.bt_statistics = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true, .advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF, .agg_time_limit = BT_AGG_THRESHOLD_DEF,
@ -416,7 +388,8 @@ static struct iwl_bt_params iwl2030_bt_params = {
.need_dc_calib = true, \ .need_dc_calib = true, \
.need_temp_offset_calib = true, \ .need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \ .led_mode = IWL_LED_RF_STATE, \
.iq_invert = true \ .iq_invert = true, \
.disable_otp_refresh = true \
struct iwl_cfg iwl2000_2bgn_cfg = { struct iwl_cfg iwl2000_2bgn_cfg = {
.name = "2000 Series 2x2 BGN", .name = "2000 Series 2x2 BGN",

View File

@ -45,7 +45,6 @@
#include "iwl-sta.h" #include "iwl-sta.h"
#include "iwl-helpers.h" #include "iwl-helpers.h"
#include "iwl-agn.h" #include "iwl-agn.h"
#include "iwl-agn-led.h"
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
#include "iwl-5000-hw.h" #include "iwl-5000-hw.h"
#include "iwl-agn-debugfs.h" #include "iwl-agn-debugfs.h"
@ -59,12 +58,10 @@
#define IWL5150_UCODE_API_MIN 1 #define IWL5150_UCODE_API_MIN 1
#define IWL5000_FW_PRE "iwlwifi-5000-" #define IWL5000_FW_PRE "iwlwifi-5000-"
#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" #define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api)
#define IWL5150_FW_PRE "iwlwifi-5150-" #define IWL5150_FW_PRE "iwlwifi-5150-"
#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" #define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
/* NIC configuration for 5000 series */ /* NIC configuration for 5000 series */
static void iwl5000_nic_config(struct iwl_priv *priv) static void iwl5000_nic_config(struct iwl_priv *priv)
@ -261,7 +258,7 @@ static void iwl5150_temperature(struct iwl_priv *priv)
u32 vt = 0; u32 vt = 0;
s32 offset = iwl_temp_calib_to_offset(priv); s32 offset = iwl_temp_calib_to_offset(priv);
vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature); vt = le32_to_cpu(priv->statistics.common.temperature);
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
/* now vt hold the temperature in Kelvin */ /* now vt hold the temperature in Kelvin */
priv->temperature = KELVIN_TO_CELSIUS(vt); priv->temperature = KELVIN_TO_CELSIUS(vt);
@ -352,10 +349,6 @@ static struct iwl_lib_ops iwl5000_lib = {
.rx_handler_setup = iwlagn_rx_handler_setup, .rx_handler_setup = iwlagn_rx_handler_setup,
.setup_deferred_work = iwlagn_setup_deferred_work, .setup_deferred_work = iwlagn_setup_deferred_work,
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.dump_fh = iwl_dump_fh,
.send_tx_power = iwlagn_send_tx_power, .send_tx_power = iwlagn_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl5000_hw_channel_switch, .set_channel_switch = iwl5000_hw_channel_switch,
@ -390,11 +383,6 @@ static struct iwl_lib_ops iwl5000_lib = {
}, },
.txfifo_flush = iwlagn_txfifo_flush, .txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
.tt_ops = {
.lower_power_detection = iwl_tt_is_low_power_state,
.tt_power_mode = iwl_tt_current_power_mode,
.ct_kill_check = iwl_check_for_ct_kill,
}
}; };
static struct iwl_lib_ops iwl5150_lib = { static struct iwl_lib_ops iwl5150_lib = {
@ -408,9 +396,6 @@ static struct iwl_lib_ops iwl5150_lib = {
.rx_handler_setup = iwlagn_rx_handler_setup, .rx_handler_setup = iwlagn_rx_handler_setup,
.setup_deferred_work = iwlagn_setup_deferred_work, .setup_deferred_work = iwlagn_setup_deferred_work,
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.send_tx_power = iwlagn_send_tx_power, .send_tx_power = iwlagn_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl5000_hw_channel_switch, .set_channel_switch = iwl5000_hw_channel_switch,
@ -445,27 +430,18 @@ static struct iwl_lib_ops iwl5150_lib = {
}, },
.txfifo_flush = iwlagn_txfifo_flush, .txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
.tt_ops = {
.lower_power_detection = iwl_tt_is_low_power_state,
.tt_power_mode = iwl_tt_current_power_mode,
.ct_kill_check = iwl_check_for_ct_kill,
}
}; };
static const struct iwl_ops iwl5000_ops = { static const struct iwl_ops iwl5000_ops = {
.lib = &iwl5000_lib, .lib = &iwl5000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl5150_ops = { static const struct iwl_ops iwl5150_ops = {
.lib = &iwl5150_lib, .lib = &iwl5150_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static struct iwl_base_params iwl5000_base_params = { static struct iwl_base_params iwl5000_base_params = {
@ -473,16 +449,12 @@ static struct iwl_base_params iwl5000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT, .wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512, .max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
}; };
static struct iwl_ht_params iwl5000_ht_params = { static struct iwl_ht_params iwl5000_ht_params = {
.ht_greenfield_support = true, .ht_greenfield_support = true,

View File

@ -46,7 +46,6 @@
#include "iwl-helpers.h" #include "iwl-helpers.h"
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
#include "iwl-6000-hw.h" #include "iwl-6000-hw.h"
#include "iwl-agn-led.h"
#include "iwl-agn-debugfs.h" #include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
@ -60,20 +59,16 @@
#define IWL6000G2_UCODE_API_MIN 4 #define IWL6000G2_UCODE_API_MIN 4
#define IWL6000_FW_PRE "iwlwifi-6000-" #define IWL6000_FW_PRE "iwlwifi-6000-"
#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" #define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api)
#define IWL6050_FW_PRE "iwlwifi-6050-" #define IWL6050_FW_PRE "iwlwifi-6050-"
#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
#define IWL6005_FW_PRE "iwlwifi-6000g2a-" #define IWL6005_FW_PRE "iwlwifi-6000g2a-"
#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" #define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode"
#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api)
#define IWL6030_FW_PRE "iwlwifi-6000g2b-" #define IWL6030_FW_PRE "iwlwifi-6000g2b-"
#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" #define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode"
#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api)
static void iwl6000_set_ct_threshold(struct iwl_priv *priv) static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{ {
@ -293,10 +288,6 @@ static struct iwl_lib_ops iwl6000_lib = {
.rx_handler_setup = iwlagn_rx_handler_setup, .rx_handler_setup = iwlagn_rx_handler_setup,
.setup_deferred_work = iwlagn_setup_deferred_work, .setup_deferred_work = iwlagn_setup_deferred_work,
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.dump_fh = iwl_dump_fh,
.send_tx_power = iwlagn_send_tx_power, .send_tx_power = iwlagn_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl6000_hw_channel_switch, .set_channel_switch = iwl6000_hw_channel_switch,
@ -332,11 +323,6 @@ static struct iwl_lib_ops iwl6000_lib = {
}, },
.txfifo_flush = iwlagn_txfifo_flush, .txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
.tt_ops = {
.lower_power_detection = iwl_tt_is_low_power_state,
.tt_power_mode = iwl_tt_current_power_mode,
.ct_kill_check = iwl_check_for_ct_kill,
}
}; };
static struct iwl_lib_ops iwl6030_lib = { static struct iwl_lib_ops iwl6030_lib = {
@ -351,10 +337,6 @@ static struct iwl_lib_ops iwl6030_lib = {
.setup_deferred_work = iwlagn_bt_setup_deferred_work, .setup_deferred_work = iwlagn_bt_setup_deferred_work,
.cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.dump_fh = iwl_dump_fh,
.send_tx_power = iwlagn_send_tx_power, .send_tx_power = iwlagn_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl6000_hw_channel_switch, .set_channel_switch = iwl6000_hw_channel_switch,
@ -390,11 +372,6 @@ static struct iwl_lib_ops iwl6030_lib = {
}, },
.txfifo_flush = iwlagn_txfifo_flush, .txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
.tt_ops = {
.lower_power_detection = iwl_tt_is_low_power_state,
.tt_power_mode = iwl_tt_current_power_mode,
.ct_kill_check = iwl_check_for_ct_kill,
}
}; };
static struct iwl_nic_ops iwl6050_nic_ops = { static struct iwl_nic_ops iwl6050_nic_ops = {
@ -409,34 +386,26 @@ static const struct iwl_ops iwl6000_ops = {
.lib = &iwl6000_lib, .lib = &iwl6000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl6050_ops = { static const struct iwl_ops iwl6050_ops = {
.lib = &iwl6000_lib, .lib = &iwl6000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.nic = &iwl6050_nic_ops, .nic = &iwl6050_nic_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl6150_ops = { static const struct iwl_ops iwl6150_ops = {
.lib = &iwl6000_lib, .lib = &iwl6000_lib,
.hcmd = &iwlagn_hcmd, .hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.nic = &iwl6150_nic_ops, .nic = &iwl6150_nic_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static const struct iwl_ops iwl6030_ops = { static const struct iwl_ops iwl6030_ops = {
.lib = &iwl6030_lib, .lib = &iwl6030_lib,
.hcmd = &iwlagn_bt_hcmd, .hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils, .utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.ieee80211_ops = &iwlagn_hw_ops,
}; };
static struct iwl_base_params iwl6000_base_params = { static struct iwl_base_params iwl6000_base_params = {
@ -444,7 +413,6 @@ static struct iwl_base_params iwl6000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0, .pll_cfg_val = 0,
.set_l0s = true,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
.led_compensation = 51, .led_compensation = 51,
@ -455,9 +423,6 @@ static struct iwl_base_params iwl6000_base_params = {
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT, .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512, .max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
.shadow_reg_enable = true, .shadow_reg_enable = true,
}; };
@ -466,7 +431,6 @@ static struct iwl_base_params iwl6050_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0, .pll_cfg_val = 0,
.set_l0s = true,
.max_ll_items = OTP_MAX_LL_ITEMS_6x50, .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true, .shadow_ram_support = true,
.led_compensation = 51, .led_compensation = 51,
@ -477,9 +441,6 @@ static struct iwl_base_params iwl6050_base_params = {
.chain_noise_scale = 1500, .chain_noise_scale = 1500,
.wd_timeout = IWL_DEF_WD_TIMEOUT, .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 1024, .max_event_log_size = 1024,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
.shadow_reg_enable = true, .shadow_reg_enable = true,
}; };
static struct iwl_base_params iwl6000_g2_base_params = { static struct iwl_base_params iwl6000_g2_base_params = {
@ -487,7 +448,6 @@ static struct iwl_base_params iwl6000_g2_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0, .pll_cfg_val = 0,
.set_l0s = true,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
.led_compensation = 57, .led_compensation = 57,
@ -498,9 +458,6 @@ static struct iwl_base_params iwl6000_g2_base_params = {
.chain_noise_scale = 1000, .chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT, .wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512, .max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
.shadow_reg_enable = true, .shadow_reg_enable = true,
}; };
@ -510,7 +467,6 @@ static struct iwl_ht_params iwl6000_ht_params = {
}; };
static struct iwl_bt_params iwl6000_bt_params = { static struct iwl_bt_params iwl6000_bt_params = {
.bt_statistics = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true, .advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF, .agg_time_limit = BT_AGG_THRESHOLD_DEF,

View File

@ -605,7 +605,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret); IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
} }
void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp) void iwl_sensitivity_calibration(struct iwl_priv *priv)
{ {
u32 rx_enable_time; u32 rx_enable_time;
u32 fa_cck; u32 fa_cck;
@ -631,16 +631,9 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
} }
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
if (iwl_bt_statistics(priv)) { rx_info = &priv->statistics.rx_non_phy;
rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> ofdm = &priv->statistics.rx_ofdm;
rx.general.common); cck = &priv->statistics.rx_cck;
ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck);
} else {
rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general);
ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm);
cck = &(((struct iwl_notif_statistics *)resp)->rx.cck);
}
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
@ -851,7 +844,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
* 1) Which antennas are connected. * 1) Which antennas are connected.
* 2) Differential rx gain settings to balance the 3 receivers. * 2) Differential rx gain settings to balance the 3 receivers.
*/ */
void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) void iwl_chain_noise_calibration(struct iwl_priv *priv)
{ {
struct iwl_chain_noise_data *data = NULL; struct iwl_chain_noise_data *data = NULL;
@ -896,13 +889,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
} }
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
if (iwl_bt_statistics(priv)) {
rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> rx_info = &priv->statistics.rx_non_phy;
rx.general.common);
} else {
rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
rx.general);
}
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
@ -911,19 +900,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
rxon_chnum = le16_to_cpu(ctx->staging.channel); rxon_chnum = le16_to_cpu(ctx->staging.channel);
if (iwl_bt_statistics(priv)) { stat_band24 =
stat_band24 = !!(((struct iwl_bt_notif_statistics *) !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
stat_resp)->flag & stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
STATISTICS_REPLY_FLG_BAND_24G_MSK);
stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *)
stat_resp)->flag) >> 16;
} else {
stat_band24 = !!(((struct iwl_notif_statistics *)
stat_resp)->flag &
STATISTICS_REPLY_FLG_BAND_24G_MSK);
stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *)
stat_resp)->flag) >> 16;
}
/* Make sure we accumulate data for just the associated channel /* Make sure we accumulate data for just the associated channel
* (even if scanning). */ * (even if scanning). */

View File

@ -66,8 +66,8 @@
#include "iwl-core.h" #include "iwl-core.h"
#include "iwl-commands.h" #include "iwl-commands.h"
void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); void iwl_chain_noise_calibration(struct iwl_priv *priv);
void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); void iwl_sensitivity_calibration(struct iwl_priv *priv);
void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_init_sensitivity(struct iwl_priv *priv);
void iwl_reset_run_time_calib(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv);

View File

@ -39,10 +39,7 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
int p = 0; int p = 0;
u32 flag; u32 flag;
if (iwl_bt_statistics(priv)) flag = le32_to_cpu(priv->statistics.flag);
flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
else
flag = le32_to_cpu(priv->_agn.statistics.flag);
p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
if (flag & UCODE_STATISTICS_CLEAR_MSK) if (flag & UCODE_STATISTICS_CLEAR_MSK)
@ -88,43 +85,22 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
* the last statistics notification from uCode * the last statistics notification from uCode
* might not reflect the current uCode activity * might not reflect the current uCode activity
*/ */
if (iwl_bt_statistics(priv)) { ofdm = &priv->statistics.rx_ofdm;
ofdm = &priv->_agn.statistics_bt.rx.ofdm; cck = &priv->statistics.rx_cck;
cck = &priv->_agn.statistics_bt.rx.cck; general = &priv->statistics.rx_non_phy;
general = &priv->_agn.statistics_bt.rx.general.common; ht = &priv->statistics.rx_ofdm_ht;
ht = &priv->_agn.statistics_bt.rx.ofdm_ht; accum_ofdm = &priv->accum_stats.rx_ofdm;
accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm; accum_cck = &priv->accum_stats.rx_cck;
accum_cck = &priv->_agn.accum_statistics_bt.rx.cck; accum_general = &priv->accum_stats.rx_non_phy;
accum_general = accum_ht = &priv->accum_stats.rx_ofdm_ht;
&priv->_agn.accum_statistics_bt.rx.general.common; delta_ofdm = &priv->delta_stats.rx_ofdm;
accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht; delta_cck = &priv->delta_stats.rx_cck;
delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm; delta_general = &priv->delta_stats.rx_non_phy;
delta_cck = &priv->_agn.delta_statistics_bt.rx.cck; delta_ht = &priv->delta_stats.rx_ofdm_ht;
delta_general = max_ofdm = &priv->max_delta_stats.rx_ofdm;
&priv->_agn.delta_statistics_bt.rx.general.common; max_cck = &priv->max_delta_stats.rx_cck;
delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht; max_general = &priv->max_delta_stats.rx_non_phy;
max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm; max_ht = &priv->max_delta_stats.rx_ofdm_ht;
max_cck = &priv->_agn.max_delta_bt.rx.cck;
max_general = &priv->_agn.max_delta_bt.rx.general.common;
max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht;
} else {
ofdm = &priv->_agn.statistics.rx.ofdm;
cck = &priv->_agn.statistics.rx.cck;
general = &priv->_agn.statistics.rx.general;
ht = &priv->_agn.statistics.rx.ofdm_ht;
accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm;
accum_cck = &priv->_agn.accum_statistics.rx.cck;
accum_general = &priv->_agn.accum_statistics.rx.general;
accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht;
delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm;
delta_cck = &priv->_agn.delta_statistics.rx.cck;
delta_general = &priv->_agn.delta_statistics.rx.general;
delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht;
max_ofdm = &priv->_agn.max_delta.rx.ofdm;
max_cck = &priv->_agn.max_delta.rx.cck;
max_general = &priv->_agn.max_delta.rx.general;
max_ht = &priv->_agn.max_delta.rx.ofdm_ht;
}
pos += iwl_statistics_flag(priv, buf, bufsz); pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
@ -531,20 +507,13 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
} }
/* the statistic information display here is based on /* the statistic information display here is based on
* the last statistics notification from uCode * the last statistics notification from uCode
* might not reflect the current uCode activity * might not reflect the current uCode activity
*/ */
if (iwl_bt_statistics(priv)) { tx = &priv->statistics.tx;
tx = &priv->_agn.statistics_bt.tx; accum_tx = &priv->accum_stats.tx;
accum_tx = &priv->_agn.accum_statistics_bt.tx; delta_tx = &priv->delta_stats.tx;
delta_tx = &priv->_agn.delta_statistics_bt.tx; max_tx = &priv->max_delta_stats.tx;
max_tx = &priv->_agn.max_delta_bt.tx;
} else {
tx = &priv->_agn.statistics.tx;
accum_tx = &priv->_agn.accum_statistics.tx;
delta_tx = &priv->_agn.delta_statistics.tx;
max_tx = &priv->_agn.max_delta.tx;
}
pos += iwl_statistics_flag(priv, buf, bufsz); pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
@ -731,36 +700,21 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
} }
/* the statistic information display here is based on /* the statistic information display here is based on
* the last statistics notification from uCode * the last statistics notification from uCode
* might not reflect the current uCode activity * might not reflect the current uCode activity
*/ */
if (iwl_bt_statistics(priv)) { general = &priv->statistics.common;
general = &priv->_agn.statistics_bt.general.common; dbg = &priv->statistics.common.dbg;
dbg = &priv->_agn.statistics_bt.general.common.dbg; div = &priv->statistics.common.div;
div = &priv->_agn.statistics_bt.general.common.div; accum_general = &priv->accum_stats.common;
accum_general = &priv->_agn.accum_statistics_bt.general.common; accum_dbg = &priv->accum_stats.common.dbg;
accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg; accum_div = &priv->accum_stats.common.div;
accum_div = &priv->_agn.accum_statistics_bt.general.common.div; delta_general = &priv->delta_stats.common;
delta_general = &priv->_agn.delta_statistics_bt.general.common; max_general = &priv->max_delta_stats.common;
max_general = &priv->_agn.max_delta_bt.general.common; delta_dbg = &priv->delta_stats.common.dbg;
delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg; max_dbg = &priv->max_delta_stats.common.dbg;
max_dbg = &priv->_agn.max_delta_bt.general.common.dbg; delta_div = &priv->delta_stats.common.div;
delta_div = &priv->_agn.delta_statistics_bt.general.common.div; max_div = &priv->max_delta_stats.common.div;
max_div = &priv->_agn.max_delta_bt.general.common.div;
} else {
general = &priv->_agn.statistics.general.common;
dbg = &priv->_agn.statistics.general.common.dbg;
div = &priv->_agn.statistics.general.common.div;
accum_general = &priv->_agn.accum_statistics.general.common;
accum_dbg = &priv->_agn.accum_statistics.general.common.dbg;
accum_div = &priv->_agn.accum_statistics.general.common.div;
delta_general = &priv->_agn.delta_statistics.general.common;
max_general = &priv->_agn.max_delta.general.common;
delta_dbg = &priv->_agn.delta_statistics.general.common.dbg;
max_dbg = &priv->_agn.max_delta.general.common.dbg;
delta_div = &priv->_agn.delta_statistics.general.common.div;
max_div = &priv->_agn.max_delta.general.common.div;
}
pos += iwl_statistics_flag(priv, buf, bufsz); pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
@ -876,8 +830,8 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file,
* the last statistics notification from uCode * the last statistics notification from uCode
* might not reflect the current uCode activity * might not reflect the current uCode activity
*/ */
bt = &priv->_agn.statistics_bt.general.activity; bt = &priv->statistics.bt_activity;
accum_bt = &priv->_agn.accum_statistics_bt.general.activity; accum_bt = &priv->accum_stats.bt_activity;
pos += iwl_statistics_flag(priv, buf, bufsz); pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
@ -918,10 +872,8 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"(rx)num_bt_kills:\t\t%u\t\t\t%u\n", "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
le32_to_cpu(priv->_agn.statistics_bt.rx. le32_to_cpu(priv->statistics.num_bt_kills),
general.num_bt_kills), priv->statistics.accum_num_bt_kills);
priv->_agn.accum_statistics_bt.rx.
general.num_bt_kills);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf); kfree(buf);

View File

@ -1,73 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
#include "iwl-commands.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-agn-led.h"
/* Send led command */
static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
{
struct iwl_host_cmd cmd = {
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
.flags = CMD_ASYNC,
.callback = NULL,
};
u32 reg;
reg = iwl_read32(priv, CSR_LED_REG);
if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
return iwl_send_cmd(priv, &cmd);
}
/* Set led register off */
void iwlagn_led_enable(struct iwl_priv *priv)
{
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
}
const struct iwl_led_ops iwlagn_led_ops = {
.cmd = iwl_send_led_cmd,
};

View File

@ -1,33 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
#ifndef __iwl_agn_led_h__
#define __iwl_agn_led_h__
extern const struct iwl_led_ops iwlagn_led_ops;
void iwlagn_led_enable(struct iwl_priv *priv);
#endif /* __iwl_agn_led_h__ */

View File

@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
static void iwlagn_set_tx_status(struct iwl_priv *priv, static void iwlagn_set_tx_status(struct iwl_priv *priv,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
struct iwl_rxon_context *ctx,
struct iwlagn_tx_resp *tx_resp, struct iwlagn_tx_resp *tx_resp,
int txq_id, bool is_agg) int txq_id, bool is_agg)
{ {
@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv,
if (!iwl_is_tx_success(status)) if (!iwl_is_tx_success(status))
iwlagn_count_tx_err_status(priv, status); iwlagn_count_tx_err_status(priv, status);
if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
iwl_is_associated_ctx(ctx) && ctx->vif &&
ctx->vif->type == NL80211_IFTYPE_STATION) {
ctx->last_tx_rejected = true;
iwl_stop_queue(priv, &priv->txq[txq_id]);
}
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
"0x%x retries %d\n", "0x%x retries %d\n",
txq_id, txq_id,
@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
/* # frames attempted by Tx command */ /* # frames attempted by Tx command */
if (agg->frame_count == 1) { if (agg->frame_count == 1) {
struct iwl_tx_info *txb;
/* Only one frame was attempted; no block-ack will arrive */ /* Only one frame was attempted; no block-ack will arrive */
idx = start_idx; idx = start_idx;
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx); agg->frame_count, agg->start_idx, idx);
iwlagn_set_tx_status(priv, txb = &priv->txq[txq_id].txb[idx];
IEEE80211_SKB_CB( iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb),
priv->txq[txq_id].txb[idx].skb), txb->ctx, tx_resp, txq_id, true);
tx_resp, txq_id, true);
agg->wait_for_ba = 0; agg->wait_for_ba = 0;
} else { } else {
/* Two or more frames were attempted; expect block-ack */ /* Two or more frames were attempted; expect block-ack */
@ -391,7 +400,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le16_to_cpu(tx_resp->status.status); struct iwl_tx_info *txb;
u32 status = le16_to_cpu(tx_resp->status.status);
int tid; int tid;
int sta_id; int sta_id;
int freed; int freed;
@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
} }
txq->time_stamp = jiffies; txq->time_stamp = jiffies;
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); txb = &txq->txb[txq->q.read_ptr];
info = IEEE80211_SKB_CB(txb->skb);
memset(&info->status, 0, sizeof(info->status)); memset(&info->status, 0, sizeof(info->status));
tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
iwl_wake_queue(priv, txq); iwl_wake_queue(priv, txq);
} }
} else { } else {
iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false); iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp,
txq_id, false);
freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
iwl_free_tfds_in_queue(priv, sta_id, tid, freed); iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if (priv->mac80211_registered && if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark)) iwl_queue_space(&txq->q) > txq->q.low_mark &&
status != TX_STATUS_FAIL_PASSIVE_NO_RX)
iwl_wake_queue(priv, txq); iwl_wake_queue(priv, txq);
} }
@ -482,8 +495,10 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
void iwlagn_setup_deferred_work(struct iwl_priv *priv) void iwlagn_setup_deferred_work(struct iwl_priv *priv)
{ {
/* in agn, the tx power calibration is done in uCode */ /*
priv->disable_tx_power_cal = 1; * nothing need to be done here anymore
* still keep for future use if needed
*/
} }
int iwlagn_hw_valid_rtc_data_addr(u32 addr) int iwlagn_hw_valid_rtc_data_addr(u32 addr)
@ -534,9 +549,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
void iwlagn_temperature(struct iwl_priv *priv) void iwlagn_temperature(struct iwl_priv *priv)
{ {
/* store temperature from correct statistics (in Celsius) */ /* store temperature from correct statistics (in Celsius) */
priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ? priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
priv->_agn.statistics_bt.general.common.temperature :
priv->_agn.statistics.general.common.temperature);
iwl_tt_handler(priv); iwl_tt_handler(priv);
} }

View File

@ -83,7 +83,6 @@ enum {
enum { enum {
IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,

View File

@ -29,6 +29,7 @@
#include "iwl-sta.h" #include "iwl-sta.h"
#include "iwl-core.h" #include "iwl-core.h"
#include "iwl-agn-calib.h" #include "iwl-agn-calib.h"
#include "iwl-helpers.h"
static int iwlagn_disable_bss(struct iwl_priv *priv, static int iwlagn_disable_bss(struct iwl_priv *priv,
struct iwl_rxon_context *ctx, struct iwl_rxon_context *ctx,
@ -600,6 +601,18 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
priv->timestamp = bss_conf->timestamp; priv->timestamp = bss_conf->timestamp;
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
} else { } else {
/*
* If we disassociate while there are pending
* frames, just wake up the queues and let the
* frames "escape" ... This shouldn't really
* be happening to start with, but we should
* not get stuck in this case either since it
* can happen if userspace gets confused.
*/
if (ctx->last_tx_rejected) {
ctx->last_tx_rejected = false;
iwl_wake_any_queue(priv, ctx);
}
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
} }
} }

View File

@ -428,6 +428,7 @@ void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
int iwlagn_alive_notify(struct iwl_priv *priv) int iwlagn_alive_notify(struct iwl_priv *priv)
{ {
const struct queue_to_fifo_ac *queue_to_fifo; const struct queue_to_fifo_ac *queue_to_fifo;
struct iwl_rxon_context *ctx;
u32 a; u32 a;
unsigned long flags; unsigned long flags;
int i, chan; int i, chan;
@ -501,6 +502,8 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
atomic_set(&priv->queue_stop_count[i], 0); atomic_set(&priv->queue_stop_count[i], 0);
for_each_context(priv, ctx)
ctx->last_tx_rejected = false;
/* reset to 0 to enable all the queue first */ /* reset to 0 to enable all the queue first */
priv->txq_ctx_active_msk = 0; priv->txq_ctx_active_msk = 0;

View File

@ -59,7 +59,6 @@
#include "iwl-sta.h" #include "iwl-sta.h"
#include "iwl-agn-calib.h" #include "iwl-agn-calib.h"
#include "iwl-agn.h" #include "iwl-agn.h"
#include "iwl-agn-led.h"
/****************************************************************************** /******************************************************************************
@ -254,6 +253,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
struct iwl_frame *frame; struct iwl_frame *frame;
unsigned int frame_size; unsigned int frame_size;
int rc; int rc;
struct iwl_host_cmd cmd = {
.id = REPLY_TX_BEACON,
.flags = CMD_SIZE_HUGE,
};
frame = iwl_get_free_frame(priv); frame = iwl_get_free_frame(priv);
if (!frame) { if (!frame) {
@ -269,8 +272,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
return -EINVAL; return -EINVAL;
} }
rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, cmd.len = frame_size;
&frame->u.cmd[0]); cmd.data = &frame->u.cmd[0];
rc = iwl_send_cmd_sync(priv, &cmd);
iwl_free_frame(priv, frame); iwl_free_frame(priv, frame);
@ -395,7 +400,9 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
return -EINVAL; return -EINVAL;
} }
BUG_ON(addr & ~DMA_BIT_MASK(36)); if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
return -EINVAL;
if (unlikely(addr & ~IWL_TX_DMA_MASK)) if (unlikely(addr & ~IWL_TX_DMA_MASK))
IWL_ERR(priv, "Unaligned address = %llx\n", IWL_ERR(priv, "Unaligned address = %llx\n",
(unsigned long long)addr); (unsigned long long)addr);
@ -719,7 +726,10 @@ static void iwl_rx_handle(struct iwl_priv *priv)
/* If an RXB doesn't have a Rx queue slot associated with it, /* If an RXB doesn't have a Rx queue slot associated with it,
* then a bug has been introduced in the queue refilling * then a bug has been introduced in the queue refilling
* routines -- catch it here */ * routines -- catch it here */
BUG_ON(rxb == NULL); if (WARN_ON(rxb == NULL)) {
i = (i + 1) & RX_QUEUE_MASK;
continue;
}
rxq->queue[i] = NULL; rxq->queue[i] = NULL;
@ -1481,7 +1491,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
le32_to_cpup((__le32 *)tlv_data); le32_to_cpup((__le32 *)tlv_data);
break; break;
default: default:
IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type);
break; break;
} }
} }
@ -1705,10 +1715,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
else else
priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS ||
(priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics))
priv->bt_statistics = true;
/* Copy images into buffers for card's bus-master reads ... */ /* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */ /* Runtime instructions (first block of data in file) */
@ -2626,17 +2632,8 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
} }
if (priv->start_calib) { if (priv->start_calib) {
if (iwl_bt_statistics(priv)) { iwl_chain_noise_calibration(priv);
iwl_chain_noise_calibration(priv, iwl_sensitivity_calibration(priv);
(void *)&priv->_agn.statistics_bt);
iwl_sensitivity_calibration(priv,
(void *)&priv->_agn.statistics_bt);
} else {
iwl_chain_noise_calibration(priv,
(void *)&priv->_agn.statistics);
iwl_sensitivity_calibration(priv,
(void *)&priv->_agn.statistics);
}
} }
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
@ -2828,9 +2825,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
if (!priv->cfg->base_params->broken_powersave) hw->flags |= IEEE80211_HW_SUPPORTS_PS |
hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (priv->cfg->sku & IWL_SKU_N) if (priv->cfg->sku & IWL_SKU_N)
hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
@ -3732,6 +3728,28 @@ static const u8 iwlagn_pan_ac_to_queue[] = {
7, 6, 5, 4, 7, 6, 5, 4,
}; };
/* This function both allocates and initializes hw and priv. */
static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
{
struct iwl_priv *priv;
/* mac80211 allocates memory for this device instance, including
* space for this driver's private structure */
struct ieee80211_hw *hw;
hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
if (hw == NULL) {
pr_err("%s: Can not allocate network device\n",
cfg->name);
goto out;
}
priv = hw->priv;
priv->hw = hw;
out:
return hw;
}
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
int err = 0, i; int err = 0, i;

View File

@ -173,8 +173,6 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv);
int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
void iwl_dump_csr(struct iwl_priv *priv);
int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
/* rx */ /* rx */
void iwlagn_rx_queue_restock(struct iwl_priv *priv); void iwlagn_rx_queue_restock(struct iwl_priv *priv);
@ -222,6 +220,7 @@ static inline u32 iwl_tx_status_to_mac80211(u32 status)
case TX_STATUS_DIRECT_DONE: case TX_STATUS_DIRECT_DONE:
return IEEE80211_TX_STAT_ACK; return IEEE80211_TX_STAT_ACK;
case TX_STATUS_FAIL_DEST_PS: case TX_STATUS_FAIL_DEST_PS:
case TX_STATUS_FAIL_PASSIVE_NO_RX:
return IEEE80211_TX_STAT_TX_FILTERED; return IEEE80211_TX_STAT_TX_FILTERED;
default: default:
return 0; return 0;

View File

@ -2535,53 +2535,6 @@ struct rate_histogram {
/* statistics command response */ /* statistics command response */
struct iwl39_statistics_rx_phy {
__le32 ina_cnt;
__le32 fina_cnt;
__le32 plcp_err;
__le32 crc32_err;
__le32 overrun_err;
__le32 early_overrun_err;
__le32 crc32_good;
__le32 false_alarm_cnt;
__le32 fina_sync_err_cnt;
__le32 sfd_timeout;
__le32 fina_timeout;
__le32 unresponded_rts;
__le32 rxe_frame_limit_overrun;
__le32 sent_ack_cnt;
__le32 sent_cts_cnt;
} __packed;
struct iwl39_statistics_rx_non_phy {
__le32 bogus_cts; /* CTS received when not expecting CTS */
__le32 bogus_ack; /* ACK received when not expecting ACK */
__le32 non_bssid_frames; /* number of frames with BSSID that
* doesn't belong to the STA BSSID */
__le32 filtered_frames; /* count frames that were dumped in the
* filtering process */
__le32 non_channel_beacons; /* beacons with our bss id but not on
* our serving channel */
} __packed;
struct iwl39_statistics_rx {
struct iwl39_statistics_rx_phy ofdm;
struct iwl39_statistics_rx_phy cck;
struct iwl39_statistics_rx_non_phy general;
} __packed;
struct iwl39_statistics_tx {
__le32 preamble_cnt;
__le32 rx_detected_cnt;
__le32 bt_prio_defer_cnt;
__le32 bt_prio_kill_cnt;
__le32 few_bytes_cnt;
__le32 cts_timeout;
__le32 ack_timeout;
__le32 expected_ack_cnt;
__le32 actual_ack_cnt;
} __packed;
struct statistics_dbg { struct statistics_dbg {
__le32 burst_check; __le32 burst_check;
__le32 burst_count; __le32 burst_count;
@ -2589,23 +2542,6 @@ struct statistics_dbg {
__le32 reserved[3]; __le32 reserved[3];
} __packed; } __packed;
struct iwl39_statistics_div {
__le32 tx_on_a;
__le32 tx_on_b;
__le32 exec_time;
__le32 probe_time;
} __packed;
struct iwl39_statistics_general {
__le32 temperature;
struct statistics_dbg dbg;
__le32 sleep_time;
__le32 slots_out;
__le32 slots_idle;
__le32 ttl_timestamp;
struct iwl39_statistics_div div;
} __packed;
struct statistics_rx_phy { struct statistics_rx_phy {
__le32 ina_cnt; __le32 ina_cnt;
__le32 fina_cnt; __le32 fina_cnt;

View File

@ -67,30 +67,6 @@ u32 iwl_debug_level;
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* This function both allocates and initializes hw and priv. */
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
{
struct iwl_priv *priv;
/* mac80211 allocates memory for this device instance, including
* space for this driver's private structure */
struct ieee80211_hw *hw;
hw = ieee80211_alloc_hw(sizeof(struct iwl_priv),
cfg->ops->ieee80211_ops);
if (hw == NULL) {
pr_err("%s: Can not allocate network device\n",
cfg->name);
goto out;
}
priv = hw->priv;
priv->hw = hw;
out:
return hw;
}
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
@ -965,12 +941,10 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
IWL_ERR(priv, "Loaded firmware version: %s\n", IWL_ERR(priv, "Loaded firmware version: %s\n",
priv->hw->wiphy->fw_version); priv->hw->wiphy->fw_version);
priv->cfg->ops->lib->dump_nic_error_log(priv); iwl_dump_nic_error_log(priv);
if (priv->cfg->ops->lib->dump_csr) iwl_dump_csr(priv);
priv->cfg->ops->lib->dump_csr(priv); iwl_dump_fh(priv, NULL, false);
if (priv->cfg->ops->lib->dump_fh) iwl_dump_nic_event_log(priv, false, NULL, false);
priv->cfg->ops->lib->dump_fh(priv, NULL, false);
priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
iwl_print_rx_config_cmd(priv, iwl_print_rx_config_cmd(priv,
@ -1051,7 +1025,6 @@ int iwl_apm_init(struct iwl_priv *priv)
/* /*
* Enable HAP INTA (interrupt from management bus) to * Enable HAP INTA (interrupt from management bus) to
* wake device's PCI Express link L1a -> L0s * wake device's PCI Express link L1a -> L0s
* NOTE: This is no-op for 3945 (non-existent bit)
*/ */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
@ -1064,20 +1037,18 @@ int iwl_apm_init(struct iwl_priv *priv)
* If not (unlikely), enable L0S, so there is at least some * If not (unlikely), enable L0S, so there is at least some
* power savings, even without L1. * power savings, even without L1.
*/ */
if (priv->cfg->base_params->set_l0s) { lctl = iwl_pcie_link_ctl(priv);
lctl = iwl_pcie_link_ctl(priv); if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) {
PCI_CFG_LINK_CTRL_VAL_L1_EN) { /* L1-ASPM enabled; disable(!) L0S */
/* L1-ASPM enabled; disable(!) L0S */ iwl_set_bit(priv, CSR_GIO_REG,
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
CSR_GIO_REG_VAL_L0S_ENABLED); IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); } else {
} else { /* L1-ASPM disabled; enable(!) L0S */
/* L1-ASPM disabled; enable(!) L0S */ iwl_clear_bit(priv, CSR_GIO_REG,
iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
CSR_GIO_REG_VAL_L0S_ENABLED); IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
}
} }
/* Configure analog phase-lock-loop before activating to D0A */ /* Configure analog phase-lock-loop before activating to D0A */
@ -1777,6 +1748,15 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
if (!ctx->vif || !iwl_is_ready_rf(priv)) {
/*
* Huh? But wait ... this can maybe happen when
* we're in the middle of a firmware restart!
*/
err = -EBUSY;
goto out;
}
interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
if (!(interface_modes & BIT(newtype))) { if (!(interface_modes & BIT(newtype))) {
@ -1804,6 +1784,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* success */ /* success */
iwl_teardown_interface(priv, vif, true); iwl_teardown_interface(priv, vif, true);
vif->type = newtype; vif->type = newtype;
vif->p2p = newp2p;
err = iwl_setup_interface(priv, ctx); err = iwl_setup_interface(priv, ctx);
WARN_ON(err); WARN_ON(err);
/* /*

View File

@ -139,12 +139,6 @@ struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv); void (*temperature)(struct iwl_priv *priv);
}; };
struct iwl_tt_ops {
bool (*lower_power_detection)(struct iwl_priv *priv);
u8 (*tt_power_mode)(struct iwl_priv *priv);
bool (*ct_kill_check)(struct iwl_priv *priv);
};
struct iwl_lib_ops { struct iwl_lib_ops {
/* set hw dependent parameters */ /* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv); int (*set_hw_params)(struct iwl_priv *priv);
@ -171,12 +165,6 @@ struct iwl_lib_ops {
void (*cancel_deferred_work)(struct iwl_priv *priv); void (*cancel_deferred_work)(struct iwl_priv *priv);
/* check validity of rtc data address */ /* check validity of rtc data address */
int (*is_valid_rtc_data_addr)(u32 addr); int (*is_valid_rtc_data_addr)(u32 addr);
int (*dump_nic_event_log)(struct iwl_priv *priv,
bool full_log, char **buf, bool display);
void (*dump_nic_error_log)(struct iwl_priv *priv);
void (*dump_csr)(struct iwl_priv *priv);
int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
int (*set_channel_switch)(struct iwl_priv *priv, int (*set_channel_switch)(struct iwl_priv *priv,
struct ieee80211_channel_switch *ch_switch); struct ieee80211_channel_switch *ch_switch);
/* power management */ /* power management */
@ -196,13 +184,6 @@ struct iwl_lib_ops {
void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
struct iwl_debugfs_ops debugfs_ops; struct iwl_debugfs_ops debugfs_ops;
/* thermal throttling */
struct iwl_tt_ops tt_ops;
};
struct iwl_led_ops {
int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
}; };
/* NIC specific ops */ /* NIC specific ops */
@ -210,23 +191,11 @@ struct iwl_nic_ops {
void (*additional_nic_config)(struct iwl_priv *priv); void (*additional_nic_config)(struct iwl_priv *priv);
}; };
struct iwl_legacy_ops {
void (*post_associate)(struct iwl_priv *priv);
void (*config_ap)(struct iwl_priv *priv);
/* station management */
int (*update_bcast_stations)(struct iwl_priv *priv);
int (*manage_ibss_station)(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add);
};
struct iwl_ops { struct iwl_ops {
const struct iwl_lib_ops *lib; const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils; const struct iwl_hcmd_utils_ops *utils;
const struct iwl_led_ops *led;
const struct iwl_nic_ops *nic; const struct iwl_nic_ops *nic;
const struct iwl_legacy_ops *legacy;
const struct ieee80211_ops *ieee80211_ops;
}; };
struct iwl_mod_params { struct iwl_mod_params {
@ -256,13 +225,6 @@ struct iwl_mod_params {
* @wd_timeout: TX queues watchdog timeout * @wd_timeout: TX queues watchdog timeout
* @temperature_kelvin: temperature report by uCode in kelvin * @temperature_kelvin: temperature report by uCode in kelvin
* @max_event_log_size: size of event log buffer size for ucode event logging * @max_event_log_size: size of event log buffer size for ucode event logging
* @tx_power_by_driver: tx power calibration performed by driver
* instead of uCode
* @ucode_tracing: support ucode continuous tracing
* @sensitivity_calib_by_driver: driver has the capability to perform
* sensitivity calibration operation
* @chain_noise_calib_by_driver: driver has the capability to perform
* chain noise calibration operation
* @shadow_reg_enable: HW shadhow register bit * @shadow_reg_enable: HW shadhow register bit
*/ */
struct iwl_base_params { struct iwl_base_params {
@ -271,12 +233,10 @@ struct iwl_base_params {
int num_of_ampdu_queues;/* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */
/* for iwl_apm_init() */ /* for iwl_apm_init() */
u32 pll_cfg_val; u32 pll_cfg_val;
bool set_l0s;
const u16 max_ll_items; const u16 max_ll_items;
const bool shadow_ram_support; const bool shadow_ram_support;
u16 led_compensation; u16 led_compensation;
const bool broken_powersave;
int chain_noise_num_beacons; int chain_noise_num_beacons;
bool adv_thermal_throttle; bool adv_thermal_throttle;
bool support_ct_kill_exit; bool support_ct_kill_exit;
@ -286,17 +246,12 @@ struct iwl_base_params {
unsigned int wd_timeout; unsigned int wd_timeout;
bool temperature_kelvin; bool temperature_kelvin;
u32 max_event_log_size; u32 max_event_log_size;
const bool tx_power_by_driver;
const bool ucode_tracing;
const bool sensitivity_calib_by_driver;
const bool chain_noise_calib_by_driver;
const bool shadow_reg_enable; const bool shadow_reg_enable;
}; };
/* /*
* @advanced_bt_coexist: support advanced bt coexist * @advanced_bt_coexist: support advanced bt coexist
* @bt_init_traffic_load: specify initial bt traffic load * @bt_init_traffic_load: specify initial bt traffic load
* @bt_prio_boost: default bt priority boost value * @bt_prio_boost: default bt priority boost value
* @bt_statistics: use BT version of statistics notification
* @agg_time_limit: maximum number of uSec in aggregation * @agg_time_limit: maximum number of uSec in aggregation
* @ampdu_factor: Maximum A-MPDU length factor * @ampdu_factor: Maximum A-MPDU length factor
* @ampdu_density: Minimum A-MPDU spacing * @ampdu_density: Minimum A-MPDU spacing
@ -306,7 +261,6 @@ struct iwl_bt_params {
bool advanced_bt_coexist; bool advanced_bt_coexist;
u8 bt_init_traffic_load; u8 bt_init_traffic_load;
u8 bt_prio_boost; u8 bt_prio_boost;
const bool bt_statistics;
u16 agg_time_limit; u16 agg_time_limit;
u8 ampdu_factor; u8 ampdu_factor;
u8 ampdu_density; u8 ampdu_density;
@ -337,6 +291,7 @@ struct iwl_ht_params {
* @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @rx_with_siso_diversity: 1x1 device with rx antenna diversity
* @internal_wimax_coex: internal wifi/wimax combo device * @internal_wimax_coex: internal wifi/wimax combo device
* @iq_invert: I/Q inversion * @iq_invert: I/Q inversion
* @disable_otp_refresh: disable OTP refresh current limit
* *
* We enable the driver to be backward compatible wrt API version. The * We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the * driver specifies which APIs it supports (with @ucode_api_max being the
@ -387,13 +342,13 @@ struct iwl_cfg {
const bool rx_with_siso_diversity; const bool rx_with_siso_diversity;
const bool internal_wimax_coex; const bool internal_wimax_coex;
const bool iq_invert; const bool iq_invert;
const bool disable_otp_refresh;
}; };
/*************************** /***************************
* L i b * * L i b *
***************************/ ***************************/
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params); const struct ieee80211_tx_queue_params *params);
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
@ -598,6 +553,8 @@ extern const struct dev_pm_ops iwl_pm_ops;
void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_error_log(struct iwl_priv *priv);
int iwl_dump_nic_event_log(struct iwl_priv *priv, int iwl_dump_nic_event_log(struct iwl_priv *priv,
bool full_log, char **buf, bool display); bool full_log, char **buf, bool display);
void iwl_dump_csr(struct iwl_priv *priv);
int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
void iwl_print_rx_config_cmd(struct iwl_priv *priv, void iwl_print_rx_config_cmd(struct iwl_priv *priv,
struct iwl_rxon_context *ctx); struct iwl_rxon_context *ctx);
@ -709,11 +666,6 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
priv->cfg->bt_params->advanced_bt_coexist; priv->cfg->bt_params->advanced_bt_coexist;
} }
static inline bool iwl_bt_statistics(struct iwl_priv *priv)
{
return priv->bt_statistics;
}
extern bool bt_coex_active; extern bool bt_coex_active;
extern bool bt_siso_mode; extern bool bt_siso_mode;

View File

@ -437,8 +437,7 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file,
int pos = 0; int pos = 0;
ssize_t ret = -ENOMEM; ssize_t ret = -ENOMEM;
ret = pos = priv->cfg->ops->lib->dump_nic_event_log( ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
priv, true, &buf, true);
if (buf) { if (buf) {
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf); kfree(buf);
@ -462,8 +461,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
if (sscanf(buf, "%d", &event_log_flag) != 1) if (sscanf(buf, "%d", &event_log_flag) != 1)
return -EFAULT; return -EFAULT;
if (event_log_flag == 1) if (event_log_flag == 1)
priv->cfg->ops->lib->dump_nic_event_log(priv, true, iwl_dump_nic_event_log(priv, true, NULL, false);
NULL, false);
return count; return count;
} }
@ -1268,8 +1266,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
if (sscanf(buf, "%d", &csr) != 1) if (sscanf(buf, "%d", &csr) != 1)
return -EFAULT; return -EFAULT;
if (priv->cfg->ops->lib->dump_csr) iwl_dump_csr(priv);
priv->cfg->ops->lib->dump_csr(priv);
return count; return count;
} }
@ -1359,13 +1356,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
int pos = 0; int pos = 0;
ssize_t ret = -EFAULT; ssize_t ret = -EFAULT;
if (priv->cfg->ops->lib->dump_fh) { ret = pos = iwl_dump_fh(priv, &buf, true);
ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); if (buf) {
if (buf) { ret = simple_read_from_buffer(user_buf,
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
count, ppos, buf, pos); kfree(buf);
kfree(buf);
}
} }
return ret; return ret;
@ -1728,11 +1723,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
if (!priv->cfg->base_params->broken_powersave) { DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(sleep_level_override, dir_data, DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
}
DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
@ -1755,29 +1747,20 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
if (priv->cfg->base_params->sensitivity_calib_by_driver) DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
if (priv->cfg->base_params->chain_noise_calib_by_driver) DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
if (priv->cfg->base_params->ucode_tracing)
DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
if (iwl_bt_statistics(priv))
DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
if (iwl_advanced_bt_coexist(priv)) if (iwl_advanced_bt_coexist(priv))
DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
if (priv->cfg->base_params->sensitivity_calib_by_driver) DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal);
&priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
if (priv->cfg->base_params->chain_noise_calib_by_driver) &priv->disable_chain_noise_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
&priv->disable_chain_noise_cal);
if (priv->cfg->base_params->tx_power_by_driver)
DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
&priv->disable_tx_power_cal);
return 0; return 0;
err: err:

View File

@ -543,13 +543,12 @@ enum iwl_ucode_tlv_type {
* enum iwl_ucode_tlv_flag - ucode API flags * enum iwl_ucode_tlv_flag - ucode API flags
* @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
* was a separate TLV but moved here to save space. * was a separate TLV but moved here to save space.
* @IWL_UCODE_TLV_FLAGS_BTSTATS: This uCode image uses BT statistics, which * @IWL_UCODE_TLV_FLAGS_RESERVED_1: reserved
* may be true even if the device doesn't have BT.
* @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
*/ */
enum iwl_ucode_tlv_flag { enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0), IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
IWL_UCODE_TLV_FLAGS_BTSTATS = BIT(1), IWL_UCODE_TLV_FLAGS_RESERVED_1 = BIT(1),
IWL_UCODE_TLV_FLAGS_MFP = BIT(2), IWL_UCODE_TLV_FLAGS_MFP = BIT(2),
}; };
@ -1170,6 +1169,8 @@ struct iwl_rxon_context {
bool enabled, is_40mhz; bool enabled, is_40mhz;
u8 extension_chan_offset; u8 extension_chan_offset;
} ht; } ht;
bool last_tx_rejected;
}; };
enum iwl_scan_type { enum iwl_scan_type {
@ -1354,6 +1355,31 @@ struct iwl_priv {
/* Last Rx'd beacon timestamp */ /* Last Rx'd beacon timestamp */
u64 timestamp; u64 timestamp;
struct {
__le32 flag;
struct statistics_general_common common;
struct statistics_rx_non_phy rx_non_phy;
struct statistics_rx_phy rx_ofdm;
struct statistics_rx_ht_phy rx_ofdm_ht;
struct statistics_rx_phy rx_cck;
struct statistics_tx tx;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct statistics_bt_activity bt_activity;
__le32 num_bt_kills, accum_num_bt_kills;
#endif
} statistics;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct {
struct statistics_general_common common;
struct statistics_rx_non_phy rx_non_phy;
struct statistics_rx_phy rx_ofdm;
struct statistics_rx_ht_phy rx_ofdm_ht;
struct statistics_rx_phy rx_cck;
struct statistics_tx tx;
struct statistics_bt_activity bt_activity;
} accum_stats, delta_stats, max_delta_stats;
#endif
struct { struct {
/* INT ICT Table */ /* INT ICT Table */
__le32 *ict_tbl; __le32 *ict_tbl;
@ -1385,19 +1411,9 @@ struct iwl_priv {
u8 phy_calib_chain_noise_reset_cmd; u8 phy_calib_chain_noise_reset_cmd;
u8 phy_calib_chain_noise_gain_cmd; u8 phy_calib_chain_noise_gain_cmd;
struct iwl_notif_statistics statistics;
struct iwl_bt_notif_statistics statistics_bt;
/* counts reply_tx error */ /* counts reply_tx error */
struct reply_tx_error_statistics reply_tx_stats; struct reply_tx_error_statistics reply_tx_stats;
struct reply_agg_tx_error_statistics reply_agg_tx_stats; struct reply_agg_tx_error_statistics reply_agg_tx_stats;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_notif_statistics accum_statistics;
struct iwl_notif_statistics delta_statistics;
struct iwl_notif_statistics max_delta;
struct iwl_bt_notif_statistics accum_statistics_bt;
struct iwl_bt_notif_statistics delta_statistics_bt;
struct iwl_bt_notif_statistics max_delta_bt;
#endif
/* notification wait support */ /* notification wait support */
struct list_head notif_waits; struct list_head notif_waits;
spinlock_t notif_wait_lock; spinlock_t notif_wait_lock;
@ -1422,7 +1438,6 @@ struct iwl_priv {
bool bt_ch_announce; bool bt_ch_announce;
bool bt_full_concurrent; bool bt_full_concurrent;
bool bt_ant_couple_ok; bool bt_ant_couple_ok;
bool bt_statistics;
__le32 kill_ack_mask; __le32 kill_ack_mask;
__le32 kill_cts_mask; __le32 kill_cts_mask;
__le16 bt_valid; __le16 bt_valid;
@ -1487,7 +1502,6 @@ struct iwl_priv {
struct work_struct txpower_work; struct work_struct txpower_work;
u32 disable_sens_cal; u32 disable_sens_cal;
u32 disable_chain_noise_cal; u32 disable_chain_noise_cal;
u32 disable_tx_power_cal;
struct work_struct run_time_calib_work; struct work_struct run_time_calib_work;
struct timer_list statistics_periodic; struct timer_list statistics_periodic;
struct timer_list ucode_trace; struct timer_list ucode_trace;

View File

@ -215,12 +215,6 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
return nvm_type; return nvm_type;
} }
const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
{
BUG_ON(offset >= priv->cfg->base_params->eeprom_size);
return &priv->eeprom[offset];
}
static int iwl_init_otp_access(struct iwl_priv *priv) static int iwl_init_otp_access(struct iwl_priv *priv)
{ {
int ret; int ret;

View File

@ -309,7 +309,6 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv);
const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
int iwl_init_channel_map(struct iwl_priv *priv); int iwl_init_channel_map(struct iwl_priv *priv);
void iwl_free_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv);
const struct iwl_channel_info *iwl_get_channel_info( const struct iwl_channel_info *iwl_get_channel_info(

View File

@ -77,14 +77,14 @@
/** /**
* Keep-Warm (KW) buffer base address. * Keep-Warm (KW) buffer base address.
* *
* Driver must allocate a 4KByte buffer that is used by 4965 for keeping the * Driver must allocate a 4KByte buffer that is for keeping the
* host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
* DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host * DRAM access when doing Txing or Rxing. The dummy accesses prevent host
* from going into a power-savings mode that would cause higher DRAM latency, * from going into a power-savings mode that would cause higher DRAM latency,
* and possible data over/under-runs, before all Tx/Rx is complete. * and possible data over/under-runs, before all Tx/Rx is complete.
* *
* Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
* of the buffer, which must be 4K aligned. Once this is set up, the 4965 * of the buffer, which must be 4K aligned. Once this is set up, the device
* automatically invokes keep-warm accesses when normal accesses might not * automatically invokes keep-warm accesses when normal accesses might not
* be sufficient to maintain fast DRAM response. * be sufficient to maintain fast DRAM response.
* *
@ -97,7 +97,7 @@
/** /**
* TFD Circular Buffers Base (CBBC) addresses * TFD Circular Buffers Base (CBBC) addresses
* *
* 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident
* circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
* (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04
* bytes from one another. Each TFD circular buffer in DRAM must be 256-byte * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte
@ -116,16 +116,16 @@
/** /**
* Rx SRAM Control and Status Registers (RSCSR) * Rx SRAM Control and Status Registers (RSCSR)
* *
* These registers provide handshake between driver and 4965 for the Rx queue * These registers provide handshake between driver and device for the Rx queue
* (this queue handles *all* command responses, notifications, Rx data, etc. * (this queue handles *all* command responses, notifications, Rx data, etc.
* sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx * sent from uCode to host driver). Unlike Tx, there is only one Rx
* queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can
* concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
* Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
* mapping between RBDs and RBs. * mapping between RBDs and RBs.
* *
* Driver must allocate host DRAM memory for the following, and set the * Driver must allocate host DRAM memory for the following, and set the
* physical address of each into 4965 registers: * physical address of each into device registers:
* *
* 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
* entries (although any power of 2, up to 4096, is selectable by driver). * entries (although any power of 2, up to 4096, is selectable by driver).
@ -140,20 +140,20 @@
* Driver sets physical address [35:8] of base of RBD circular buffer * Driver sets physical address [35:8] of base of RBD circular buffer
* into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
* *
* 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers
* (RBs) have been filled, via a "write pointer", actually the index of * (RBs) have been filled, via a "write pointer", actually the index of
* the RB's corresponding RBD within the circular buffer. Driver sets * the RB's corresponding RBD within the circular buffer. Driver sets
* physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
* *
* Bit fields in lower dword of Rx status buffer (upper dword not used * Bit fields in lower dword of Rx status buffer (upper dword not used
* by driver; see struct iwl4965_shared, val0): * by driver:
* 31-12: Not used by driver * 31-12: Not used by driver
* 11- 0: Index of last filled Rx buffer descriptor * 11- 0: Index of last filled Rx buffer descriptor
* (4965 writes, driver reads this value) * (device writes, driver reads this value)
* *
* As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must * As the driver prepares Receive Buffers (RBs) for device to fill, driver must
* enter pointers to these RBs into contiguous RBD circular buffer entries, * enter pointers to these RBs into contiguous RBD circular buffer entries,
* and update the 4965's "write" index register, * and update the device's "write" index register,
* FH_RSCSR_CHNL0_RBDCB_WPTR_REG. * FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
* *
* This "write" index corresponds to the *next* RBD that the driver will make * This "write" index corresponds to the *next* RBD that the driver will make
@ -162,12 +162,12 @@
* RBs), should be 8 after preparing the first 8 RBs (for example), and must * RBs), should be 8 after preparing the first 8 RBs (for example), and must
* wrap back to 0 at the end of the circular buffer (but don't wrap before * wrap back to 0 at the end of the circular buffer (but don't wrap before
* "read" index has advanced past 1! See below). * "read" index has advanced past 1! See below).
* NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
* *
* As the 4965 fills RBs (referenced from contiguous RBDs within the circular * As the device fills RBs (referenced from contiguous RBDs within the circular
* buffer), it updates the Rx status buffer in host DRAM, 2) described above, * buffer), it updates the Rx status buffer in host DRAM, 2) described above,
* to tell the driver the index of the latest filled RBD. The driver must * to tell the driver the index of the latest filled RBD. The driver must
* read this "read" index from DRAM after receiving an Rx interrupt from 4965. * read this "read" index from DRAM after receiving an Rx interrupt from device
* *
* The driver must also internally keep track of a third index, which is the * The driver must also internally keep track of a third index, which is the
* next RBD to process. When receiving an Rx interrupt, driver should process * next RBD to process. When receiving an Rx interrupt, driver should process
@ -176,7 +176,7 @@
* driver may process the RB pointed to by RBD 0. Depending on volume of * driver may process the RB pointed to by RBD 0. Depending on volume of
* traffic, there may be many RBs to process. * traffic, there may be many RBs to process.
* *
* If read index == write index, 4965 thinks there is no room to put new data. * If read index == write index, device thinks there is no room to put new data.
* Due to this, the maximum number of filled RBs is 255, instead of 256. To * Due to this, the maximum number of filled RBs is 255, instead of 256. To
* be safe, make sure that there is a gap of at least 2 RBDs between "write" * be safe, make sure that there is a gap of at least 2 RBDs between "write"
* and "read" indexes; that is, make sure that there are no more than 254 * and "read" indexes; that is, make sure that there are no more than 254
@ -303,7 +303,7 @@
/** /**
* Transmit DMA Channel Control/Status Registers (TCSR) * Transmit DMA Channel Control/Status Registers (TCSR)
* *
* 4965 has one configuration register for each of 8 Tx DMA/FIFO channels * Device has one configuration register for each of 8 Tx DMA/FIFO channels
* supported in hardware (don't confuse these with the 16 Tx queues in DRAM, * supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
* which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
* *
@ -326,7 +326,6 @@
#define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60)
/* Find Control/Status reg for given Tx DMA/FIFO channel */ /* Find Control/Status reg for given Tx DMA/FIFO channel */
#define FH49_TCSR_CHNL_NUM (7)
#define FH50_TCSR_CHNL_NUM (8) #define FH50_TCSR_CHNL_NUM (8)
/* TCSR: tx_config register values */ /* TCSR: tx_config register values */
@ -424,7 +423,6 @@
#define RX_LOW_WATERMARK 8 #define RX_LOW_WATERMARK 8
/* Size of one Rx buffer in host DRAM */ /* Size of one Rx buffer in host DRAM */
#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */
#define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_4K (4 * 1024)
#define IWL_RX_BUF_SIZE_8K (8 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024)
@ -443,7 +441,7 @@ struct iwl_rb_status {
__le16 closed_fr_num; __le16 closed_fr_num;
__le16 finished_rb_num; __le16 finished_rb_num;
__le16 finished_fr_nam; __le16 finished_fr_nam;
__le32 __unused; /* 3945 only */ __le32 __unused;
} __packed; } __packed;

View File

@ -143,10 +143,12 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{ {
int ret; int ret;
BUG_ON(!(cmd->flags & CMD_ASYNC)); if (WARN_ON(!(cmd->flags & CMD_ASYNC)))
return -EINVAL;
/* An asynchronous command can not expect an SKB to be set. */ /* An asynchronous command can not expect an SKB to be set. */
BUG_ON(cmd->flags & CMD_WANT_SKB); if (WARN_ON(cmd->flags & CMD_WANT_SKB))
return -EINVAL;
/* Assign a generic callback if one is not provided */ /* Assign a generic callback if one is not provided */
if (!cmd->callback) if (!cmd->callback)
@ -169,10 +171,12 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int cmd_idx; int cmd_idx;
int ret; int ret;
lockdep_assert_held(&priv->mutex); if (WARN_ON(cmd->flags & CMD_ASYNC))
return -EINVAL;
/* A synchronous command can not have a callback set. */ /* A synchronous command can not have a callback set. */
BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback); if (WARN_ON(cmd->callback))
return -EINVAL;
IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
get_cmd_string(cmd->id)); get_cmd_string(cmd->id));

View File

@ -131,6 +131,19 @@ static inline void iwl_stop_queue(struct iwl_priv *priv,
ieee80211_stop_queue(priv->hw, ac); ieee80211_stop_queue(priv->hw, ac);
} }
static inline void iwl_wake_any_queue(struct iwl_priv *priv,
struct iwl_rxon_context *ctx)
{
u8 ac;
for (ac = 0; ac < AC_NUM; ac++) {
IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n",
ac, (atomic_read(&priv->queue_stop_count[ac]) > 0)
? "stopped" : "awake");
iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]);
}
}
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue

View File

@ -61,10 +61,16 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
{ .throughput = 300 * 1024 - 1, .blink_time = 50 }, { .throughput = 300 * 1024 - 1, .blink_time = 50 },
}; };
/* Set led register off */
void iwlagn_led_enable(struct iwl_priv *priv)
{
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
}
/* /*
* Adjust led blink rate to compensate on a MAC Clock difference on every HW * Adjust led blink rate to compensate on a MAC Clock difference on every HW
* Led blink rate analysis showed an average deviation of 0% on 3945, * Led blink rate analysis showed an average deviation of 20% on 5000 series
* 5% on 4965 HW and 20% on 5000 series and up. * and up.
* Need to compensate on the led on/off time per HW according to the deviation * Need to compensate on the led on/off time per HW according to the deviation
* to achieve the desired led frequency * to achieve the desired led frequency
* The calculation is: (100-averageDeviation)/100 * blinkTime * The calculation is: (100-averageDeviation)/100 * blinkTime
@ -84,6 +90,24 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
return (u8)((time * compensation) >> 6); return (u8)((time * compensation) >> 6);
} }
static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
{
struct iwl_host_cmd cmd = {
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
.flags = CMD_ASYNC,
.callback = NULL,
};
u32 reg;
reg = iwl_read32(priv, CSR_LED_REG);
if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
return iwl_send_cmd(priv, &cmd);
}
/* Set led pattern command */ /* Set led pattern command */
static int iwl_led_cmd(struct iwl_priv *priv, static int iwl_led_cmd(struct iwl_priv *priv,
unsigned long on, unsigned long on,
@ -108,7 +132,7 @@ static int iwl_led_cmd(struct iwl_priv *priv,
led_cmd.off = iwl_blink_compensation(priv, off, led_cmd.off = iwl_blink_compensation(priv, off,
priv->cfg->base_params->led_compensation); priv->cfg->base_params->led_compensation);
ret = priv->cfg->ops->led->cmd(priv, &led_cmd); ret = iwl_send_led_cmd(priv, &led_cmd);
if (!ret) { if (!ret) {
priv->blink_on = on; priv->blink_on = on;
priv->blink_off = off; priv->blink_off = off;

View File

@ -50,6 +50,7 @@ enum iwl_led_mode {
IWL_LED_BLINK, IWL_LED_BLINK,
}; };
void iwlagn_led_enable(struct iwl_priv *priv);
void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_init(struct iwl_priv *priv);
void iwl_leds_exit(struct iwl_priv *priv); void iwl_leds_exit(struct iwl_priv *priv);

View File

@ -188,9 +188,10 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
table = range_0; table = range_0;
} }
BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
memset(cmd, 0, sizeof(*cmd));
*cmd = table[lvl].cmd; else
*cmd = table[lvl].cmd;
if (period == 0) { if (period == 0) {
skip = 0; skip = 0;
@ -354,16 +355,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
dtimper = priv->hw->conf.ps_dtim_period ?: 1; dtimper = priv->hw->conf.ps_dtim_period ?: 1;
if (priv->cfg->base_params->broken_powersave) if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && else if (iwl_tt_is_low_power_state(priv)) {
priv->cfg->ops->lib->tt_ops.tt_power_mode &&
priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
/* in thermal throttling low power state */ /* in thermal throttling low power state */
iwl_static_sleep_cmd(priv, cmd, iwl_static_sleep_cmd(priv, cmd,
priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper); iwl_tt_current_power_mode(priv), dtimper);
} else if (!enabled) } else if (!enabled)
iwl_power_sleep_cam_cmd(priv, cmd); iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->power_data.debug_sleep_level_override >= 0) else if (priv->power_data.debug_sleep_level_override >= 0)

View File

@ -107,17 +107,7 @@
* device. A queue maps to only one (selectable by driver) Tx DMA channel, * device. A queue maps to only one (selectable by driver) Tx DMA channel,
* but one DMA channel may take input from several queues. * but one DMA channel may take input from several queues.
* *
* Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows * Tx DMA FIFOs have dedicated purposes.
* (cf. default_queue_to_tx_fifo in iwl-4965.c):
*
* 0 -- EDCA BK (background) frames, lowest priority
* 1 -- EDCA BE (best effort) frames, normal priority
* 2 -- EDCA VI (video) frames, higher priority
* 3 -- EDCA VO (voice) and management frames, highest priority
* 4 -- Commands (e.g. RXON, etc.)
* 5 -- unused (HCCA)
* 6 -- unused (HCCA)
* 7 -- not used by driver (device-internal only)
* *
* For 5000 series and up, they are used differently * For 5000 series and up, they are used differently
* (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c):
@ -151,7 +141,7 @@
* Tx completion may end up being out-of-order). * Tx completion may end up being out-of-order).
* *
* The driver must maintain the queue's Byte Count table in host DRAM * The driver must maintain the queue's Byte Count table in host DRAM
* (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. * for this mode.
* This mode does not support fragmentation. * This mode does not support fragmentation.
* *
* 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
@ -164,7 +154,7 @@
* *
* Driver controls scheduler operation via 3 means: * Driver controls scheduler operation via 3 means:
* 1) Scheduler registers * 1) Scheduler registers
* 2) Shared scheduler data base in internal 4956 SRAM * 2) Shared scheduler data base in internal SRAM
* 3) Shared data in host DRAM * 3) Shared data in host DRAM
* *
* Initialization: * Initialization:

View File

@ -390,21 +390,16 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
* the BA_TIMEOUT_MAX, reload firmware and bring system back to normal * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
* operation state. * operation state.
*/ */
static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt) static bool iwl_good_ack_health(struct iwl_priv *priv,
struct statistics_tx *cur)
{ {
int actual_delta, expected_delta, ba_timeout_delta; int actual_delta, expected_delta, ba_timeout_delta;
struct statistics_tx *cur, *old; struct statistics_tx *old;
if (priv->_agn.agg_tids_count) if (priv->_agn.agg_tids_count)
return true; return true;
if (iwl_bt_statistics(priv)) { old = &priv->statistics.tx;
cur = &pkt->u.stats_bt.tx;
old = &priv->_agn.statistics_bt.tx;
} else {
cur = &pkt->u.stats.tx;
old = &priv->_agn.statistics.tx;
}
actual_delta = le32_to_cpu(cur->actual_ack_cnt) - actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
le32_to_cpu(old->actual_ack_cnt); le32_to_cpu(old->actual_ack_cnt);
@ -430,10 +425,10 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt
* DEBUG is not, these will just compile out. * DEBUG is not, these will just compile out.
*/ */
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
priv->_agn.delta_statistics.tx.rx_detected_cnt); priv->delta_stats.tx.rx_detected_cnt);
IWL_DEBUG_RADIO(priv, IWL_DEBUG_RADIO(priv,
"ack_or_ba_timeout_collision delta %d\n", "ack_or_ba_timeout_collision delta %d\n",
priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision); priv->delta_stats.tx.ack_or_ba_timeout_collision);
#endif #endif
if (ba_timeout_delta >= BA_TIMEOUT_MAX) if (ba_timeout_delta >= BA_TIMEOUT_MAX)
@ -450,7 +445,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt
* to improve the throughput. * to improve the throughput.
*/ */
static bool iwl_good_plcp_health(struct iwl_priv *priv, static bool iwl_good_plcp_health(struct iwl_priv *priv,
struct iwl_rx_packet *pkt, unsigned int msecs) struct statistics_rx_phy *cur_ofdm,
struct statistics_rx_ht_phy *cur_ofdm_ht,
unsigned int msecs)
{ {
int delta; int delta;
int threshold = priv->cfg->base_params->plcp_delta_threshold; int threshold = priv->cfg->base_params->plcp_delta_threshold;
@ -460,29 +457,12 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
return true; return true;
} }
if (iwl_bt_statistics(priv)) { delta = le32_to_cpu(cur_ofdm->plcp_err) -
struct statistics_rx_bt *cur, *old; le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
le32_to_cpu(cur_ofdm_ht->plcp_err) -
le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
cur = &pkt->u.stats_bt.rx; /* Can be negative if firmware reset statistics */
old = &priv->_agn.statistics_bt.rx;
delta = le32_to_cpu(cur->ofdm.plcp_err) -
le32_to_cpu(old->ofdm.plcp_err) +
le32_to_cpu(cur->ofdm_ht.plcp_err) -
le32_to_cpu(old->ofdm_ht.plcp_err);
} else {
struct statistics_rx *cur, *old;
cur = &pkt->u.stats.rx;
old = &priv->_agn.statistics.rx;
delta = le32_to_cpu(cur->ofdm.plcp_err) -
le32_to_cpu(old->ofdm.plcp_err) +
le32_to_cpu(cur->ofdm_ht.plcp_err) -
le32_to_cpu(old->ofdm_ht.plcp_err);
}
/* Can be negative if firmware reseted statistics */
if (delta <= 0) if (delta <= 0)
return true; return true;
@ -497,44 +477,36 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
} }
static void iwl_recover_from_statistics(struct iwl_priv *priv, static void iwl_recover_from_statistics(struct iwl_priv *priv,
struct iwl_rx_packet *pkt) struct statistics_rx_phy *cur_ofdm,
struct statistics_rx_ht_phy *cur_ofdm_ht,
struct statistics_tx *tx,
unsigned long stamp)
{ {
const struct iwl_mod_params *mod_params = priv->cfg->mod_params; const struct iwl_mod_params *mod_params = priv->cfg->mod_params;
unsigned int msecs; unsigned int msecs;
unsigned long stamp;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return; return;
stamp = jiffies;
msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
/* Only gather statistics and update time stamp when not associated */ /* Only gather statistics and update time stamp when not associated */
if (!iwl_is_any_associated(priv)) if (!iwl_is_any_associated(priv))
goto out; return;
/* Do not check/recover when do not have enough statistics data */ /* Do not check/recover when do not have enough statistics data */
if (msecs < 99) if (msecs < 99)
return; return;
if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) { if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) {
IWL_ERR(priv, "low ack count detected, restart firmware\n"); IWL_ERR(priv, "low ack count detected, restart firmware\n");
if (!iwl_force_reset(priv, IWL_FW_RESET, false)) if (!iwl_force_reset(priv, IWL_FW_RESET, false))
return; return;
} }
if (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs)) if (mod_params->plcp_check &&
!iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
iwl_force_reset(priv, IWL_RF_RESET, false); iwl_force_reset(priv, IWL_RF_RESET, false);
out:
if (iwl_bt_statistics(priv))
memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
sizeof(priv->_agn.statistics_bt));
else
memcpy(&priv->_agn.statistics, &pkt->u.stats,
sizeof(priv->_agn.statistics));
priv->rx_statistics_jiffies = stamp;
} }
/* Calculate noise level, based on measurements during network silence just /* Calculate noise level, based on measurements during network silence just
@ -548,10 +520,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
int bcn_silence_a, bcn_silence_b, bcn_silence_c; int bcn_silence_a, bcn_silence_b, bcn_silence_c;
int last_rx_noise; int last_rx_noise;
if (iwl_bt_statistics(priv)) rx_info = &priv->statistics.rx_non_phy;
rx_info = &(priv->_agn.statistics_bt.rx.general.common);
else
rx_info = &(priv->_agn.statistics.rx.general);
bcn_silence_a = bcn_silence_a =
le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
bcn_silence_b = bcn_silence_b =
@ -583,105 +553,153 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
last_rx_noise); last_rx_noise);
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* /*
* based on the assumption of all statistics counter are in DWORD * based on the assumption of all statistics counter are in DWORD
* FIXME: This function is for debugging, do not deal with * FIXME: This function is for debugging, do not deal with
* the case of counters roll-over. * the case of counters roll-over.
*/ */
static void iwl_accumulative_statistics(struct iwl_priv *priv, static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
__le32 *stats) __le32 *max_delta, __le32 *accum, int size)
{ {
#ifdef CONFIG_IWLWIFI_DEBUGFS int i;
int i, size;
__le32 *prev_stats;
u32 *accum_stats;
u32 *delta, *max_delta;
struct statistics_general_common *general, *accum_general;
struct statistics_tx *tx, *accum_tx;
if (iwl_bt_statistics(priv)) { for (i = 0;
prev_stats = (__le32 *)&priv->_agn.statistics_bt; i < size / sizeof(__le32);
accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; i++, prev++, cur++, delta++, max_delta++, accum++) {
size = sizeof(struct iwl_bt_notif_statistics); if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
general = &priv->_agn.statistics_bt.general.common; *delta = cpu_to_le32(
accum_general = &priv->_agn.accum_statistics_bt.general.common; le32_to_cpu(*cur) - le32_to_cpu(*prev));
tx = &priv->_agn.statistics_bt.tx; le32_add_cpu(accum, le32_to_cpu(*delta));
accum_tx = &priv->_agn.accum_statistics_bt.tx; if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
delta = (u32 *)&priv->_agn.delta_statistics_bt;
max_delta = (u32 *)&priv->_agn.max_delta_bt;
} else {
prev_stats = (__le32 *)&priv->_agn.statistics;
accum_stats = (u32 *)&priv->_agn.accum_statistics;
size = sizeof(struct iwl_notif_statistics);
general = &priv->_agn.statistics.general.common;
accum_general = &priv->_agn.accum_statistics.general.common;
tx = &priv->_agn.statistics.tx;
accum_tx = &priv->_agn.accum_statistics.tx;
delta = (u32 *)&priv->_agn.delta_statistics;
max_delta = (u32 *)&priv->_agn.max_delta;
}
for (i = sizeof(__le32); i < size;
i += sizeof(__le32), stats++, prev_stats++, delta++,
max_delta++, accum_stats++) {
if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
*delta = (le32_to_cpu(*stats) -
le32_to_cpu(*prev_stats));
*accum_stats += *delta;
if (*delta > *max_delta)
*max_delta = *delta; *max_delta = *delta;
} }
} }
/* reset accumulative statistics for "no-counter" type statistics */
accum_general->temperature = general->temperature;
accum_general->temperature_m = general->temperature_m;
accum_general->ttl_timestamp = general->ttl_timestamp;
accum_tx->tx_power.ant_a = tx->tx_power.ant_a;
accum_tx->tx_power.ant_b = tx->tx_power.ant_b;
accum_tx->tx_power.ant_c = tx->tx_power.ant_c;
#endif
} }
static void
iwl_accumulative_statistics(struct iwl_priv *priv,
struct statistics_general_common *common,
struct statistics_rx_non_phy *rx_non_phy,
struct statistics_rx_phy *rx_ofdm,
struct statistics_rx_ht_phy *rx_ofdm_ht,
struct statistics_rx_phy *rx_cck,
struct statistics_tx *tx,
struct statistics_bt_activity *bt_activity)
{
#define ACCUM(_name) \
accum_stats((__le32 *)&priv->statistics._name, \
(__le32 *)_name, \
(__le32 *)&priv->delta_stats._name, \
(__le32 *)&priv->max_delta_stats._name, \
(__le32 *)&priv->accum_stats._name, \
sizeof(*_name));
ACCUM(common);
ACCUM(rx_non_phy);
ACCUM(rx_ofdm);
ACCUM(rx_ofdm_ht);
ACCUM(rx_cck);
ACCUM(tx);
if (bt_activity)
ACCUM(bt_activity);
#undef ACCUM
}
#else
static inline void
iwl_accumulative_statistics(struct iwl_priv *priv,
struct statistics_general_common *common,
struct statistics_rx_non_phy *rx_non_phy,
struct statistics_rx_phy *rx_ofdm,
struct statistics_rx_ht_phy *rx_ofdm_ht,
struct statistics_rx_phy *rx_cck,
struct statistics_tx *tx,
struct statistics_bt_activity *bt_activity)
{
}
#endif
static void iwl_rx_statistics(struct iwl_priv *priv, static void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
unsigned long stamp = jiffies;
const int reg_recalib_period = 60; const int reg_recalib_period = 60;
int change; int change;
struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
__le32 *flag;
struct statistics_general_common *common;
struct statistics_rx_non_phy *rx_non_phy;
struct statistics_rx_phy *rx_ofdm;
struct statistics_rx_ht_phy *rx_ofdm_ht;
struct statistics_rx_phy *rx_cck;
struct statistics_tx *tx;
struct statistics_bt_activity *bt_activity;
if (iwl_bt_statistics(priv)) { len -= sizeof(struct iwl_cmd_header); /* skip header */
IWL_DEBUG_RX(priv,
"Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl_bt_notif_statistics),
le32_to_cpu(pkt->len_n_flags) &
FH_RSCSR_FRAME_SIZE_MSK);
change = ((priv->_agn.statistics_bt.general.common.temperature != IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
pkt->u.stats_bt.general.common.temperature) || len);
((priv->_agn.statistics_bt.flag &
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(pkt->u.stats_bt.flag &
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); if (len == sizeof(struct iwl_bt_notif_statistics)) {
struct iwl_bt_notif_statistics *stats;
stats = &pkt->u.stats_bt;
flag = &stats->flag;
common = &stats->general.common;
rx_non_phy = &stats->rx.general.common;
rx_ofdm = &stats->rx.ofdm;
rx_ofdm_ht = &stats->rx.ofdm_ht;
rx_cck = &stats->rx.cck;
tx = &stats->tx;
bt_activity = &stats->general.activity;
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* handle this exception directly */
priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
le32_add_cpu(&priv->statistics.accum_num_bt_kills,
le32_to_cpu(stats->rx.general.num_bt_kills));
#endif
} else if (len == sizeof(struct iwl_notif_statistics)) {
struct iwl_notif_statistics *stats;
stats = &pkt->u.stats;
flag = &stats->flag;
common = &stats->general.common;
rx_non_phy = &stats->rx.general;
rx_ofdm = &stats->rx.ofdm;
rx_ofdm_ht = &stats->rx.ofdm_ht;
rx_cck = &stats->rx.cck;
tx = &stats->tx;
bt_activity = NULL;
} else { } else {
IWL_DEBUG_RX(priv, WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
"Statistics notification received (%d vs %d).\n", len, sizeof(struct iwl_bt_notif_statistics),
(int)sizeof(struct iwl_notif_statistics), sizeof(struct iwl_notif_statistics));
le32_to_cpu(pkt->len_n_flags) & return;
FH_RSCSR_FRAME_SIZE_MSK);
change = ((priv->_agn.statistics.general.common.temperature !=
pkt->u.stats.general.common.temperature) ||
((priv->_agn.statistics.flag &
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(pkt->u.stats.flag &
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
} }
iwl_recover_from_statistics(priv, pkt); change = common->temperature != priv->statistics.common.temperature ||
(*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
rx_ofdm_ht, rx_cck, tx, bt_activity);
iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
priv->statistics.flag = *flag;
memcpy(&priv->statistics.common, common, sizeof(*common));
memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
memcpy(&priv->statistics.tx, tx, sizeof(*tx));
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (bt_activity)
memcpy(&priv->statistics.bt_activity, bt_activity,
sizeof(*bt_activity));
#endif
priv->rx_statistics_jiffies = stamp;
set_bit(STATUS_STATISTICS, &priv->status); set_bit(STATUS_STATISTICS, &priv->status);
@ -708,18 +726,12 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv,
if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
memset(&priv->_agn.accum_statistics, 0, memset(&priv->accum_stats, 0,
sizeof(struct iwl_notif_statistics)); sizeof(priv->accum_stats));
memset(&priv->_agn.delta_statistics, 0, memset(&priv->delta_stats, 0,
sizeof(struct iwl_notif_statistics)); sizeof(priv->delta_stats));
memset(&priv->_agn.max_delta, 0, memset(&priv->max_delta_stats, 0,
sizeof(struct iwl_notif_statistics)); sizeof(priv->max_delta_stats));
memset(&priv->_agn.accum_statistics_bt, 0,
sizeof(struct iwl_bt_notif_statistics));
memset(&priv->_agn.delta_statistics_bt, 0,
sizeof(struct iwl_bt_notif_statistics));
memset(&priv->_agn.max_delta_bt, 0,
sizeof(struct iwl_bt_notif_statistics));
#endif #endif
IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
} }
@ -873,6 +885,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
{ {
struct sk_buff *skb; struct sk_buff *skb;
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
struct iwl_rxon_context *ctx;
/* We only process data packets if the interface is open */ /* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) { if (unlikely(!priv->is_open)) {
@ -895,6 +908,26 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
iwl_update_stats(priv, false, fc, len); iwl_update_stats(priv, false, fc, len);
/*
* Wake any queues that were stopped due to a passive channel tx
* failure. This can happen because the regulatory enforcement in
* the device waits for a beacon before allowing transmission,
* sometimes even after already having transmitted frames for the
* association because the new RXON may reset the information.
*/
if (unlikely(ieee80211_is_beacon(fc))) {
for_each_context(priv, ctx) {
if (!ctx->last_tx_rejected)
continue;
if (compare_ether_addr(hdr->addr3,
ctx->active.bssid_addr))
continue;
ctx->last_tx_rejected = false;
iwl_wake_any_queue(priv, ctx);
}
}
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
ieee80211_rx(priv->hw, skb); ieee80211_rx(priv->hw, skb);

View File

@ -494,7 +494,8 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
priv->num_stations--; priv->num_stations--;
BUG_ON(priv->num_stations < 0); if (WARN_ON(priv->num_stations < 0))
priv->num_stations = 0;
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
@ -679,7 +680,8 @@ void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
priv->num_stations--; priv->num_stations--;
BUG_ON(priv->num_stations < 0); if (WARN_ON(priv->num_stations < 0))
priv->num_stations = 0;
kfree(priv->stations[i].lq); kfree(priv->stations[i].lq);
priv->stations[i].lq = NULL; priv->stations[i].lq = NULL;
} }
@ -775,7 +777,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
spin_unlock_irqrestore(&priv->sta_lock, flags_spin); spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
iwl_dump_lq_cmd(priv, lq); iwl_dump_lq_cmd(priv, lq);
BUG_ON(init && (cmd.flags & CMD_ASYNC)); if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
return -EINVAL;
if (is_lq_table_valid(priv, ctx, lq)) if (is_lq_table_valid(priv, ctx, lq))
ret = iwl_send_cmd(priv, &cmd); ret = iwl_send_cmd(priv, &cmd);

View File

@ -232,7 +232,6 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
* reclaiming packets (on 'tx done IRQ), if free space become > high mark, * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
* Tx queue resumed. * Tx queue resumed.
* *
* See more detailed info in iwl-4965-hw.h.
***************************************************/ ***************************************************/
int iwl_queue_space(const struct iwl_queue *q) int iwl_queue_space(const struct iwl_queue *q)
@ -264,11 +263,13 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
/* count must be power-of-two size, otherwise iwl_queue_inc_wrap /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
* and iwl_queue_dec_wrap are broken. */ * and iwl_queue_dec_wrap are broken. */
BUG_ON(!is_power_of_2(count)); if (WARN_ON(!is_power_of_2(count)))
return -EINVAL;
/* slots_num must be power-of-two size, otherwise /* slots_num must be power-of-two size, otherwise
* get_cmd_index is broken. */ * get_cmd_index is broken. */
BUG_ON(!is_power_of_2(slots_num)); if (WARN_ON(!is_power_of_2(slots_num)))
return -EINVAL;
q->low_mark = q->n_window / 4; q->low_mark = q->n_window / 4;
if (q->low_mark < 4) if (q->low_mark < 4)
@ -385,7 +386,9 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
/* Initialize queue's high/low-water marks, and head/tail indexes */ /* Initialize queue's high/low-water marks, and head/tail indexes */
iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
if (ret)
return ret;
/* Tell device where to find queue */ /* Tell device where to find queue */
priv->cfg->ops->lib->txq_init(priv, txq); priv->cfg->ops->lib->txq_init(priv, txq);
@ -447,14 +450,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
/* If any of the command structures end up being larger than /*
* If any of the command structures end up being larger than
* the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
* we will need to increase the size of the TFD entries * we will need to increase the size of the TFD entries
* Also, check to see if command buffer should not exceed the size * Also, check to see if command buffer should not exceed the size
* of device_cmd and max_cmd_size. */ * of device_cmd and max_cmd_size.
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && */
!(cmd->flags & CMD_SIZE_HUGE)); if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
BUG_ON(fix_size > IWL_MAX_CMD_SIZE); !(cmd->flags & CMD_SIZE_HUGE)))
return -EINVAL;
if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE))
return -EINVAL;
if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
IWL_WARN(priv, "Not sending command - %s KILL\n", IWL_WARN(priv, "Not sending command - %s KILL\n",
@ -462,16 +470,21 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
return -EIO; return -EIO;
} }
/*
* As we only have a single huge buffer, check that the command
* is synchronous (otherwise buffers could end up being reused).
*/
if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE)))
return -EINVAL;
spin_lock_irqsave(&priv->hcmd_lock, flags); spin_lock_irqsave(&priv->hcmd_lock, flags);
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
spin_unlock_irqrestore(&priv->hcmd_lock, flags); spin_unlock_irqrestore(&priv->hcmd_lock, flags);
IWL_ERR(priv, "No space in command queue\n"); IWL_ERR(priv, "No space in command queue\n");
if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { is_ct_kill = iwl_check_for_ct_kill(priv);
is_ct_kill =
priv->cfg->ops->lib->tt_ops.ct_kill_check(priv);
}
if (!is_ct_kill) { if (!is_ct_kill) {
IWL_ERR(priv, "Restarting adapter due to queue full\n"); IWL_ERR(priv, "Restarting adapter due to queue full\n");
iwlagn_fw_error(priv, false); iwlagn_fw_error(priv, false);

View File

@ -115,7 +115,7 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv,
SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
/* Clear RD responder bit */ /* Clear RD responder bit */
RESETHT_EXTCAP_RDG(ht_ext_cap); ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER;
ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info);
ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
@ -242,9 +242,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
* *
* Handling includes changing the header fields into CPU format. * Handling includes changing the header fields into CPU format.
*/ */
int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf)
struct host_cmd_ds_command *resp,
void *data_buf)
{ {
struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
@ -298,8 +296,7 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
* - Setting AMSDU control parameters (for SET only) * - Setting AMSDU control parameters (for SET only)
* - Ensuring correct endian-ness * - Ensuring correct endian-ness
*/ */
int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
struct host_cmd_ds_command *cmd,
int cmd_action, void *data_buf) int cmd_action, void *data_buf)
{ {
struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
@ -331,8 +328,7 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
* *
* Handling includes changing the header fields into CPU format. * Handling includes changing the header fields into CPU format.
*/ */
int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
struct host_cmd_ds_command *resp,
void *data_buf) void *data_buf)
{ {
struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
@ -357,8 +353,7 @@ int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
* - Setting HT Tx capability and HT Tx information fields * - Setting HT Tx capability and HT Tx information fields
* - Ensuring correct endian-ness * - Ensuring correct endian-ness
*/ */
int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
struct host_cmd_ds_command *cmd,
u16 cmd_action, void *data_buf) u16 cmd_action, void *data_buf)
{ {
struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
@ -541,11 +536,8 @@ mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
if (curr_tx_buf_size != tx_buf) if (curr_tx_buf_size != tx_buf)
mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
HostCmd_ACT_GEN_SET, 0, HostCmd_ACT_GEN_SET, 0, &tx_buf);
NULL, &tx_buf);
return;
} }
/* /*
@ -583,8 +575,6 @@ void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
list_del(&tx_ba_tsr_tbl->list); list_del(&tx_ba_tsr_tbl->list);
kfree(tx_ba_tsr_tbl); kfree(tx_ba_tsr_tbl);
return;
} }
/* /*
@ -663,8 +653,6 @@ void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
} }
return;
} }
/* /*
@ -694,8 +682,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
/* We don't wait for the response of this command */ /* We don't wait for the response of this command */
ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
0, 0, NULL, &add_ba_req); 0, 0, &add_ba_req);
return ret; return ret;
} }
@ -722,8 +710,8 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
/* We don't wait for the response of this command */ /* We don't wait for the response of this command */
ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
HostCmd_ACT_GEN_SET, 0, NULL, &delba); HostCmd_ACT_GEN_SET, 0, &delba);
return ret; return ret;
} }

Some files were not shown because too many files have changed in this diff Show More