提交 b5f185f3 编写于 作者: D David S. Miller

Merge tag 'master-2014-12-08' of...

Merge tag 'master-2014-12-08' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John W. Linville says:

====================
pull request: wireless-next 2014-12-08

Please pull this last batch of pending wireless updates for the 3.19 tree...

For the wireless bits, Johannes says:

"This time I have Felix's no-status rate control work, which will allow
drivers to work better with rate control even if they don't have perfect
status reporting. In addition to this, a small hwsim fix from Patrik,
one of the regulatory patches from Arik, and a number of cleanups and
fixes I did myself.

Of note is a patch where I disable CFG80211_WEXT so that compatibility
is no longer selectable - this is intended as a wake-up call for anyone
who's still using it, and is still easily worked around (it's a one-line
patch) before we fully remove the code as well in the future."

For the Bluetooth bits, Johan says:

"Here's one more bluetooth-next pull request for 3.19:

 - Minor cleanups for ieee802154 & mac802154
 - Fix for the kernel warning with !TASK_RUNNING reported by Kirill A.
   Shutemov
 - Support for another ath3k device
 - Fix for tracking link key based security level
 - Device tree bindings for btmrvl + a state update fix
 - Fix for wrong ACL flags on LE links"

And...

"In addition to the previous one this contains two more cleanups to
mac802154 as well as support for some new HCI features from the
Bluetooth 4.2 specification.

From the original request:

'Here's what should be the last bluetooth-next pull request for 3.19.
It's rather large but the majority of it is the Low Energy Secure
Connections feature that's part of the Bluetooth 4.2 specification. The
specification went public only this week so we couldn't publish the
corresponding code before that. The code itself can nevertheless be
considered fairly mature as it's been in development for over 6 months
and gone through several interoperability test events.

Besides LE SC the pull request contains an important fix for command
complete events for mgmt sockets which also fixes some leaks of hci_conn
objects when powering off or unplugging Bluetooth adapters.

A smaller feature that's part of the pull request is service discovery
support. This is like normal device discovery except that devices not
matching specific UUIDs or strong enough RSSI are filtered out.

Other changes that the pull request contains are firmware dump support
to the btmrvl driver, firmware download support for Broadcom BCM20702A0
variants, as well as some coding style cleanups in 6lowpan &
ieee802154/mac802154 code.'"

For the NFC bits, Samuel says:

"With this one we get:

- NFC digital improvements for DEP support: Chaining, NACK and ATN
  support added.

- NCI improvements: Support for p2p target, SE IO operand addition,
  SE operands extensions to support proprietary implementations, and
  a few fixes.

- NFC HCI improvements: OPEN_PIPE and NOTIFY_ALL_CLEARED support,
  and SE IO operand addition.

- A bunch of minor improvements and fixes for STMicro st21nfcb and
  st21nfca"

For the iwlwifi bits, Emmanuel says:

"Major works are CSA and TDLS. On top of that I have a new
firmware API for scan and a few rate control improvements.
Johannes find a few tricks to improve our CPU utilization
and adds support for a new spin of 7265 called 7265D.
Along with this a few random things that don't stand out."

And...

"I deprecate here -8.ucode since -9 has been published long ago.
Along with that I have a new activity, we have now better
a infrastructure for firmware debugging. This will allow to
have configurable probes insides the firmware.
Luca continues his work on NetDetect, this feature is now
complete. All the rest is minor fixes here and there."

For the Atheros bits, Kalle says:

"Only ath10k changes this time and no major changes. Most visible are:

o new debugfs interface for runtime firmware debugging (Yanbo)

o fix shared WEP (Sujith)

o don't rebuild whenever kernel version changes (Johannes)

o lots of refactoring to make it easier to add new hw support (Michal)

There's also smaller fixes and improvements with no point of listing
here."

In addition, there are a few last minute updates to ath5k,
ath9k, brcmfmac, brcmsmac, mwifiex, rt2x00, rtlwifi, and wil6210.
Also included is a pull of the wireless tree to pick-up the fixes
originally included in "pull request: wireless 2014-12-03"...

Please let me know if there are problems!
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
btmrvl
------
Required properties:
- compatible : must be "btmrvl,cfgdata"
Optional properties:
- btmrvl,cal-data : Calibration data downloaded to the device during
initialization. This is an array of 28 values(u8).
- btmrvl,gpio-gap : gpio and gap (in msecs) combination to be
configured.
Example:
GPIO pin 13 is configured as a wakeup source and GAP is set to 100 msecs
in below example.
btmrvl {
compatible = "btmrvl,cfgdata";
btmrvl,cal-data = /bits/ 8 <
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0xf0 0x00>;
btmrvl,gpio-gap = <0x0d64>;
};
......@@ -7919,11 +7919,10 @@ S: Maintained
F: drivers/media/dvb-frontends/rtl2832_sdr*
RTL8180 WIRELESS DRIVER
M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
S: Orphan
F: drivers/net/wireless/rtl818x/rtl8180/
RTL8187 WIRELESS DRIVER
......
......@@ -210,6 +210,7 @@ config BT_MRVL_SDIO
tristate "Marvell BT-over-SDIO driver"
depends on BT_MRVL && MMC
select FW_LOADER
select WANT_DEV_COREDUMP
help
The driver for Marvell Bluetooth chipsets with SDIO interface.
......
......@@ -106,6 +106,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3375) },
{ USB_DEVICE(0x13d3, 0x3393) },
{ USB_DEVICE(0x13d3, 0x3402) },
{ USB_DEVICE(0x13d3, 0x3408) },
{ USB_DEVICE(0x13d3, 0x3432) },
/* Atheros AR5BBU12 with sflash firmware */
......@@ -158,6 +159,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
......
......@@ -167,6 +167,35 @@ static const struct file_operations btmrvl_hscmd_fops = {
.llseek = default_llseek,
};
static ssize_t btmrvl_fwdump_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
bool result;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (strtobool(buf, &result))
return -EINVAL;
if (!result)
return -EINVAL;
btmrvl_firmware_dump(priv);
return count;
}
static const struct file_operations btmrvl_fwdump_fops = {
.write = btmrvl_fwdump_write,
.open = simple_open,
.llseek = default_llseek,
};
void btmrvl_debugfs_init(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
......@@ -197,6 +226,8 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
priv, &btmrvl_hscmd_fops);
debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
priv, &btmrvl_hscfgcmd_fops);
debugfs_create_file("fw_dump", 0200, dbg->config_dir,
priv, &btmrvl_fwdump_fops);
dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
debugfs_create_u8("curpsmode", 0444, dbg->status_dir,
......
......@@ -32,6 +32,24 @@
/* Time to wait for command response in millisecond */
#define WAIT_UNTIL_CMD_RESP 5000
enum rdwr_status {
RDWR_STATUS_SUCCESS = 0,
RDWR_STATUS_FAILURE = 1,
RDWR_STATUS_DONE = 2
};
#define FW_DUMP_MAX_NAME_LEN 8
#define FW_DUMP_HOST_READY 0xEE
#define FW_DUMP_DONE 0xFF
#define FW_DUMP_READ_DONE 0xFE
struct memory_type_mapping {
u8 mem_name[FW_DUMP_MAX_NAME_LEN];
u8 *mem_ptr;
u32 mem_size;
u8 done_flag;
};
struct btmrvl_thread {
struct task_struct *task;
wait_queue_head_t wait_q;
......@@ -81,6 +99,7 @@ struct btmrvl_private {
u8 *payload, u16 nb);
int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
int (*hw_process_int_status) (struct btmrvl_private *priv);
void (*firmware_dump)(struct btmrvl_private *priv);
spinlock_t driver_lock; /* spinlock used by driver */
#ifdef CONFIG_DEBUG_FS
void *debugfs_data;
......@@ -151,6 +170,7 @@ int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv);
int btmrvl_enable_hs(struct btmrvl_private *priv);
void btmrvl_firmware_dump(struct btmrvl_private *priv);
#ifdef CONFIG_DEBUG_FS
void btmrvl_debugfs_init(struct hci_dev *hdev);
......
......@@ -22,6 +22,7 @@
#include <linux/of.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <linux/mmc/sdio_func.h>
#include "btmrvl_drv.h"
#include "btmrvl_sdio.h"
......@@ -41,6 +42,11 @@ void btmrvl_interrupt(struct btmrvl_private *priv)
priv->adapter->int_count++;
if (priv->adapter->hs_state == HS_ACTIVATED) {
BT_DBG("BT: HS DEACTIVATED in ISR!");
priv->adapter->hs_state = HS_DEACTIVATED;
}
wake_up_interruptible(&priv->main_thread.wait_q);
}
EXPORT_SYMBOL_GPL(btmrvl_interrupt);
......@@ -209,7 +215,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
ret = btmrvl_send_sync_cmd(priv, BT_CMD_MODULE_CFG_REQ, &subcmd, 1);
if (ret)
BT_ERR("module_cfg_cmd(%x) failed\n", subcmd);
BT_ERR("module_cfg_cmd(%x) failed", subcmd);
return ret;
}
......@@ -245,7 +251,7 @@ int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_CONFIG, param, 2);
if (ret)
BT_ERR("HSCFG command failed\n");
BT_ERR("HSCFG command failed");
return ret;
}
......@@ -263,7 +269,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv)
ret = btmrvl_send_sync_cmd(priv, BT_CMD_AUTO_SLEEP_MODE, &param, 1);
if (ret)
BT_ERR("PSMODE command failed\n");
BT_ERR("PSMODE command failed");
return 0;
}
......@@ -276,7 +282,7 @@ int btmrvl_enable_hs(struct btmrvl_private *priv)
ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0);
if (ret) {
BT_ERR("Host sleep enable command failed\n");
BT_ERR("Host sleep enable command failed");
return ret;
}
......@@ -323,12 +329,19 @@ int btmrvl_prepare_command(struct btmrvl_private *priv)
} else {
ret = priv->hw_wakeup_firmware(priv);
priv->adapter->hs_state = HS_DEACTIVATED;
BT_DBG("BT: HS DEACTIVATED due to host activity!");
}
}
return ret;
}
void btmrvl_firmware_dump(struct btmrvl_private *priv)
{
if (priv->firmware_dump)
priv->firmware_dump(priv);
}
static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
{
int ret = 0;
......@@ -487,34 +500,36 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv,
ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data,
BT_CAL_HDR_LEN + len);
if (ret)
BT_ERR("Failed to download caibration data\n");
BT_ERR("Failed to download caibration data");
return 0;
}
static int btmrvl_cal_data_dt(struct btmrvl_private *priv)
static int btmrvl_check_device_tree(struct btmrvl_private *priv)
{
struct device_node *dt_node;
u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE];
const char name[] = "btmrvl_caldata";
const char property[] = "btmrvl,caldata";
int ret;
dt_node = of_find_node_by_name(NULL, name);
if (!dt_node)
return -ENODEV;
ret = of_property_read_u8_array(dt_node, property,
cal_data + BT_CAL_HDR_LEN,
BT_CAL_DATA_SIZE);
if (ret)
return ret;
BT_DBG("Use cal data from device tree");
ret = btmrvl_download_cal_data(priv, cal_data, BT_CAL_DATA_SIZE);
if (ret) {
BT_ERR("Fail to download calibrate data");
return ret;
u32 val;
for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") {
ret = of_property_read_u32(dt_node, "btmrvl,gpio-gap", &val);
if (!ret)
priv->btmrvl_dev.gpio_gap = val;
ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data",
cal_data + BT_CAL_HDR_LEN,
BT_CAL_DATA_SIZE);
if (ret)
return ret;
BT_DBG("Use cal data from device tree");
ret = btmrvl_download_cal_data(priv, cal_data,
BT_CAL_DATA_SIZE);
if (ret) {
BT_ERR("Fail to download calibrate data");
return ret;
}
}
return 0;
......@@ -526,14 +541,15 @@ static int btmrvl_setup(struct hci_dev *hdev)
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
btmrvl_cal_data_dt(priv);
priv->btmrvl_dev.gpio_gap = 0xffff;
btmrvl_check_device_tree(priv);
btmrvl_pscan_window_reporting(priv, 0x01);
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
priv->btmrvl_dev.gpio_gap = 0xffff;
btmrvl_send_hscfg_cmd(priv);
return 0;
......
......@@ -24,6 +24,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/module.h>
#include <linux/devcoredump.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
......@@ -33,6 +34,24 @@
#define VERSION "1.0"
static struct memory_type_mapping mem_type_mapping_tbl[] = {
{"ITCM", NULL, 0, 0xF0},
{"DTCM", NULL, 0, 0xF1},
{"SQRAM", NULL, 0, 0xF2},
{"APU", NULL, 0, 0xF3},
{"CIU", NULL, 0, 0xF4},
{"ICU", NULL, 0, 0xF5},
{"MAC", NULL, 0, 0xF6},
{"EXT7", NULL, 0, 0xF7},
{"EXT8", NULL, 0, 0xF8},
{"EXT9", NULL, 0, 0xF9},
{"EXT10", NULL, 0, 0xFA},
{"EXT11", NULL, 0, 0xFB},
{"EXT12", NULL, 0, 0xFC},
{"EXT13", NULL, 0, 0xFD},
{"EXTLAST", NULL, 0, 0xFE},
};
/* The btmrvl_sdio_remove() callback function is called
* when user removes this module from kernel space or ejects
* the card from the slot. The driver handles these 2 cases
......@@ -122,6 +141,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
.int_read_to_clear = true,
.host_int_rsr = 0x01,
.card_misc_cfg = 0xcc,
.fw_dump_ctrl = 0xe2,
.fw_dump_start = 0xe3,
.fw_dump_end = 0xea,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
......@@ -130,6 +152,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.reg = &btmrvl_reg_8688,
.support_pscan_win_report = false,
.sd_blksz_fw_dl = 64,
.supports_fw_dump = false,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
......@@ -138,6 +161,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
.reg = &btmrvl_reg_87xx,
.support_pscan_win_report = false,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = false,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
......@@ -146,6 +170,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
.reg = &btmrvl_reg_87xx,
.support_pscan_win_report = false,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = false,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
......@@ -154,6 +179,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
.reg = &btmrvl_reg_8887,
.support_pscan_win_report = true,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = false,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
......@@ -162,6 +188,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
.reg = &btmrvl_reg_8897,
.support_pscan_win_report = true,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = true,
};
static const struct sdio_device_id btmrvl_sdio_ids[] = {
......@@ -764,8 +791,8 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
card = sdio_get_drvdata(func);
if (!card || !card->priv) {
BT_ERR("sbi_interrupt(%p) card or priv is "
"NULL, card=%p\n", func, card);
BT_ERR("sbi_interrupt(%p) card or priv is NULL, card=%p",
func, card);
return;
}
......@@ -1080,6 +1107,277 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
return ret;
}
static void btmrvl_sdio_dump_regs(struct btmrvl_private *priv)
{
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
int ret = 0;
unsigned int reg, reg_start, reg_end;
char buf[256], *ptr;
u8 loop, func, data;
int MAX_LOOP = 2;
btmrvl_sdio_wakeup_fw(priv);
sdio_claim_host(card->func);
for (loop = 0; loop < MAX_LOOP; loop++) {
memset(buf, 0, sizeof(buf));
ptr = buf;
if (loop == 0) {
/* Read the registers of SDIO function0 */
func = loop;
reg_start = 0;
reg_end = 9;
} else {
func = 2;
reg_start = 0;
reg_end = 0x09;
}
ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ",
func, reg_start, reg_end);
for (reg = reg_start; reg <= reg_end; reg++) {
if (func == 0)
data = sdio_f0_readb(card->func, reg, &ret);
else
data = sdio_readb(card->func, reg, &ret);
if (!ret) {
ptr += sprintf(ptr, "%02x ", data);
} else {
ptr += sprintf(ptr, "ERR");
break;
}
}
BT_INFO("%s", buf);
}
sdio_release_host(card->func);
}
/* This function read/write firmware */
static enum
rdwr_status btmrvl_sdio_rdwr_firmware(struct btmrvl_private *priv,
u8 doneflag)
{
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
int ret, tries;
u8 ctrl_data = 0;
sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl,
&ret);
if (ret) {
BT_ERR("SDIO write err");
return RDWR_STATUS_FAILURE;
}
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl,
&ret);
if (ret) {
BT_ERR("SDIO read err");
return RDWR_STATUS_FAILURE;
}
if (ctrl_data == FW_DUMP_DONE)
break;
if (doneflag && ctrl_data == doneflag)
return RDWR_STATUS_DONE;
if (ctrl_data != FW_DUMP_HOST_READY) {
BT_INFO("The ctrl reg was changed, re-try again!");
sdio_writeb(card->func, FW_DUMP_HOST_READY,
card->reg->fw_dump_ctrl, &ret);
if (ret) {
BT_ERR("SDIO write err");
return RDWR_STATUS_FAILURE;
}
}
usleep_range(100, 200);
}
if (ctrl_data == FW_DUMP_HOST_READY) {
BT_ERR("Fail to pull ctrl_data");
return RDWR_STATUS_FAILURE;
}
return RDWR_STATUS_SUCCESS;
}
/* This function dump sdio register and memory data */
static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv)
{
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
int ret = 0;
unsigned int reg, reg_start, reg_end;
enum rdwr_status stat;
u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr;
u8 dump_num, idx, i, read_reg, doneflag = 0;
u32 memory_size, fw_dump_len = 0;
/* dump sdio register first */
btmrvl_sdio_dump_regs(priv);
if (!card->supports_fw_dump) {
BT_ERR("Firmware dump not supported for this card!");
return;
}
for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
if (entry->mem_ptr) {
vfree(entry->mem_ptr);
entry->mem_ptr = NULL;
}
entry->mem_size = 0;
}
btmrvl_sdio_wakeup_fw(priv);
sdio_claim_host(card->func);
BT_INFO("== btmrvl firmware dump start ==");
stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
reg = card->reg->fw_dump_start;
/* Read the number of the memories which will dump */
dump_num = sdio_readb(card->func, reg, &ret);
if (ret) {
BT_ERR("SDIO read memory length err");
goto done;
}
/* Read the length of every memory which will dump */
for (idx = 0; idx < dump_num; idx++) {
struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
memory_size = 0;
reg = card->reg->fw_dump_start;
for (i = 0; i < 4; i++) {
read_reg = sdio_readb(card->func, reg, &ret);
if (ret) {
BT_ERR("SDIO read err");
goto done;
}
memory_size |= (read_reg << i*8);
reg++;
}
if (memory_size == 0) {
BT_INFO("Firmware dump finished!");
break;
}
BT_INFO("%s_SIZE=0x%x", entry->mem_name, memory_size);
entry->mem_ptr = vzalloc(memory_size + 1);
entry->mem_size = memory_size;
if (!entry->mem_ptr) {
BT_ERR("Vzalloc %s failed", entry->mem_name);
goto done;
}
fw_dump_len += (strlen("========Start dump ") +
strlen(entry->mem_name) +
strlen("========\n") +
(memory_size + 1) +
strlen("\n========End dump========\n"));
dbg_ptr = entry->mem_ptr;
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
BT_INFO("Start %s output, please wait...",
entry->mem_name);
do {
stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
reg_start = card->reg->fw_dump_start;
reg_end = card->reg->fw_dump_end;
for (reg = reg_start; reg <= reg_end; reg++) {
*dbg_ptr = sdio_readb(card->func, reg, &ret);
if (ret) {
BT_ERR("SDIO read err");
goto done;
}
if (dbg_ptr < end_ptr)
dbg_ptr++;
else
BT_ERR("Allocated buffer not enough");
}
if (stat != RDWR_STATUS_DONE) {
continue;
} else {
BT_INFO("%s done: size=0x%tx",
entry->mem_name,
dbg_ptr - entry->mem_ptr);
break;
}
} while (1);
}
BT_INFO("== btmrvl firmware dump end ==");
done:
sdio_release_host(card->func);
if (fw_dump_len == 0)
return;
fw_dump_data = vzalloc(fw_dump_len+1);
if (!fw_dump_data) {
BT_ERR("Vzalloc fw_dump_data fail!");
return;
}
fw_dump_ptr = fw_dump_data;
/* Dump all the memory data into single file, a userspace script will
be used to split all the memory data to multiple files*/
BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump start");
for (idx = 0; idx < dump_num; idx++) {
struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
if (entry->mem_ptr) {
strcpy(fw_dump_ptr, "========Start dump ");
fw_dump_ptr += strlen("========Start dump ");
strcpy(fw_dump_ptr, entry->mem_name);
fw_dump_ptr += strlen(entry->mem_name);
strcpy(fw_dump_ptr, "========\n");
fw_dump_ptr += strlen("========\n");
memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
fw_dump_ptr += entry->mem_size;
strcpy(fw_dump_ptr, "\n========End dump========\n");
fw_dump_ptr += strlen("\n========End dump========\n");
vfree(mem_type_mapping_tbl[idx].mem_ptr);
mem_type_mapping_tbl[idx].mem_ptr = NULL;
}
}
/* fw_dump_data will be free in device coredump release function
after 5 min*/
dev_coredumpv(&priv->btmrvl_dev.hcidev->dev, fw_dump_data,
fw_dump_len, GFP_KERNEL);
BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end");
}
static int btmrvl_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
......@@ -1103,6 +1401,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
card->reg = data->reg;
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
card->support_pscan_win_report = data->support_pscan_win_report;
card->supports_fw_dump = data->supports_fw_dump;
}
if (btmrvl_sdio_register_dev(card) < 0) {
......@@ -1134,6 +1433,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
priv->hw_host_to_card = btmrvl_sdio_host_to_card;
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
priv->hw_process_int_status = btmrvl_sdio_process_int_status;
priv->firmware_dump = btmrvl_sdio_dump_firmware;
if (btmrvl_register_hdev(priv)) {
BT_ERR("Register hdev failed!");
......
......@@ -81,6 +81,9 @@ struct btmrvl_sdio_card_reg {
bool int_read_to_clear;
u8 host_int_rsr;
u8 card_misc_cfg;
u8 fw_dump_ctrl;
u8 fw_dump_start;
u8 fw_dump_end;
};
struct btmrvl_sdio_card {
......@@ -90,6 +93,7 @@ struct btmrvl_sdio_card {
const char *firmware;
const struct btmrvl_sdio_card_reg *reg;
bool support_pscan_win_report;
bool supports_fw_dump;
u16 sd_blksz_fw_dl;
u8 rx_unit;
struct btmrvl_private *priv;
......@@ -101,6 +105,7 @@ struct btmrvl_sdio_device {
const struct btmrvl_sdio_card_reg *reg;
const bool support_pscan_win_report;
u16 sd_blksz_fw_dl;
bool supports_fw_dump;
};
......
......@@ -110,7 +110,8 @@ static const struct usb_device_id btusb_table[] = {
.driver_info = BTUSB_BCM_PATCHRAM },
/* Foxconn - Hon Hai */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
/* Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
......@@ -185,6 +186,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
......
......@@ -2104,6 +2104,7 @@ static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
bp->flags &= ~B44_FLAG_WOL_ENABLE;
spin_unlock_irq(&bp->lock);
device_set_wakeup_enable(bp->sdev->dev, wol->wolopts & WAKE_MAGIC);
return 0;
}
......@@ -2452,6 +2453,7 @@ static int b44_init_one(struct ssb_device *sdev,
}
}
device_set_wakeup_capable(sdev->dev, true);
netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
return 0;
......
......@@ -858,7 +858,7 @@ static int cc2520_probe(struct spi_device *spi)
pinctrl = devm_pinctrl_get_select_default(&spi->dev);
if (IS_ERR(pinctrl))
dev_warn(&spi->dev,
"pinctrl pins are not configured");
"pinctrl pins are not configured\n");
pdata = cc2520_get_platform_data(spi);
if (!pdata) {
......
......@@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work)
mutex_unlock(&ar->conf_mutex);
}
static void ath10k_core_init_max_sta_count(struct ath10k *ar)
{
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
ar->max_num_peers = TARGET_10X_NUM_PEERS;
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
} else {
ar->max_num_peers = TARGET_NUM_PEERS;
ar->max_num_stations = TARGET_NUM_STATIONS;
}
}
int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
{
int status;
......@@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
return ret;
}
ath10k_core_init_max_sta_count(ar);
mutex_lock(&ar->conf_mutex);
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
......
......@@ -79,10 +79,12 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
struct ath10k_skb_cb {
dma_addr_t paddr;
u8 eid;
u8 vdev_id;
struct {
u8 tid;
u16 freq;
bool is_offchan;
struct ath10k_htt_txbuf *txbuf;
u32 txbuf_paddr;
......@@ -122,6 +124,7 @@ struct ath10k_wmi {
struct completion service_ready;
struct completion unified_ready;
wait_queue_head_t tx_credits_wq;
DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX);
struct wmi_cmd_map *cmd;
struct wmi_vdev_param_map *vdev_param;
struct wmi_pdev_param_map *pdev_param;
......@@ -218,6 +221,8 @@ struct ath10k_peer {
int vdev_id;
u8 addr[ETH_ALEN];
DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
/* protected by ar->data_lock */
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
};
......@@ -310,7 +315,6 @@ struct ath10k_debug {
struct ath10k_fw_stats fw_stats;
struct completion fw_stats_complete;
bool fw_stats_done;
DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX);
unsigned long htt_stats_mask;
struct delayed_work htt_stats_dwork;
......@@ -320,6 +324,7 @@ struct ath10k_debug {
/* protected by conf_mutex */
u32 fw_dbglog_mask;
u32 pktlog_filter;
u32 reg_addr;
u8 htt_max_amsdu;
u8 htt_max_ampdu;
......@@ -560,8 +565,12 @@ struct ath10k {
struct list_head peers;
wait_queue_head_t peer_mapping_wq;
/* number of created peers; protected by data_lock */
/* protected by conf_mutex */
int num_peers;
int num_stations;
int max_num_peers;
int max_num_stations;
struct work_struct offchan_tx_work;
struct sk_buff_head offchan_tx_queue;
......
......@@ -17,9 +17,8 @@
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/version.h>
#include <linux/vermagic.h>
#include <linux/vmalloc.h>
#include <linux/utsname.h>
#include "core.h"
#include "debug.h"
......@@ -124,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar)
{
ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n",
ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n",
ar->hw_params.name,
ar->target_version,
ar->chip_id,
......@@ -136,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar)
ar->fw_version_minor,
ar->fw_version_release,
ar->fw_version_build,
ath10k_cal_mode_str(ar->cal_mode));
ath10k_cal_mode_str(ar->cal_mode),
ar->max_num_stations);
ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
config_enabled(CONFIG_ATH10K_DEBUG),
config_enabled(CONFIG_ATH10K_DEBUGFS),
......@@ -179,13 +179,6 @@ EXPORT_SYMBOL(ath10k_warn);
#ifdef CONFIG_ATH10K_DEBUGFS
void ath10k_debug_read_service_map(struct ath10k *ar,
const void *service_map,
size_t map_size)
{
memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
}
static ssize_t ath10k_read_wmi_services(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
......@@ -207,8 +200,9 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
if (len > buf_len)
len = buf_len;
spin_lock_bh(&ar->data_lock);
for (i = 0; i < WMI_SERVICE_MAX; i++) {
enabled = test_bit(i, ar->debug.wmi_service_bitmap);
enabled = test_bit(i, ar->wmi.svc_map);
name = wmi_service_name(i);
if (!name) {
......@@ -224,6 +218,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
"%-40s %s\n",
name, enabled ? "enabled" : "-");
}
spin_unlock_bh(&ar->data_lock);
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
......@@ -866,8 +861,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
sizeof(dump_data->fw_ver));
dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE);
strlcpy(dump_data->kernel_ver, VERMAGIC_STRING,
dump_data->kernel_ver_code = 0;
strlcpy(dump_data->kernel_ver, init_utsname()->release,
sizeof(dump_data->kernel_ver));
dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
......@@ -929,6 +924,236 @@ static const struct file_operations fops_fw_crash_dump = {
.llseek = default_llseek,
};
static ssize_t ath10k_reg_addr_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
u8 buf[32];
unsigned int len = 0;
u32 reg_addr;
mutex_lock(&ar->conf_mutex);
reg_addr = ar->debug.reg_addr;
mutex_unlock(&ar->conf_mutex);
len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath10k_reg_addr_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
u32 reg_addr;
int ret;
ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
if (ret)
return ret;
if (!IS_ALIGNED(reg_addr, 4))
return -EFAULT;
mutex_lock(&ar->conf_mutex);
ar->debug.reg_addr = reg_addr;
mutex_unlock(&ar->conf_mutex);
return count;
}
static const struct file_operations fops_reg_addr = {
.read = ath10k_reg_addr_read,
.write = ath10k_reg_addr_write,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath10k_reg_value_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
u8 buf[48];
unsigned int len;
u32 reg_addr, reg_val;
int ret;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON &&
ar->state != ATH10K_STATE_UTF) {
ret = -ENETDOWN;
goto exit;
}
reg_addr = ar->debug.reg_addr;
reg_val = ath10k_hif_read32(ar, reg_addr);
len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static ssize_t ath10k_reg_value_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
u32 reg_addr, reg_val;
int ret;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON &&
ar->state != ATH10K_STATE_UTF) {
ret = -ENETDOWN;
goto exit;
}
reg_addr = ar->debug.reg_addr;
ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
if (ret)
goto exit;
ath10k_hif_write32(ar, reg_addr, reg_val);
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_reg_value = {
.read = ath10k_reg_value_read,
.write = ath10k_reg_value_write,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath10k_mem_value_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
u8 *buf;
int ret;
if (*ppos < 0)
return -EINVAL;
if (!count)
return 0;
mutex_lock(&ar->conf_mutex);
buf = vmalloc(count);
if (!buf) {
ret = -ENOMEM;
goto exit;
}
if (ar->state != ATH10K_STATE_ON &&
ar->state != ATH10K_STATE_UTF) {
ret = -ENETDOWN;
goto exit;
}
ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
if (ret) {
ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n",
(u32)(*ppos), ret);
goto exit;
}
ret = copy_to_user(user_buf, buf, count);
if (ret) {
ret = -EFAULT;
goto exit;
}
count -= ret;
*ppos += count;
ret = count;
exit:
vfree(buf);
mutex_unlock(&ar->conf_mutex);
return ret;
}
static ssize_t ath10k_mem_value_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
u8 *buf;
int ret;
if (*ppos < 0)
return -EINVAL;
if (!count)
return 0;
mutex_lock(&ar->conf_mutex);
buf = vmalloc(count);
if (!buf) {
ret = -ENOMEM;
goto exit;
}
if (ar->state != ATH10K_STATE_ON &&
ar->state != ATH10K_STATE_UTF) {
ret = -ENETDOWN;
goto exit;
}
ret = copy_from_user(buf, user_buf, count);
if (ret) {
ret = -EFAULT;
goto exit;
}
ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
if (ret) {
ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
(u32)(*ppos), ret);
goto exit;
}
*ppos += count;
ret = count;
exit:
vfree(buf);
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_mem_value = {
.read = ath10k_mem_value_read,
.write = ath10k_mem_value_write,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static int ath10k_debug_htt_stats_req(struct ath10k *ar)
{
u64 cookie;
......@@ -1630,6 +1855,15 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_fw_crash_dump);
debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_reg_addr);
debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_reg_value);
debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_mem_value);
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_chip_id);
......
......@@ -35,6 +35,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_BMI = 0x00000400,
ATH10K_DBG_REGULATORY = 0x00000800,
ATH10K_DBG_TESTMODE = 0x00001000,
ATH10K_DBG_WMI_PRINT = 0x00002000,
ATH10K_DBG_ANY = 0xffffffff,
};
......@@ -61,9 +62,6 @@ int ath10k_debug_create(struct ath10k *ar);
void ath10k_debug_destroy(struct ath10k *ar);
int ath10k_debug_register(struct ath10k *ar);
void ath10k_debug_unregister(struct ath10k *ar);
void ath10k_debug_read_service_map(struct ath10k *ar,
const void *service_map,
size_t map_size);
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
struct ath10k_fw_crash_data *
ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
......@@ -108,12 +106,6 @@ static inline void ath10k_debug_unregister(struct ath10k *ar)
{
}
static inline void ath10k_debug_read_service_map(struct ath10k *ar,
const void *service_map,
size_t map_size)
{
}
static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
struct sk_buff *skb)
{
......
......@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include "core.h"
#include "debug.h"
struct ath10k_hif_sg_item {
u16 transfer_id;
......@@ -31,11 +32,9 @@ struct ath10k_hif_sg_item {
struct ath10k_hif_cb {
int (*tx_completion)(struct ath10k *ar,
struct sk_buff *wbuf,
unsigned transfer_id);
struct sk_buff *wbuf);
int (*rx_completion)(struct ath10k *ar,
struct sk_buff *wbuf,
u8 pipe_id);
struct sk_buff *wbuf);
};
struct ath10k_hif_ops {
......@@ -47,6 +46,8 @@ struct ath10k_hif_ops {
int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
size_t buf_len);
int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
int nbytes);
/*
* API to handle HIF-specific BMI message exchanges, this API is
* synchronous and only allowed to be called from a context that
......@@ -84,6 +85,10 @@ struct ath10k_hif_ops {
u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
u32 (*read32)(struct ath10k *ar, u32 address);
void (*write32)(struct ath10k *ar, u32 address, u32 value);
/* Power up the device and enter BMI transfer mode for FW download */
int (*power_up)(struct ath10k *ar);
......@@ -108,6 +113,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
return ar->hif.ops->diag_read(ar, address, buf, buf_len);
}
static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
const void *data, int nbytes)
{
if (!ar->hif.ops->diag_write)
return -EOPNOTSUPP;
return ar->hif.ops->diag_write(ar, address, data, nbytes);
}
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
void *request, u32 request_len,
void *response, u32 *response_len)
......@@ -187,4 +201,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
return ar->hif.ops->resume(ar);
}
static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
{
if (!ar->hif.ops->read32) {
ath10k_warn(ar, "hif read32 not supported\n");
return 0xdeaddead;
}
return ar->hif.ops->read32(ar, address);
}
static inline void ath10k_hif_write32(struct ath10k *ar,
u32 address, u32 data)
{
if (!ar->hif.ops->write32) {
ath10k_warn(ar, "hif write32 not supported\n");
return;
}
ar->hif.ops->write32(ar, address, data);
}
#endif /* _HIF_H_ */
......@@ -160,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
ath10k_htc_prepare_tx_skb(ep, skb);
skb_cb->eid = eid;
skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
ret = dma_mapping_error(dev, skb_cb->paddr);
if (ret)
......@@ -197,15 +198,18 @@ int ath10k_htc_send(struct ath10k_htc *htc,
}
static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
struct sk_buff *skb,
unsigned int eid)
struct sk_buff *skb)
{
struct ath10k_htc *htc = &ar->htc;
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
struct ath10k_skb_cb *skb_cb;
struct ath10k_htc_ep *ep;
if (WARN_ON_ONCE(!skb))
return 0;
skb_cb = ATH10K_SKB_CB(skb);
ep = &htc->endpoint[skb_cb->eid];
ath10k_htc_notify_tx_completion(ep, skb);
/* the skb now belongs to the completion handler */
......@@ -317,8 +321,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
}
static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
struct sk_buff *skb,
u8 pipe_id)
struct sk_buff *skb)
{
int status = 0;
struct ath10k_htc *htc = &ar->htc;
......
......@@ -126,6 +126,7 @@ enum htt_data_tx_ext_tid {
* (HL hosts manage queues on the host )
* more_in_batch: only for HL hosts. indicates if more packets are
* pending. this allows target to wait and aggregate
* freq: 0 means home channel of given vdev. intended for offchannel
*/
struct htt_data_tx_desc {
u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */
......@@ -133,7 +134,8 @@ struct htt_data_tx_desc {
__le16 len;
__le16 id;
__le32 frags_paddr;
__le32 peerid;
__le16 peerid;
__le16 freq;
u8 prefetch[0]; /* start of frame, for FW classification engine */
} __packed;
......@@ -156,6 +158,9 @@ enum htt_rx_ring_flags {
HTT_RX_RING_FLAGS_PHY_DATA_RX = 1 << 15
};
#define HTT_RX_RING_SIZE_MIN 128
#define HTT_RX_RING_SIZE_MAX 2048
struct htt_rx_ring_setup_ring {
__le32 fw_idx_shadow_reg_paddr;
__le32 rx_ring_base_paddr;
......
......@@ -554,13 +554,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID);
skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq);
trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n",
flags0, flags1, msdu->len, msdu_id, frags_paddr,
(u32)skb_cb->paddr, vdev_id, tid);
(u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len);
trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
......
......@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr {
#define TARGET_DMA_BURST_SIZE 0
#define TARGET_MAC_AGGR_DELIM 0
#define TARGET_AST_SKID_LIMIT 16
#define TARGET_NUM_PEERS 16
#define TARGET_NUM_STATIONS 16
#define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \
(TARGET_NUM_VDEVS))
#define TARGET_NUM_OFFLOAD_PEERS 0
#define TARGET_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_NUM_PEER_KEYS 2
#define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS)))
#define TARGET_NUM_TIDS ((TARGET_NUM_PEERS) * 2)
#define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_RX_TIMEOUT_LO_PRI 100
......@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_DMA_BURST_SIZE 0
#define TARGET_10X_MAC_AGGR_DELIM 0
#define TARGET_10X_AST_SKID_LIMIT 16
#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS))
#define TARGET_10X_NUM_PEERS_MAX 128
#define TARGET_10X_NUM_STATIONS 128
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
(TARGET_10X_NUM_VDEVS))
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_10X_NUM_PEER_KEYS 2
#define TARGET_10X_NUM_TIDS 256
#define TARGET_10X_NUM_TIDS_MAX 256
#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
(TARGET_10X_NUM_PEERS) * 2)
#define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_10X_RX_TIMEOUT_LO_PRI 100
......
......@@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
if (ret)
return ret;
spin_lock_bh(&ar->data_lock);
peer->keys[i] = arvif->wep_keys[i];
spin_unlock_bh(&ar->data_lock);
}
return 0;
......@@ -173,12 +175,39 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
i, ret);
spin_lock_bh(&ar->data_lock);
peer->keys[i] = NULL;
spin_unlock_bh(&ar->data_lock);
}
return first_errno;
}
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
u8 keyidx)
{
struct ath10k_peer *peer;
int i;
lockdep_assert_held(&ar->data_lock);
/* We don't know which vdev this peer belongs to,
* since WMI doesn't give us that information.
*
* FIXME: multi-bss needs to be handled.
*/
peer = ath10k_peer_find(ar, 0, addr);
if (!peer)
return false;
for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
if (peer->keys[i] && peer->keys[i]->keyidx == keyidx)
return true;
}
return false;
}
static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key)
{
......@@ -326,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
lockdep_assert_held(&ar->conf_mutex);
if (ar->num_peers >= ar->max_num_peers)
return -ENOBUFS;
ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
if (ret) {
ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
......@@ -339,9 +371,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
addr, vdev_id, ret);
return ret;
}
spin_lock_bh(&ar->data_lock);
ar->num_peers++;
spin_unlock_bh(&ar->data_lock);
return 0;
}
......@@ -391,15 +422,11 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
return 0;
}
static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
{
struct ath10k *ar = arvif->ar;
u32 vdev_param;
if (value != 0xFFFFFFFF)
value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,
ATH10K_RTS_MAX);
vdev_param = ar->wmi.vdev_param->rts_threshold;
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
}
......@@ -432,9 +459,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
if (ret)
return ret;
spin_lock_bh(&ar->data_lock);
ar->num_peers--;
spin_unlock_bh(&ar->data_lock);
return 0;
}
......@@ -471,8 +496,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
list_del(&peer->list);
kfree(peer);
}
ar->num_peers = 0;
spin_unlock_bh(&ar->data_lock);
ar->num_peers = 0;
ar->num_stations = 0;
}
/************************/
......@@ -1997,6 +2024,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
}
}
static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
{
/* FIXME: Not really sure since when the behaviour changed. At some
* point new firmware stopped requiring creation of peer entries for
* offchannel tx (and actually creating them causes issues with wmi-htc
* tx credit replenishment and reliability). Assuming it's at least 3.4
* because that's when the `freq` was introduced to TX_FRM HTT command.
*/
return !(ar->htt.target_version_major >= 3 &&
ar->htt.target_version_minor >= 4);
}
static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
......@@ -2172,10 +2211,10 @@ void __ath10k_scan_finish(struct ath10k *ar)
case ATH10K_SCAN_IDLE:
break;
case ATH10K_SCAN_RUNNING:
case ATH10K_SCAN_ABORTING:
if (ar->scan.is_roc)
ieee80211_remain_on_channel_expired(ar->hw);
else
case ATH10K_SCAN_ABORTING:
if (!ar->scan.is_roc)
ieee80211_scan_completed(ar->hw,
(ar->scan.state ==
ATH10K_SCAN_ABORTING));
......@@ -2341,16 +2380,21 @@ static void ath10k_tx(struct ieee80211_hw *hw,
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
spin_lock_bh(&ar->data_lock);
ATH10K_SKB_CB(skb)->htt.is_offchan = true;
ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq;
ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
spin_unlock_bh(&ar->data_lock);
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
skb);
if (ath10k_mac_need_offchan_tx_work(ar)) {
ATH10K_SKB_CB(skb)->htt.freq = 0;
ATH10K_SKB_CB(skb)->htt.is_offchan = true;
skb_queue_tail(&ar->offchan_tx_queue, skb);
ieee80211_queue_work(hw, &ar->offchan_tx_work);
return;
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
skb);
skb_queue_tail(&ar->offchan_tx_queue, skb);
ieee80211_queue_work(hw, &ar->offchan_tx_work);
return;
}
}
ath10k_tx_htt(ar, skb);
......@@ -2414,12 +2458,28 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
{
/* It is not clear that allowing gaps in chainmask
* is helpful. Probably it will not do what user
* is hoping for, so warn in that case.
*/
if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0)
return;
ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n",
dbg, cm);
}
static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
{
int ret;
lockdep_assert_held(&ar->conf_mutex);
ath10k_check_chain_mask(ar, tx_ant, "tx");
ath10k_check_chain_mask(ar, rx_ant, "rx");
ar->cfg_tx_chainmask = tx_ant;
ar->cfg_rx_chainmask = rx_ant;
......@@ -2782,6 +2842,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
return ret;
}
static u32 get_nss_from_chainmask(u16 chain_mask)
{
if ((chain_mask & 0x15) == 0x15)
return 4;
else if ((chain_mask & 0x7) == 0x7)
return 3;
else if ((chain_mask & 0x3) == 0x3)
return 2;
return 1;
}
/*
* TODO:
* Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE,
......@@ -2914,6 +2985,20 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_vdev_delete;
}
if (ar->cfg_tx_chainmask) {
u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
vdev_param = ar->wmi.vdev_param->nss;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
nss);
if (ret) {
ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n",
arvif->vdev_id, ar->cfg_tx_chainmask, nss,
ret);
goto err_vdev_delete;
}
}
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
if (ret) {
......@@ -3014,10 +3099,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret;
mutex_lock(&ar->conf_mutex);
cancel_work_sync(&arvif->wep_key_work);
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
......@@ -3511,6 +3596,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_unlock(&ar->conf_mutex);
}
static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->conf_mutex);
if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
return 0;
if (ar->num_stations >= ar->max_num_stations)
return -ENOBUFS;
ar->num_stations++;
return 0;
}
static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->conf_mutex);
if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
return;
ar->num_stations--;
}
static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
......@@ -3520,7 +3636,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
int max_num_peers;
int ret = 0;
if (old_state == IEEE80211_STA_NOTEXIST &&
......@@ -3542,26 +3657,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* New station addition.
*/
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
else
max_num_peers = TARGET_NUM_PEERS;
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
arvif->vdev_id, sta->addr,
ar->num_stations + 1, ar->max_num_stations,
ar->num_peers + 1, ar->max_num_peers);
if (ar->num_peers >= max_num_peers) {
ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
ar->num_peers, max_num_peers);
ret = -ENOBUFS;
ret = ath10k_mac_inc_num_stations(arvif);
if (ret) {
ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
ar->max_num_stations);
goto exit;
}
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer create %pM (new sta) num_peers %d\n",
arvif->vdev_id, sta->addr, ar->num_peers);
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
if (ret)
if (ret) {
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
ath10k_mac_dec_num_stations(arvif);
goto exit;
}
if (vif->type == NL80211_IFTYPE_STATION) {
WARN_ON(arvif->is_started);
......@@ -3572,6 +3687,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
sta->addr));
ath10k_mac_dec_num_stations(arvif);
goto exit;
}
......@@ -3602,6 +3718,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
ath10k_mac_dec_num_stations(arvif);
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP ||
......@@ -3790,6 +3907,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
if (ret)
goto exit;
duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC);
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
arg.vdev_id = arvif->vdev_id;
......@@ -4106,6 +4225,10 @@ ath10k_default_bitrate_mask(struct ath10k *ar,
u32 legacy = 0x00ff;
u8 ht = 0xff, i;
u16 vht = 0x3ff;
u16 nrf = ar->num_rf_chains;
if (ar->cfg_tx_chainmask)
nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask);
switch (band) {
case IEEE80211_BAND_2GHZ:
......@@ -4121,11 +4244,11 @@ ath10k_default_bitrate_mask(struct ath10k *ar,
if (mask->control[band].legacy != legacy)
return false;
for (i = 0; i < ar->num_rf_chains; i++)
for (i = 0; i < nrf; i++)
if (mask->control[band].ht_mcs[i] != ht)
return false;
for (i = 0; i < ar->num_rf_chains; i++)
for (i = 0; i < nrf; i++)
if (mask->control[band].vht_mcs[i] != vht)
return false;
......@@ -4376,6 +4499,9 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
u8 fixed_nss = ar->num_rf_chains;
u8 force_sgi;
if (ar->cfg_tx_chainmask)
fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
force_sgi = mask->control[band].gi;
if (force_sgi == NL80211_TXRATE_FORCE_LGI)
return -EINVAL;
......@@ -4905,10 +5031,6 @@ int ath10k_mac_register(struct ath10k *ar)
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_SPECTRUM_MGMT;
/* MSDU can have HTT TX fragment pushed in front. The additional 4
* bytes is used for padding/alignment if necessary. */
ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
......
......@@ -21,6 +21,8 @@
#include <net/mac80211.h>
#include "core.h"
#define WEP_KEYID_SHIFT 6
struct ath10k_generic_iter {
struct ath10k *ar;
int ret;
......@@ -41,6 +43,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
void ath10k_halt(struct ath10k *ar);
void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
void ath10k_drain_tx(struct ath10k *ar);
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
u8 keyidx);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{
......
......@@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
struct ath10k *ar = ce_state->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
void *transfer_context;
struct sk_buff_head list;
struct sk_buff *skb;
u32 ce_data;
unsigned int nbytes;
unsigned int transfer_id;
while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
&ce_data, &nbytes,
&transfer_id) == 0) {
__skb_queue_head_init(&list);
while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data,
&nbytes, &transfer_id) == 0) {
/* no need to call tx completion for NULL pointers */
if (transfer_context == NULL)
if (skb == NULL)
continue;
cb->tx_completion(ar, transfer_context, transfer_id);
__skb_queue_tail(&list, skb);
}
while ((skb = __skb_dequeue(&list)))
cb->tx_completion(ar, skb);
}
/* Called by lower (CE) layer when data is received from the Target. */
......@@ -847,12 +851,14 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
struct sk_buff *skb;
struct sk_buff_head list;
void *transfer_context;
u32 ce_data;
unsigned int nbytes, max_nbytes;
unsigned int transfer_id;
unsigned int flags;
__skb_queue_head_init(&list);
while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
&ce_data, &nbytes, &transfer_id,
&flags) == 0) {
......@@ -869,13 +875,16 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
}
skb_put(skb, nbytes);
__skb_queue_tail(&list, skb);
}
while ((skb = __skb_dequeue(&list))) {
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
ce_state->id, skb->len);
ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
skb->data, skb->len);
cb->rx_completion(ar, skb, pipe_info->pipe_num);
cb->rx_completion(ar, skb);
}
ath10k_pci_rx_post_pipe(pipe_info);
......@@ -1263,7 +1272,7 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
id = MS(__le16_to_cpu(ce_desc[i].flags),
CE_DESC_FLAGS_META_DATA);
ar_pci->msg_callbacks_current.tx_completion(ar, skb, id);
ar_pci->msg_callbacks_current.tx_completion(ar, skb);
}
}
......@@ -1988,6 +1997,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.tx_sg = ath10k_pci_hif_tx_sg,
.diag_read = ath10k_pci_hif_diag_read,
.diag_write = ath10k_pci_diag_write_mem,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
.start = ath10k_pci_hif_start,
.stop = ath10k_pci_hif_stop,
......@@ -1998,6 +2008,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.get_free_queue_number = ath10k_pci_hif_get_free_queue_number,
.power_up = ath10k_pci_hif_power_up,
.power_down = ath10k_pci_hif_power_down,
.read32 = ath10k_pci_read32,
.write32 = ath10k_pci_write32,
#ifdef CONFIG_PM
.suspend = ath10k_pci_hif_suspend,
.resume = ath10k_pci_hif_resume,
......
......@@ -21,9 +21,11 @@
#include "core.h"
#if !defined(_TRACE_H_)
static inline u32 ath10k_frm_hdr_len(void *buf)
static inline u32 ath10k_frm_hdr_len(const void *buf)
{
return ieee80211_hdrlen(((struct ieee80211_hdr *)buf)->frame_control);
const struct ieee80211_hdr *hdr = buf;
return ieee80211_hdrlen(hdr->frame_control);
}
#endif
......@@ -145,7 +147,8 @@ TRACE_EVENT(ath10k_log_dbg_dump,
);
TRACE_EVENT(ath10k_wmi_cmd,
TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len, int ret),
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len,
int ret),
TP_ARGS(ar, id, buf, buf_len, ret),
......@@ -178,7 +181,7 @@ TRACE_EVENT(ath10k_wmi_cmd,
);
TRACE_EVENT(ath10k_wmi_event,
TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len),
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
TP_ARGS(ar, id, buf, buf_len),
......@@ -208,7 +211,7 @@ TRACE_EVENT(ath10k_wmi_event,
);
TRACE_EVENT(ath10k_htt_stats,
TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len),
TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
TP_ARGS(ar, buf, buf_len),
......@@ -235,7 +238,7 @@ TRACE_EVENT(ath10k_htt_stats,
);
TRACE_EVENT(ath10k_wmi_dbglog,
TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len),
TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
TP_ARGS(ar, buf, buf_len),
......@@ -262,7 +265,7 @@ TRACE_EVENT(ath10k_wmi_dbglog,
);
TRACE_EVENT(ath10k_htt_pktlog,
TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len),
TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len),
TP_ARGS(ar, buf, buf_len),
......@@ -349,7 +352,7 @@ TRACE_EVENT(ath10k_txrx_tx_unref,
);
DECLARE_EVENT_CLASS(ath10k_hdr_event,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len),
......@@ -376,7 +379,7 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event,
);
DECLARE_EVENT_CLASS(ath10k_payload_event,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len),
......@@ -404,27 +407,27 @@ DECLARE_EVENT_CLASS(ath10k_payload_event,
);
DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len)
);
DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len)
);
DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len)
);
DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len)
);
TRACE_EVENT(ath10k_htt_rx_desc,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
TP_ARGS(ar, data, len),
......
......@@ -1113,6 +1113,40 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
return rate_idx;
}
/* If keys are configured, HW decrypts all frames
* with protected bit set. Mark such frames as decrypted.
*/
static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
struct sk_buff *skb,
struct ieee80211_rx_status *status)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
unsigned int hdrlen;
bool peer_key;
u8 *addr, keyidx;
if (!ieee80211_is_auth(hdr->frame_control) ||
!ieee80211_has_protected(hdr->frame_control))
return;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN))
return;
keyidx = skb->data[hdrlen + (IEEE80211_WEP_IV_LEN - 1)] >> WEP_KEYID_SHIFT;
addr = ieee80211_get_SA(hdr);
spin_lock_bh(&ar->data_lock);
peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx);
spin_unlock_bh(&ar->data_lock);
if (peer_key) {
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac wep key present for peer %pM\n", addr);
status->flag |= RX_FLAG_DECRYPTED;
}
}
static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_mgmt_rx_event_v1 *ev_v1;
......@@ -1166,8 +1200,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
return 0;
}
if (rx_status & WMI_RX_STATUS_ERR_CRC)
status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (rx_status & WMI_RX_STATUS_ERR_CRC) {
dev_kfree_skb(skb);
return 0;
}
if (rx_status & WMI_RX_STATUS_ERR_MIC)
status->flag |= RX_FLAG_MMIC_ERROR;
......@@ -1200,6 +1237,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control);
ath10k_wmi_handle_wep_reauth(ar, skb, status);
/* FW delivers WEP Shared Auth frame with Protected Bit set and
* encrypted payload. However in case of PMF it delivers decrypted
* frames with Protected Bit set. */
......@@ -2261,7 +2300,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
/* the last byte is always reserved for the null character */
buf[i] = '\0';
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
}
static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
......@@ -2418,6 +2457,7 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
arg->num_mem_reqs = ev->num_mem_reqs;
arg->service_map = ev->wmi_service_bitmap;
arg->service_map_len = sizeof(ev->wmi_service_bitmap);
n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
ARRAY_SIZE(arg->mem_reqs));
......@@ -2452,6 +2492,7 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
arg->num_mem_reqs = ev->num_mem_reqs;
arg->service_map = ev->wmi_service_bitmap;
arg->service_map_len = sizeof(ev->wmi_service_bitmap);
n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
ARRAY_SIZE(arg->mem_reqs));
......@@ -2470,15 +2511,18 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
{
struct wmi_svc_rdy_ev_arg arg = {};
u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
int ret;
memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
wmi_10x_svc_map(arg.service_map, svc_bmap);
wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map,
arg.service_map_len);
} else {
ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
wmi_main_svc_map(arg.service_map, svc_bmap);
wmi_main_svc_map(arg.service_map, ar->wmi.svc_map,
arg.service_map_len);
}
if (ret) {
......@@ -2500,9 +2544,8 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
arg.service_map, sizeof(arg.service_map));
arg.service_map, arg.service_map_len);
/* only manually set fw features when not using FW IE format */
if (ar->fw_api == 1 && ar->fw_version_build > 636)
......@@ -3142,7 +3185,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
u32 len, val;
config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS);
config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS);
config.num_offload_reorder_bufs =
......
......@@ -222,128 +222,131 @@ static inline char *wmi_service_name(int service_id)
#undef SVCSTR
}
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
(__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
((svc_id) < (len) && \
__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
BIT((svc_id)%(sizeof(u32))))
#define SVCMAP(x, y) \
#define SVCMAP(x, y, len) \
do { \
if (WMI_SERVICE_IS_ENABLED((in), (x))) \
if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \
__set_bit(y, out); \
} while (0)
static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out)
static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
size_t len)
{
SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
WMI_SERVICE_BEACON_OFFLOAD);
WMI_SERVICE_BEACON_OFFLOAD, len);
SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
WMI_SERVICE_SCAN_OFFLOAD);
WMI_SERVICE_SCAN_OFFLOAD, len);
SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
WMI_SERVICE_ROAM_OFFLOAD);
WMI_SERVICE_ROAM_OFFLOAD, len);
SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
WMI_SERVICE_BCN_MISS_OFFLOAD);
WMI_SERVICE_BCN_MISS_OFFLOAD, len);
SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
WMI_SERVICE_STA_PWRSAVE);
WMI_SERVICE_STA_PWRSAVE, len);
SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
WMI_SERVICE_STA_ADVANCED_PWRSAVE);
WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
WMI_SERVICE_AP_UAPSD);
WMI_SERVICE_AP_UAPSD, len);
SVCMAP(WMI_10X_SERVICE_AP_DFS,
WMI_SERVICE_AP_DFS);
WMI_SERVICE_AP_DFS, len);
SVCMAP(WMI_10X_SERVICE_11AC,
WMI_SERVICE_11AC);
WMI_SERVICE_11AC, len);
SVCMAP(WMI_10X_SERVICE_BLOCKACK,
WMI_SERVICE_BLOCKACK);
WMI_SERVICE_BLOCKACK, len);
SVCMAP(WMI_10X_SERVICE_PHYERR,
WMI_SERVICE_PHYERR);
WMI_SERVICE_PHYERR, len);
SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
WMI_SERVICE_BCN_FILTER);
WMI_SERVICE_BCN_FILTER, len);
SVCMAP(WMI_10X_SERVICE_RTT,
WMI_SERVICE_RTT);
WMI_SERVICE_RTT, len);
SVCMAP(WMI_10X_SERVICE_RATECTRL,
WMI_SERVICE_RATECTRL);
WMI_SERVICE_RATECTRL, len);
SVCMAP(WMI_10X_SERVICE_WOW,
WMI_SERVICE_WOW);
WMI_SERVICE_WOW, len);
SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
WMI_SERVICE_RATECTRL_CACHE);
WMI_SERVICE_RATECTRL_CACHE, len);
SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
WMI_SERVICE_IRAM_TIDS);
WMI_SERVICE_IRAM_TIDS, len);
SVCMAP(WMI_10X_SERVICE_BURST,
WMI_SERVICE_BURST);
WMI_SERVICE_BURST, len);
SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len);
SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
WMI_SERVICE_FORCE_FW_HANG);
WMI_SERVICE_FORCE_FW_HANG, len);
SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len);
}
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out)
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
size_t len)
{
SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
WMI_SERVICE_BEACON_OFFLOAD);
WMI_SERVICE_BEACON_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
WMI_SERVICE_SCAN_OFFLOAD);
WMI_SERVICE_SCAN_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
WMI_SERVICE_ROAM_OFFLOAD);
WMI_SERVICE_ROAM_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
WMI_SERVICE_BCN_MISS_OFFLOAD);
WMI_SERVICE_BCN_MISS_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
WMI_SERVICE_STA_PWRSAVE);
WMI_SERVICE_STA_PWRSAVE, len);
SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
WMI_SERVICE_STA_ADVANCED_PWRSAVE);
WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
WMI_SERVICE_AP_UAPSD);
WMI_SERVICE_AP_UAPSD, len);
SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
WMI_SERVICE_AP_DFS);
WMI_SERVICE_AP_DFS, len);
SVCMAP(WMI_MAIN_SERVICE_11AC,
WMI_SERVICE_11AC);
WMI_SERVICE_11AC, len);
SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
WMI_SERVICE_BLOCKACK);
WMI_SERVICE_BLOCKACK, len);
SVCMAP(WMI_MAIN_SERVICE_PHYERR,
WMI_SERVICE_PHYERR);
WMI_SERVICE_PHYERR, len);
SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
WMI_SERVICE_BCN_FILTER);
WMI_SERVICE_BCN_FILTER, len);
SVCMAP(WMI_MAIN_SERVICE_RTT,
WMI_SERVICE_RTT);
WMI_SERVICE_RTT, len);
SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
WMI_SERVICE_RATECTRL);
WMI_SERVICE_RATECTRL, len);
SVCMAP(WMI_MAIN_SERVICE_WOW,
WMI_SERVICE_WOW);
WMI_SERVICE_WOW, len);
SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
WMI_SERVICE_RATECTRL_CACHE);
WMI_SERVICE_RATECTRL_CACHE, len);
SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
WMI_SERVICE_IRAM_TIDS);
WMI_SERVICE_IRAM_TIDS, len);
SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
WMI_SERVICE_ARPNS_OFFLOAD);
WMI_SERVICE_ARPNS_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_NLO,
WMI_SERVICE_NLO);
WMI_SERVICE_NLO, len);
SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
WMI_SERVICE_GTK_OFFLOAD);
WMI_SERVICE_GTK_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
WMI_SERVICE_SCAN_SCH);
WMI_SERVICE_SCAN_SCH, len);
SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
WMI_SERVICE_CSA_OFFLOAD);
WMI_SERVICE_CSA_OFFLOAD, len);
SVCMAP(WMI_MAIN_SERVICE_CHATTER,
WMI_SERVICE_CHATTER);
WMI_SERVICE_CHATTER, len);
SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
WMI_SERVICE_COEX_FREQAVOID);
WMI_SERVICE_COEX_FREQAVOID, len);
SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
WMI_SERVICE_PACKET_POWER_SAVE);
WMI_SERVICE_PACKET_POWER_SAVE, len);
SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
WMI_SERVICE_FORCE_FW_HANG);
WMI_SERVICE_FORCE_FW_HANG, len);
SVCMAP(WMI_MAIN_SERVICE_GPIO,
WMI_SERVICE_GPIO);
WMI_SERVICE_GPIO, len);
SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len);
SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len);
SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len);
SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
WMI_SERVICE_STA_KEEP_ALIVE);
WMI_SERVICE_STA_KEEP_ALIVE, len);
SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
WMI_SERVICE_TX_ENCAP);
WMI_SERVICE_TX_ENCAP, len);
}
#undef SVCMAP
......@@ -1952,6 +1955,11 @@ struct wmi_ssid_list {
#define WLAN_SCAN_PARAMS_MAX_BSSID 4
#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256
/* Values lower than this may be refused by some firmware revisions with a scan
* completion with a timedout reason.
*/
#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40
/* Scan priority numbers must be sequential, starting with 0 */
enum wmi_scan_priority {
WMI_SCAN_PRIORITY_VERY_LOW = 0,
......@@ -4547,7 +4555,6 @@ struct wmi_dbglog_cfg_cmd {
__le32 config_valid;
} __packed;
#define ATH10K_RTS_MAX 2347
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
......@@ -4572,6 +4579,7 @@ struct wmi_svc_rdy_ev_arg {
__le32 eeprom_rd;
__le32 num_mem_reqs;
const __le32 *service_map;
size_t service_map_len;
const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
};
......
......@@ -225,13 +225,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
} else {
switch (queue_type) {
case AR5K_TX_QUEUE_DATA:
for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
ah->ah_txq[queue].tqi_type !=
AR5K_TX_QUEUE_INACTIVE; queue++) {
if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
return -EINVAL;
}
queue = queue_info->tqi_subtype;
break;
case AR5K_TX_QUEUE_UAPSD:
queue = AR5K_TX_QUEUE_ID_UAPSD;
......
......@@ -281,7 +281,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen)
| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(i->txpower, AR_XmitPower0)
| SM(i->txpower[0], AR_XmitPower0)
| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
......@@ -307,9 +307,9 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
| set11nRateFlags(i->rates, 3)
| SM(i->rtscts_rate, AR_RTSCTSRate);
ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower, AR_XmitPower1);
ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower, AR_XmitPower2);
ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower, AR_XmitPower3);
ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower[1], AR_XmitPower1);
ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower[2], AR_XmitPower2);
ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower[3], AR_XmitPower3);
}
static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
......
......@@ -4377,6 +4377,25 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah,
targetPowerArray, numPiers);
}
static void ar9003_hw_selfgen_tpc_txpower(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 *pwr_array)
{
u32 val;
/* target power values for self generated frames (ACK,RTS/CTS) */
if (IS_CHAN_2GHZ(chan)) {
val = SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) |
SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) |
SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT);
} else {
val = SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) |
SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) |
SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT);
}
REG_WRITE(ah, AR_TPC, val);
}
/* Set tx power registers to array of values passed in */
static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
{
......@@ -5312,6 +5331,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
struct ar9300_modal_eep_header *modal_hdr;
u8 targetPowerValT2[ar9300RateSize];
u8 target_power_val_t2_eep[ar9300RateSize];
u8 targetPowerValT2_tpc[ar9300RateSize];
unsigned int i = 0, paprd_scale_factor = 0;
u8 pwr_idx, min_pwridx = 0;
......@@ -5363,6 +5383,9 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
twiceAntennaReduction,
powerLimit);
memcpy(targetPowerValT2_tpc, targetPowerValT2,
sizeof(targetPowerValT2));
if (ar9003_is_paprd_enabled(ah)) {
for (i = 0; i < ar9300RateSize; i++) {
if ((ah->paprd_ratemask & (1 << i)) &&
......@@ -5396,6 +5419,30 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
ar9003_hw_calibration_apply(ah, chan->channel);
ar9003_paprd_set_txpower(ah, chan, targetPowerValT2);
ar9003_hw_selfgen_tpc_txpower(ah, chan, targetPowerValT2);
/* TPC initializations */
if (ah->tpc_enabled) {
u32 val;
ar9003_hw_init_rate_txpower(ah, targetPowerValT2_tpc, chan);
/* Enable TPC */
REG_WRITE(ah, AR_PHY_PWRTX_MAX,
AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
/* Disable per chain power reduction */
val = REG_READ(ah, AR_PHY_POWER_TX_SUB);
if (AR_SREV_9340(ah))
REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
val & 0xFFFFFFC0);
else
REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
val & 0xFFFFF000);
} else {
/* Disable TPC */
REG_WRITE(ah, AR_PHY_PWRTX_MAX, 0);
}
}
static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
......
......@@ -101,7 +101,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen)
| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(i->txpower, AR_XmitPower0)
| SM(i->txpower[0], AR_XmitPower0)
| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0)
......@@ -152,9 +152,9 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding;
ACCESS_ONCE(ads->ctl20) = SM(i->txpower, AR_XmitPower1);
ACCESS_ONCE(ads->ctl21) = SM(i->txpower, AR_XmitPower2);
ACCESS_ONCE(ads->ctl22) = SM(i->txpower, AR_XmitPower3);
ACCESS_ONCE(ads->ctl20) = SM(i->txpower[1], AR_XmitPower1);
ACCESS_ONCE(ads->ctl21) = SM(i->txpower[2], AR_XmitPower2);
ACCESS_ONCE(ads->ctl22) = SM(i->txpower[3], AR_XmitPower3);
}
static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
......
......@@ -18,6 +18,21 @@
#include "hw.h"
#include "ar9003_phy.h"
#define AR9300_OFDM_RATES 8
#define AR9300_HT_SS_RATES 8
#define AR9300_HT_DS_RATES 8
#define AR9300_HT_TS_RATES 8
#define AR9300_11NA_OFDM_SHIFT 0
#define AR9300_11NA_HT_SS_SHIFT 8
#define AR9300_11NA_HT_DS_SHIFT 16
#define AR9300_11NA_HT_TS_SHIFT 24
#define AR9300_11NG_OFDM_SHIFT 4
#define AR9300_11NG_HT_SS_SHIFT 12
#define AR9300_11NG_HT_DS_SHIFT 20
#define AR9300_11NG_HT_TS_SHIFT 28
static const int firstep_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
......@@ -40,6 +55,71 @@ static const int m2ThreshLowExt_off = 127;
static const int m1ThreshExt_off = 127;
static const int m2ThreshExt_off = 127;
static const u8 ofdm2pwr[] = {
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_36,
ALL_TARGET_LEGACY_48,
ALL_TARGET_LEGACY_54
};
static const u8 mcs2pwr_ht20[] = {
ALL_TARGET_HT20_0_8_16,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_4,
ALL_TARGET_HT20_5,
ALL_TARGET_HT20_6,
ALL_TARGET_HT20_7,
ALL_TARGET_HT20_0_8_16,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_12,
ALL_TARGET_HT20_13,
ALL_TARGET_HT20_14,
ALL_TARGET_HT20_15,
ALL_TARGET_HT20_0_8_16,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_1_3_9_11_17_19,
ALL_TARGET_HT20_20,
ALL_TARGET_HT20_21,
ALL_TARGET_HT20_22,
ALL_TARGET_HT20_23
};
static const u8 mcs2pwr_ht40[] = {
ALL_TARGET_HT40_0_8_16,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_4,
ALL_TARGET_HT40_5,
ALL_TARGET_HT40_6,
ALL_TARGET_HT40_7,
ALL_TARGET_HT40_0_8_16,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_12,
ALL_TARGET_HT40_13,
ALL_TARGET_HT40_14,
ALL_TARGET_HT40_15,
ALL_TARGET_HT40_0_8_16,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_1_3_9_11_17_19,
ALL_TARGET_HT40_20,
ALL_TARGET_HT40_21,
ALL_TARGET_HT40_22,
ALL_TARGET_HT40_23,
};
/**
* ar9003_hw_set_channel - set channel on single-chip device
* @ah: atheros hardware structure
......@@ -1799,6 +1879,100 @@ static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower)
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0));
}
static void ar9003_hw_init_txpower_cck(struct ath_hw *ah, u8 *rate_array)
{
ah->tx_power[0] = rate_array[ALL_TARGET_LEGACY_1L_5L];
ah->tx_power[1] = rate_array[ALL_TARGET_LEGACY_1L_5L];
ah->tx_power[2] = min(rate_array[ALL_TARGET_LEGACY_1L_5L],
rate_array[ALL_TARGET_LEGACY_5S]);
ah->tx_power[3] = min(rate_array[ALL_TARGET_LEGACY_11L],
rate_array[ALL_TARGET_LEGACY_11S]);
}
static void ar9003_hw_init_txpower_ofdm(struct ath_hw *ah, u8 *rate_array,
int offset)
{
int i, j;
for (i = offset; i < offset + AR9300_OFDM_RATES; i++) {
/* OFDM rate to power table idx */
j = ofdm2pwr[i - offset];
ah->tx_power[i] = rate_array[j];
}
}
static void ar9003_hw_init_txpower_ht(struct ath_hw *ah, u8 *rate_array,
int ss_offset, int ds_offset,
int ts_offset, bool is_40)
{
int i, j, mcs_idx = 0;
const u8 *mcs2pwr = (is_40) ? mcs2pwr_ht40 : mcs2pwr_ht20;
for (i = ss_offset; i < ss_offset + AR9300_HT_SS_RATES; i++) {
j = mcs2pwr[mcs_idx];
ah->tx_power[i] = rate_array[j];
mcs_idx++;
}
for (i = ds_offset; i < ds_offset + AR9300_HT_DS_RATES; i++) {
j = mcs2pwr[mcs_idx];
ah->tx_power[i] = rate_array[j];
mcs_idx++;
}
for (i = ts_offset; i < ts_offset + AR9300_HT_TS_RATES; i++) {
j = mcs2pwr[mcs_idx];
ah->tx_power[i] = rate_array[j];
mcs_idx++;
}
}
static void ar9003_hw_init_txpower_stbc(struct ath_hw *ah, int ss_offset,
int ds_offset, int ts_offset)
{
memcpy(&ah->tx_power_stbc[ss_offset], &ah->tx_power[ss_offset],
AR9300_HT_SS_RATES);
memcpy(&ah->tx_power_stbc[ds_offset], &ah->tx_power[ds_offset],
AR9300_HT_DS_RATES);
memcpy(&ah->tx_power_stbc[ts_offset], &ah->tx_power[ts_offset],
AR9300_HT_TS_RATES);
}
void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
struct ath9k_channel *chan)
{
if (IS_CHAN_5GHZ(chan)) {
ar9003_hw_init_txpower_ofdm(ah, rate_array,
AR9300_11NA_OFDM_SHIFT);
if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
ar9003_hw_init_txpower_ht(ah, rate_array,
AR9300_11NA_HT_SS_SHIFT,
AR9300_11NA_HT_DS_SHIFT,
AR9300_11NA_HT_TS_SHIFT,
IS_CHAN_HT40(chan));
ar9003_hw_init_txpower_stbc(ah,
AR9300_11NA_HT_SS_SHIFT,
AR9300_11NA_HT_DS_SHIFT,
AR9300_11NA_HT_TS_SHIFT);
}
} else {
ar9003_hw_init_txpower_cck(ah, rate_array);
ar9003_hw_init_txpower_ofdm(ah, rate_array,
AR9300_11NG_OFDM_SHIFT);
if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
ar9003_hw_init_txpower_ht(ah, rate_array,
AR9300_11NG_HT_SS_SHIFT,
AR9300_11NG_HT_DS_SHIFT,
AR9300_11NG_HT_TS_SHIFT,
IS_CHAN_HT40(chan));
ar9003_hw_init_txpower_stbc(ah,
AR9300_11NG_HT_SS_SHIFT,
AR9300_11NG_HT_DS_SHIFT,
AR9300_11NG_HT_TS_SHIFT);
}
}
}
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
......
......@@ -189,6 +189,7 @@ struct ath_frame_info {
u8 rtscts_rate;
u8 retries : 7;
u8 baw_tracked : 1;
u8 tx_power;
};
struct ath_rxbuf {
......
......@@ -78,7 +78,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_tx_info info;
struct ieee80211_supported_band *sband;
u8 chainmask = ah->txchainmask;
u8 rate = 0;
u8 i, rate = 0;
sband = &common->sbands[sc->cur_chandef.chan->band];
rate = sband->bitrates[rateidx].hw_value;
......@@ -88,7 +88,8 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
memset(&info, 0, sizeof(info));
info.pkt_len = skb->len + FCS_LEN;
info.type = ATH9K_PKT_TYPE_BEACON;
info.txpower = MAX_RATE_POWER;
for (i = 0; i < 4; i++)
info.txpower[i] = MAX_RATE_POWER;
info.keyix = ATH9K_TXKEYIX_INVALID;
info.keytype = ATH9K_KEY_TYPE_CLEAR;
info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
......
......@@ -217,8 +217,8 @@
#define AH_WOW_BEACON_MISS BIT(3)
enum ath_hw_txq_subtype {
ATH_TXQ_AC_BE = 0,
ATH_TXQ_AC_BK = 1,
ATH_TXQ_AC_BK = 0,
ATH_TXQ_AC_BE = 1,
ATH_TXQ_AC_VI = 2,
ATH_TXQ_AC_VO = 3,
};
......@@ -940,6 +940,10 @@ struct ath_hw {
const struct firmware *eeprom_blob;
struct ath_dynack dynack;
bool tpc_enabled;
u8 tx_power[Ar5416RateSize];
u8 tx_power_stbc[Ar5416RateSize];
};
struct ath_bus_ops {
......@@ -1080,6 +1084,8 @@ int ar9003_paprd_init_table(struct ath_hw *ah);
bool ar9003_paprd_is_done(struct ath_hw *ah);
bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
struct ath9k_channel *chan);
/* Hardware family op attach helpers */
int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
......
......@@ -532,10 +532,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->reg_ops.read = ath9k_ioread32;
ah->reg_ops.write = ath9k_iowrite32;
ah->reg_ops.rmw = ath9k_reg_rmw;
sc->sc_ah = ah;
pCap = &ah->caps;
common = ath9k_hw_common(ah);
/* Will be cleared in ath9k_start() */
set_bit(ATH_OP_INVALID, &common->op_flags);
sc->sc_ah = ah;
sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
sc->tx99_power = MAX_RATE_POWER + 1;
init_waitqueue_head(&sc->tx_wait);
......@@ -896,9 +900,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
common = ath9k_hw_common(ah);
ath9k_set_hw_capab(sc, hw);
/* Will be cleared in ath9k_start() */
set_bit(ATH_OP_INVALID, &common->op_flags);
/* Initialize regulatory */
error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
......
......@@ -311,14 +311,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
q = ATH9K_NUM_TX_QUEUES - 3;
break;
case ATH9K_TX_QUEUE_DATA:
for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++)
if (ah->txq[q].tqi_type ==
ATH9K_TX_QUEUE_INACTIVE)
break;
if (q == ATH9K_NUM_TX_QUEUES) {
ath_err(common, "No available TX queue\n");
return -1;
}
q = qinfo->tqi_subtype;
break;
default:
ath_err(common, "Invalid TX queue type: %u\n", type);
......
......@@ -704,7 +704,7 @@ struct ath_tx_info {
enum ath9k_pkt_type type;
enum ath9k_key_type keytype;
u8 keyix;
u8 txpower;
u8 txpower[4];
};
struct ath_hw;
......
......@@ -512,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev)
if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
return IRQ_NONE;
/* shared irq, not for us */
if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
return IRQ_NONE;
/* shared irq, not for us */
if (!ath9k_hw_intrpend(ah))
return IRQ_NONE;
if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
ath9k_hw_kill_interrupts(ah);
return IRQ_HANDLED;
}
/*
* Figure out the reason(s) for the interrupt. Note
* that the hal returns a pseudo-ISR that may include
......@@ -532,6 +529,9 @@ irqreturn_t ath_isr(int irq, void *dev)
ath9k_debug_sync_cause(sc, sync_cause);
status &= ah->imask; /* discard unasked-for bits */
if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
return IRQ_HANDLED;
/*
* If there are no status bits set, then this interrupt was not
* for me (should have been caught above).
......@@ -613,6 +613,7 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int r;
ath9k_hw_kill_interrupts(sc->sc_ah);
set_bit(ATH_OP_HW_RESET, &common->op_flags);
ath9k_ps_wakeup(sc);
......@@ -633,6 +634,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
#ifdef CONFIG_ATH9K_DEBUGFS
RESET_STAT_INC(sc, type);
#endif
ath9k_hw_kill_interrupts(sc->sc_ah);
set_bit(ATH_OP_HW_RESET, &common->op_flags);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
}
......@@ -887,6 +889,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
&sc->cur_chan->chandef);
ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
set_bit(ATH_OP_INVALID, &common->op_flags);
ath9k_hw_phy_disable(ah);
ath9k_hw_configpcipowersave(ah, true);
......@@ -895,7 +900,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_ps_restore(sc);
set_bit(ATH_OP_INVALID, &common->op_flags);
sc->ps_idle = prev_idle;
mutex_unlock(&sc->mutex);
......
......@@ -1724,6 +1724,8 @@ enum {
#define AR_TPC_CTS_S 8
#define AR_TPC_CHIRP 0x003f0000
#define AR_TPC_CHIRP_S 16
#define AR_TPC_RPT 0x3f000000
#define AR_TPC_RPT_S 24
#define AR_QUIET1 0x80fc
#define AR_QUIET1_NEXT_QUIET_S 0
......
......@@ -1096,6 +1096,37 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
}
}
static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
u8 rateidx)
{
u8 max_power;
struct ath_hw *ah = sc->sc_ah;
if (sc->tx99_state)
return MAX_RATE_POWER;
if (!AR_SREV_9300_20_OR_LATER(ah)) {
/* ar9002 is not sipported for the moment */
return MAX_RATE_POWER;
}
if (!bf->bf_state.bfs_paprd) {
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
max_power = min(ah->tx_power_stbc[rateidx],
fi->tx_power);
else
max_power = min(ah->tx_power[rateidx], fi->tx_power);
} else {
max_power = ah->paprd_training_power;
}
return max_power;
}
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_info *info, int len, bool rts)
{
......@@ -1166,6 +1197,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
is_40, is_sgi, is_sp);
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
continue;
}
......@@ -1193,6 +1226,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
phy, rate->bitrate * 100, len, rix, is_sp);
info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
}
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
......@@ -1239,7 +1274,6 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
memset(&info, 0, sizeof(info));
info.is_first = true;
info.is_last = true;
info.txpower = MAX_RATE_POWER;
info.qcu = txq->axq_qnum;
while (bf) {
......@@ -2063,6 +2097,7 @@ static void setup_frame_info(struct ieee80211_hw *hw,
fi->keyix = ATH9K_TXKEYIX_INVALID;
fi->keytype = keytype;
fi->framelen = framelen;
fi->tx_power = MAX_RATE_POWER;
if (!rate)
return;
......
......@@ -86,7 +86,7 @@ static const struct radar_detector_specs fcc_radar_ref_types[] = {
FCC_PATTERN(1, 0, 5, 150, 230, 1, 23),
FCC_PATTERN(2, 6, 10, 200, 500, 1, 16),
FCC_PATTERN(3, 11, 20, 200, 500, 1, 12),
FCC_PATTERN(4, 50, 100, 1000, 2000, 20, 1),
FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 20),
FCC_PATTERN(5, 0, 1, 333, 333, 1, 9),
};
......@@ -105,7 +105,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
JP_PATTERN(4, 0, 5, 150, 230, 1, 23),
JP_PATTERN(5, 6, 10, 200, 500, 1, 16),
JP_PATTERN(6, 11, 20, 200, 500, 1, 12),
JP_PATTERN(7, 50, 100, 1000, 2000, 20, 1),
JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20),
JP_PATTERN(5, 0, 1, 333, 333, 1, 9),
};
......
......@@ -798,7 +798,7 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, params->mac, false);
wil6210_disconnect(wil, params->mac, params->reason_code, false);
mutex_unlock(&wil->mutex);
return 0;
......
......@@ -32,6 +32,23 @@ void wil_err(struct wil6210_priv *wil, const char *fmt, ...)
va_end(args);
}
void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
{
if (net_ratelimit()) {
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
netdev_err(ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
}
}
void wil_info(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
......
......@@ -573,8 +573,10 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
if (!frame)
return -ENOMEM;
if (copy_from_user(frame, buf, len))
if (copy_from_user(frame, buf, len)) {
kfree(frame);
return -EIO;
}
params.buf = frame;
params.len = len;
......@@ -614,8 +616,10 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
return -ENOMEM;
rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
if (rc < 0)
if (rc < 0) {
kfree(wmi);
return rc;
}
cmd = &wmi[1];
cmdid = le16_to_cpu(wmi->id);
......
......@@ -15,7 +15,6 @@
*/
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/crc32.h>
#include "wil6210.h"
#include "fw.h"
......
......@@ -446,7 +446,7 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
if (size >= sizeof(*hdr)) {
wil_err_fw(wil, "Stop at offset %ld"
" record type %d [%zd bytes]\n",
(const void *)hdr - data,
(long)((const void *)hdr - data),
le16_to_cpu(hdr->type), hdr_sz);
}
return -EINVAL;
......@@ -471,7 +471,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name)
size_t sz;
const void *d;
rc = request_firmware(&fw, name, wil_to_pcie_dev(wil));
rc = request_firmware(&fw, name, wil_to_dev(wil));
if (rc) {
wil_err_fw(wil, "Failed to load firmware %s\n", name);
return rc;
......
......@@ -36,7 +36,8 @@
*/
#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
#define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE
#define WIL6210_IMC_RX (BIT_DMA_EP_RX_ICR_RX_DONE | \
BIT_DMA_EP_RX_ICR_RX_HTRSH)
#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \
......@@ -171,6 +172,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
u32 isr = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
bool need_unmask = true;
trace_wil6210_irq_rx(isr);
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
......@@ -182,12 +184,24 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil6210_mask_irq_rx(wil);
if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
/* RX_DONE and RX_HTRSH interrupts are the same if interrupt
* moderation is not used. Interrupt moderation may cause RX
* buffer overflow while RX_DONE is delayed. The required
* action is always the same - should empty the accumulated
* packets from the RX ring.
*/
if (isr & (BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH)) {
wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)
wil_err_ratelimited(wil, "Received \"Rx buffer is in risk "
"of overflow\" interrupt\n");
isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH);
if (test_bit(wil_status_reset_done, &wil->status)) {
if (test_bit(wil_status_napi_en, &wil->status)) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_rx);
} else {
wil_err(wil, "Got Rx interrupt while "
......@@ -204,6 +218,10 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
/* Rx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_rx);
if (unlikely(need_unmask))
wil6210_unmask_irq_rx(wil);
return IRQ_HANDLED;
}
......@@ -213,6 +231,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
u32 isr = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
bool need_unmask = true;
trace_wil6210_irq_tx(isr);
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
......@@ -231,6 +250,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
isr &= ~(BIT(25) - 1UL);
if (test_bit(wil_status_reset_done, &wil->status)) {
wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_tx);
} else {
wil_err(wil, "Got Tx interrupt while in reset\n");
......@@ -243,6 +263,10 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
/* Tx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_tx);
if (unlikely(need_unmask))
wil6210_unmask_irq_tx(wil);
return IRQ_HANDLED;
}
......
......@@ -67,6 +67,36 @@ static struct kernel_param_ops mtu_max_ops = {
module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO);
MODULE_PARM_DESC(mtu_max, " Max MTU value.");
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
static int ring_order_set(const char *val, const struct kernel_param *kp)
{
int ret;
uint x;
ret = kstrtouint(val, 0, &x);
if (ret)
return ret;
if ((x < WIL_RING_SIZE_ORDER_MIN) || (x > WIL_RING_SIZE_ORDER_MAX))
return -EINVAL;
*((uint *)kp->arg) = x;
return 0;
}
static struct kernel_param_ops ring_order_ops = {
.set = ring_order_set,
.get = param_get_uint,
};
module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
......@@ -104,7 +134,7 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
}
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
bool from_event)
u16 reason_code, bool from_event)
{
uint i;
struct net_device *ndev = wil_to_ndev(wil);
......@@ -117,8 +147,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
sta->data_port_open = false;
if (sta->status != wil_sta_unused) {
if (!from_event)
wmi_disconnect_sta(wil, sta->addr,
WLAN_REASON_DEAUTH_LEAVING);
wmi_disconnect_sta(wil, sta->addr, reason_code);
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
......@@ -152,7 +181,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
}
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
bool from_event)
u16 reason_code, bool from_event)
{
int cid = -ENOENT;
struct net_device *ndev = wil_to_ndev(wil);
......@@ -167,10 +196,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
}
if (cid >= 0) /* disconnect 1 peer */
wil_disconnect_cid(wil, cid, from_event);
wil_disconnect_cid(wil, cid, reason_code, from_event);
else /* disconnect all */
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
wil_disconnect_cid(wil, cid, from_event);
wil_disconnect_cid(wil, cid, reason_code, from_event);
/* link state */
switch (wdev->iftype) {
......@@ -179,8 +208,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
wil_link_off(wil);
if (test_bit(wil_status_fwconnected, &wil->status)) {
clear_bit(wil_status_fwconnected, &wil->status);
cfg80211_disconnected(ndev,
WLAN_STATUS_UNSPECIFIED_FAILURE,
cfg80211_disconnected(ndev, reason_code,
NULL, 0, GFP_KERNEL);
} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
......@@ -200,7 +228,7 @@ static void wil_disconnect_worker(struct work_struct *work)
struct wil6210_priv, disconnect_worker);
mutex_lock(&wil->mutex);
_wil6210_disconnect(wil, NULL, false);
_wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false);
mutex_unlock(&wil->mutex);
}
......@@ -222,6 +250,7 @@ static void wil_scan_timer_fn(ulong x)
clear_bit(wil_status_fwready, &wil->status);
wil_err(wil, "Scan timeout detected, start fw error recovery\n");
wil->recovery_state = fw_recovery_pending;
schedule_work(&wil->fw_error_worker);
}
......@@ -333,7 +362,7 @@ static void wil_connect_worker(struct work_struct *work)
wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
wil->pending_connect_cid = -1;
if (rc == 0) {
wil->sta[cid].status = wil_sta_connected;
......@@ -392,18 +421,19 @@ int wil_priv_init(struct wil6210_priv *wil)
* wil6210_disconnect - disconnect one connection
* @wil: driver context
* @bssid: peer to disconnect, NULL to disconnect all
* @reason_code: Reason code for the Disassociation frame
* @from_event: whether is invoked from FW event handler
*
* Disconnect and release associated resources. If invoked not from the
* FW event handler, issue WMI command(s) to trigger MAC disconnect.
*/
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
bool from_event)
u16 reason_code, bool from_event)
{
wil_dbg_misc(wil, "%s()\n", __func__);
del_timer_sync(&wil->connect_timer);
_wil6210_disconnect(wil, bssid, from_event);
_wil6210_disconnect(wil, bssid, reason_code, from_event);
}
void wil_priv_deinit(struct wil6210_priv *wil)
......@@ -415,7 +445,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, NULL, false);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
destroy_workqueue(wil->wmi_wq_conn);
......@@ -463,6 +493,9 @@ static int wil_target_reset(struct wil6210_priv *wil)
wil_halt_cpu(wil);
/* Clear Fw Download notification */
C(RGF_USER_USAGE_6, BIT(0));
if (is_sparrow) {
S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
/* XTAL stabilization should take about 3ms */
......@@ -600,7 +633,7 @@ int wil_reset(struct wil6210_priv *wil)
WARN_ON(test_bit(wil_status_napi_en, &wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, false);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
wil->status = 0; /* prevent NAPI from being scheduled */
......@@ -705,7 +738,7 @@ int __wil_up(struct wil6210_priv *wil)
return rc;
/* Rx VRING. After MAC and beacon */
rc = wil_rx_init(wil);
rc = wil_rx_init(wil, 1 << rx_ring_order);
if (rc)
return rc;
......
......@@ -210,8 +210,6 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d = &vring->va[i].rx;
dma_addr_t pa;
/* TODO align */
struct sk_buff *skb = dev_alloc_skb(sz + headroom);
if (unlikely(!skb))
......@@ -596,7 +594,7 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
wil_rx_refill(wil, v->size);
}
int wil_rx_init(struct wil6210_priv *wil)
int wil_rx_init(struct wil6210_priv *wil, u16 size)
{
struct vring *vring = &wil->vring_rx;
int rc;
......@@ -608,7 +606,7 @@ int wil_rx_init(struct wil6210_priv *wil)
return -EINVAL;
}
vring->size = WIL6210_RX_RING_SIZE;
vring->size = size;
rc = wil_vring_alloc(wil, vring);
if (rc)
return rc;
......@@ -928,8 +926,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_dbg_txrx(wil, "%s()\n", __func__);
if (avail < 1 + nr_frags) {
wil_err(wil, "Tx ring full. No space for %d fragments\n",
1 + nr_frags);
wil_err_ratelimited(wil,
"Tx ring full. No space for %d fragments\n",
1 + nr_frags);
return -ENOMEM;
}
_d = &vring->va[i].tx;
......
......@@ -49,8 +49,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL)
#define WIL6210_RX_RING_SIZE (128)
#define WIL6210_TX_RING_SIZE (512)
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9)
#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9)
/* limit ring size in range [32..32k] */
#define WIL_RING_SIZE_ORDER_MIN (5)
#define WIL_RING_SIZE_ORDER_MAX (15)
#define WIL6210_MAX_TX_RINGS (24) /* HW limit */
#define WIL6210_MAX_CID (8) /* HW limit */
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
......@@ -126,6 +129,7 @@ struct RGF_ICR {
#define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */
#define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */
#define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0)
#define BIT_DMA_EP_RX_ICR_RX_HTRSH BIT(1)
#define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */
#define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0)
#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
......@@ -468,13 +472,14 @@ struct wil6210_priv {
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
#define wil_to_pcie_dev(i) (&i->pdev->dev)
__printf(2, 3)
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
__printf(2, 3)
void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
__printf(2, 3)
void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...);
__printf(2, 3)
void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
......@@ -586,9 +591,9 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
bool from_event);
u16 reason_code, bool from_event);
int wil_rx_init(struct wil6210_priv *wil);
int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil);
/* TX API */
......
......@@ -478,15 +478,15 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
void *d, int len)
{
struct wmi_disconnect_event *evt = d;
u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n",
evt->bssid,
evt->protocol_reason_status, evt->disconnect_reason);
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
evt->bssid, reason_code, evt->disconnect_reason);
wil->sinfo_gen++;
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, evt->bssid, true);
wil6210_disconnect(wil, evt->bssid, reason_code, true);
mutex_unlock(&wil->mutex);
}
......
......@@ -183,6 +183,7 @@ struct vif_saved_ie {
* @pm_block: power-management blocked.
* @list: linked list.
* @mgmt_rx_reg: registered rx mgmt frame types.
* @mbss: Multiple BSS type, set if not first AP (not relevant for P2P).
*/
struct brcmf_cfg80211_vif {
struct brcmf_if *ifp;
......@@ -194,6 +195,7 @@ struct brcmf_cfg80211_vif {
struct vif_saved_ie saved_ie;
struct list_head list;
u16 mgmt_rx_reg;
bool mbss;
};
/* association inform */
......
......@@ -836,7 +836,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
return ifp;
}
void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
{
struct brcmf_if *ifp;
......@@ -869,6 +869,38 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
}
}
void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx)
{
if (drvr->iflist[bssidx]) {
brcmf_fws_del_interface(drvr->iflist[bssidx]);
brcmf_del_if(drvr, bssidx);
}
}
int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
{
int ifidx;
int bsscfgidx;
bool available;
int highest;
available = false;
bsscfgidx = 2;
highest = 2;
for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) {
if (drvr->iflist[ifidx]) {
if (drvr->iflist[ifidx]->bssidx == bsscfgidx)
bsscfgidx = highest + 1;
else if (drvr->iflist[ifidx]->bssidx > highest)
highest = drvr->iflist[ifidx]->bssidx;
} else {
available = true;
}
}
return available ? bsscfgidx : -ENOMEM;
}
int brcmf_attach(struct device *dev)
{
struct brcmf_pub *drvr = NULL;
......@@ -1033,10 +1065,7 @@ void brcmf_detach(struct device *dev)
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
if (drvr->iflist[i]) {
brcmf_fws_del_interface(drvr->iflist[i]);
brcmf_del_if(drvr, i);
}
brcmf_remove_interface(drvr, i);
brcmf_cfg80211_detach(drvr->config);
......
......@@ -175,7 +175,8 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
char *name, u8 *mac_addr);
void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx);
int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
enum brcmf_netif_stop_reason reason, bool state);
void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
......
......@@ -97,6 +97,28 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
}
}
/**
* brcmf_feat_iovar_int_set() - determine feature through iovar set.
*
* @ifp: interface to query.
* @id: feature id.
* @name: iovar name.
*/
static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp,
enum brcmf_feat_id id, char *name, u32 val)
{
int err;
err = brcmf_fil_iovar_int_set(ifp, name, val);
if (err == 0) {
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
ifp->drvr->feat_flags |= BIT(id);
} else {
brcmf_dbg(TRACE, "%s feature check failed: %d\n",
brcmf_feat_names[id], err);
}
}
void brcmf_feat_attach(struct brcmf_pub *drvr)
{
struct brcmf_if *ifp = drvr->iflist[0];
......@@ -104,6 +126,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
if (drvr->bus_if->wowl_supported)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
/* set chip related quirks */
switch (drvr->bus_if->chip) {
......
......@@ -22,6 +22,7 @@
* MCHAN: multi-channel for concurrent P2P.
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
BRCMF_FEAT_DEF(MCHAN) \
BRCMF_FEAT_DEF(WOWL)
/*
......
......@@ -221,10 +221,8 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
brcmf_fws_del_interface(ifp);
brcmf_del_if(drvr, ifevent->bssidx);
}
if (ifp && ifevent->action == BRCMF_E_IF_DEL)
brcmf_remove_interface(drvr, ifevent->bssidx);
}
/**
......
......@@ -136,7 +136,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
mutex_lock(&ifp->drvr->proto_block);
brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
......@@ -154,7 +154,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
mutex_lock(&ifp->drvr->proto_block);
err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
......@@ -171,7 +171,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
__le32 data_le = cpu_to_le32(data);
mutex_lock(&ifp->drvr->proto_block);
brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data);
err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
mutex_unlock(&ifp->drvr->proto_block);
......@@ -188,7 +188,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
mutex_unlock(&ifp->drvr->proto_block);
*data = le32_to_cpu(data_le);
brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data);
return err;
}
......@@ -224,7 +224,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
mutex_lock(&drvr->proto_block);
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
......@@ -264,7 +264,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
brcmf_err("Creating iovar failed\n");
}
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
......@@ -347,7 +347,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
mutex_lock(&drvr->proto_block);
brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx,
ifp->bssidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
......@@ -386,7 +387,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
err = -EPERM;
brcmf_err("Creating bsscfg failed\n");
}
brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx,
ifp->bssidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
......
......@@ -519,4 +519,10 @@ struct brcmf_fil_wowl_pattern_le {
/* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */
};
struct brcmf_mbss_ssid_le {
__le32 bsscfgidx;
__le32 SSID_len;
unsigned char SSID[32];
};
#endif /* FWIL_TYPES_H_ */
......@@ -1080,8 +1080,17 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
{
struct brcmf_if *ifp;
/* The ifidx is the idx to map to matching netdev/ifp. When receiving
* events this is easy because it contains the bssidx which maps
* 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
* bssidx 1 is used for p2p0 and no data can be received or
* transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
*/
if (ifidx)
(ifidx)++;
ifp = msgbuf->drvr->iflist[ifidx];
if (!ifp || !ifp->ndev) {
brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
brcmu_pkt_buf_free_skb(skb);
return;
}
......@@ -1354,6 +1363,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
}
INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker);
count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings);
count = count * sizeof(unsigned long);
msgbuf->flow_map = kzalloc(count, GFP_KERNEL);
if (!msgbuf->flow_map)
goto fail;
......
......@@ -798,12 +798,14 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo)
brcmf_dbg(PCIE, "Enter\n");
/* is it a v1 or v2 implementation */
devinfo->irq_requested = false;
pci_enable_msi(pdev);
if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
if (request_threaded_irq(pdev->irq,
brcmf_pcie_quick_check_isr_v1,
brcmf_pcie_isr_thread_v1,
IRQF_SHARED, "brcmf_pcie_intr",
devinfo)) {
pci_disable_msi(pdev);
brcmf_err("Failed to request IRQ %d\n", pdev->irq);
return -EIO;
}
......@@ -813,6 +815,7 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo)
brcmf_pcie_isr_thread_v2,
IRQF_SHARED, "brcmf_pcie_intr",
devinfo)) {
pci_disable_msi(pdev);
brcmf_err("Failed to request IRQ %d\n", pdev->irq);
return -EIO;
}
......@@ -839,6 +842,7 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)
return;
devinfo->irq_requested = false;
free_irq(pdev->irq, devinfo);
pci_disable_msi(pdev);
msleep(50);
count = 0;
......@@ -1857,6 +1861,8 @@ static struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
{ /* end: all zeroes */ }
};
......
......@@ -31,8 +31,8 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data, int len)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
const struct brcmf_vndr_dcmd_hdr *cmdhdr = data;
struct sk_buff *reply;
int ret, payload, ret_len;
......@@ -42,6 +42,9 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
cmdhdr->len);
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
ifp = vif->ifp;
len -= sizeof(struct brcmf_vndr_dcmd_hdr);
ret_len = cmdhdr->len;
if (ret_len > 0 || len > 0) {
......@@ -63,11 +66,11 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
}
if (cmdhdr->set)
ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), cmdhdr->cmd,
dcmd_buf, ret_len);
ret = brcmf_fil_cmd_data_set(ifp, cmdhdr->cmd, dcmd_buf,
ret_len);
else
ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), cmdhdr->cmd,
dcmd_buf, ret_len);
ret = brcmf_fil_cmd_data_get(ifp, cmdhdr->cmd, dcmd_buf,
ret_len);
if (ret != 0)
goto exit;
......
......@@ -445,18 +445,18 @@ static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
kfree(wlc->protection);
kfree(wlc->stf);
kfree(wlc->bandstate[0]);
kfree(wlc->corestate->macstat_snapshot);
if (wlc->corestate)
kfree(wlc->corestate->macstat_snapshot);
kfree(wlc->corestate);
kfree(wlc->hw->bandstate[0]);
if (wlc->hw)
kfree(wlc->hw->bandstate[0]);
kfree(wlc->hw);
if (wlc->beacon)
dev_kfree_skb_any(wlc->beacon);
if (wlc->probe_resp)
dev_kfree_skb_any(wlc->probe_resp);
/* free the wlc */
kfree(wlc);
wlc = NULL;
}
static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)
......
......@@ -68,6 +68,8 @@
#define BRCM_PCIE_43567_DEVICE_ID 0x43d3
#define BRCM_PCIE_43570_DEVICE_ID 0x43d9
#define BRCM_PCIE_43602_DEVICE_ID 0x43ba
#define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb
#define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc
/* brcmsmac IDs */
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
......
......@@ -218,4 +218,6 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...)
}
#endif
char *brcmu_boardrev_str(u32 brev, char *buf);
#endif /* _BRCMU_UTILS_H_ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册