forked from Minki/linux
Merge ath-next from ath.git
Major changes: ath10k * add board 2 API support for automatically choosing correct board file * data path optimisations * disable PCI power save for qca988x and QCA99x0 due to interop reasons wil6210 * BlockAckReq support * firmware crashdump using devcoredump * capture all frames with sniffer
This commit is contained in:
commit
81c1f74de3
@ -82,6 +82,16 @@ enum bmi_cmd_id {
|
||||
|
||||
#define BMI_NVRAM_SEG_NAME_SZ 16
|
||||
|
||||
#define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10
|
||||
|
||||
#define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00
|
||||
#define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10
|
||||
|
||||
#define ATH10K_BMI_CHIP_ID_FROM_OTP_MASK 0x18000
|
||||
#define ATH10K_BMI_CHIP_ID_FROM_OTP_LSB 15
|
||||
|
||||
#define ATH10K_BMI_BOARD_ID_STATUS_MASK 0xff
|
||||
|
||||
struct bmi_cmd {
|
||||
__le32 id; /* enum bmi_cmd_id */
|
||||
union {
|
||||
|
@ -413,7 +413,7 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
|
||||
lockdep_assert_held(&ar_pci->ce_lock);
|
||||
|
||||
if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
|
||||
return -EIO;
|
||||
return -ENOSPC;
|
||||
|
||||
desc->addr = __cpu_to_le32(paddr);
|
||||
desc->nbytes = 0;
|
||||
@ -1076,9 +1076,7 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
|
||||
}
|
||||
|
||||
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
|
||||
const struct ce_attr *attr,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *),
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *))
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
@ -1104,10 +1102,10 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
|
||||
ce_state->src_sz_max = attr->src_sz_max;
|
||||
|
||||
if (attr->src_nentries)
|
||||
ce_state->send_cb = send_cb;
|
||||
ce_state->send_cb = attr->send_cb;
|
||||
|
||||
if (attr->dest_nentries)
|
||||
ce_state->recv_cb = recv_cb;
|
||||
ce_state->recv_cb = attr->recv_cb;
|
||||
|
||||
if (attr->src_nentries) {
|
||||
ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
|
||||
|
@ -209,9 +209,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
|
||||
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
|
||||
const struct ce_attr *attr,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *),
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *));
|
||||
const struct ce_attr *attr);
|
||||
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
|
||||
|
||||
/*==================CE Engine Shutdown=======================*/
|
||||
@ -277,6 +275,9 @@ struct ce_attr {
|
||||
|
||||
/* #entries in destination ring - Must be a power of 2 */
|
||||
unsigned int dest_nentries;
|
||||
|
||||
void (*send_cb)(struct ath10k_ce_pipe *);
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *);
|
||||
};
|
||||
|
||||
#define SR_BA_ADDRESS 0x0000
|
||||
|
@ -448,6 +448,56 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
|
||||
{
|
||||
u32 result, address;
|
||||
u8 board_id, chip_id;
|
||||
int ret;
|
||||
|
||||
address = ar->hw_params.patch_load_addr;
|
||||
|
||||
if (!ar->otp_data || !ar->otp_len) {
|
||||
ath10k_warn(ar,
|
||||
"failed to retrieve board id because of invalid otp\n");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"boot upload otp to 0x%x len %zd for board id\n",
|
||||
address, ar->otp_len);
|
||||
|
||||
ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "could not write otp for board id check: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID,
|
||||
&result);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "could not execute otp for board id check: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP);
|
||||
chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"boot get otp board id result 0x%08x board_id %d chip_id %d\n",
|
||||
result, board_id, chip_id);
|
||||
|
||||
if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ar->id.bmi_ids_valid = true;
|
||||
ar->id.bmi_board_id = board_id;
|
||||
ar->id.bmi_chip_id = chip_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
{
|
||||
u32 result, address = ar->hw_params.patch_load_addr;
|
||||
@ -486,8 +536,8 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
|
||||
|
||||
if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
|
||||
ar->fw_features))
|
||||
&& result != 0) {
|
||||
ar->fw_features)) &&
|
||||
result != 0) {
|
||||
ath10k_err(ar, "otp calibration failed: %d", result);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -510,7 +560,7 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
data_len = ar->firmware_len;
|
||||
mode_name = "normal";
|
||||
ret = ath10k_swap_code_seg_configure(ar,
|
||||
ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW);
|
||||
ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to configure fw code swap: %d\n",
|
||||
ret);
|
||||
@ -541,11 +591,18 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
||||
static void ath10k_core_free_board_files(struct ath10k *ar)
|
||||
{
|
||||
if (!IS_ERR(ar->board))
|
||||
release_firmware(ar->board);
|
||||
|
||||
ar->board = NULL;
|
||||
ar->board_data = NULL;
|
||||
ar->board_len = 0;
|
||||
}
|
||||
|
||||
static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
||||
{
|
||||
if (!IS_ERR(ar->otp))
|
||||
release_firmware(ar->otp);
|
||||
|
||||
@ -557,10 +614,6 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
||||
|
||||
ath10k_swap_code_seg_release(ar);
|
||||
|
||||
ar->board = NULL;
|
||||
ar->board_data = NULL;
|
||||
ar->board_len = 0;
|
||||
|
||||
ar->otp = NULL;
|
||||
ar->otp_data = NULL;
|
||||
ar->otp_len = 0;
|
||||
@ -570,7 +623,6 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
||||
ar->firmware_len = 0;
|
||||
|
||||
ar->cal_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
static int ath10k_fetch_cal_file(struct ath10k *ar)
|
||||
@ -592,25 +644,7 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_spec_board_file(struct ath10k *ar)
|
||||
{
|
||||
char filename[100];
|
||||
|
||||
scnprintf(filename, sizeof(filename), "board-%s-%s.bin",
|
||||
ath10k_bus_str(ar->hif.bus), ar->spec_board_id);
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename);
|
||||
if (IS_ERR(ar->board))
|
||||
return PTR_ERR(ar->board);
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
ar->spec_board_loaded = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_generic_board_file(struct ath10k *ar)
|
||||
static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar)
|
||||
{
|
||||
if (!ar->hw_params.fw.board) {
|
||||
ath10k_err(ar, "failed to find board file fw entry\n");
|
||||
@ -625,35 +659,236 @@ static int ath10k_core_fetch_generic_board_file(struct ath10k *ar)
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
ar->spec_board_loaded = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,
|
||||
const void *buf, size_t buf_len,
|
||||
const char *boardname)
|
||||
{
|
||||
const struct ath10k_fw_ie *hdr;
|
||||
bool name_match_found;
|
||||
int ret, board_ie_id;
|
||||
size_t board_ie_len;
|
||||
const void *board_ie_data;
|
||||
|
||||
name_match_found = false;
|
||||
|
||||
/* go through ATH10K_BD_IE_BOARD_ elements */
|
||||
while (buf_len > sizeof(struct ath10k_fw_ie)) {
|
||||
hdr = buf;
|
||||
board_ie_id = le32_to_cpu(hdr->id);
|
||||
board_ie_len = le32_to_cpu(hdr->len);
|
||||
board_ie_data = hdr->data;
|
||||
|
||||
buf_len -= sizeof(*hdr);
|
||||
buf += sizeof(*hdr);
|
||||
|
||||
if (buf_len < ALIGN(board_ie_len, 4)) {
|
||||
ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n",
|
||||
buf_len, ALIGN(board_ie_len, 4));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (board_ie_id) {
|
||||
case ATH10K_BD_IE_BOARD_NAME:
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "",
|
||||
board_ie_data, board_ie_len);
|
||||
|
||||
if (board_ie_len != strlen(boardname))
|
||||
break;
|
||||
|
||||
ret = memcmp(board_ie_data, boardname, strlen(boardname));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
name_match_found = true;
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"boot found match for name '%s'",
|
||||
boardname);
|
||||
break;
|
||||
case ATH10K_BD_IE_BOARD_DATA:
|
||||
if (!name_match_found)
|
||||
/* no match found */
|
||||
break;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"boot found board data for '%s'",
|
||||
boardname);
|
||||
|
||||
ar->board_data = board_ie_data;
|
||||
ar->board_len = board_ie_len;
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
default:
|
||||
ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n",
|
||||
board_ie_id);
|
||||
break;
|
||||
}
|
||||
|
||||
/* jump over the padding */
|
||||
board_ie_len = ALIGN(board_ie_len, 4);
|
||||
|
||||
buf_len -= board_ie_len;
|
||||
buf += board_ie_len;
|
||||
}
|
||||
|
||||
/* no match found */
|
||||
ret = -ENOENT;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
|
||||
const char *boardname,
|
||||
const char *filename)
|
||||
{
|
||||
size_t len, magic_len, ie_len;
|
||||
struct ath10k_fw_ie *hdr;
|
||||
const u8 *data;
|
||||
int ret, ie_id;
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename);
|
||||
if (IS_ERR(ar->board))
|
||||
return PTR_ERR(ar->board);
|
||||
|
||||
data = ar->board->data;
|
||||
len = ar->board->size;
|
||||
|
||||
/* magic has extra null byte padded */
|
||||
magic_len = strlen(ATH10K_BOARD_MAGIC) + 1;
|
||||
if (len < magic_len) {
|
||||
ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n",
|
||||
ar->hw_params.fw.dir, filename, len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) {
|
||||
ath10k_err(ar, "found invalid board magic\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* magic is padded to 4 bytes */
|
||||
magic_len = ALIGN(magic_len, 4);
|
||||
if (len < magic_len) {
|
||||
ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n",
|
||||
ar->hw_params.fw.dir, filename, len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
data += magic_len;
|
||||
len -= magic_len;
|
||||
|
||||
while (len > sizeof(struct ath10k_fw_ie)) {
|
||||
hdr = (struct ath10k_fw_ie *)data;
|
||||
ie_id = le32_to_cpu(hdr->id);
|
||||
ie_len = le32_to_cpu(hdr->len);
|
||||
|
||||
len -= sizeof(*hdr);
|
||||
data = hdr->data;
|
||||
|
||||
if (len < ALIGN(ie_len, 4)) {
|
||||
ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n",
|
||||
ie_id, ie_len, len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (ie_id) {
|
||||
case ATH10K_BD_IE_BOARD:
|
||||
ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
|
||||
boardname);
|
||||
if (ret == -ENOENT)
|
||||
/* no match found, continue */
|
||||
break;
|
||||
else if (ret)
|
||||
/* there was an error, bail out */
|
||||
goto err;
|
||||
|
||||
/* board data found */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* jump over the padding */
|
||||
ie_len = ALIGN(ie_len, 4);
|
||||
|
||||
len -= ie_len;
|
||||
data += ie_len;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!ar->board_data || !ar->board_len) {
|
||||
ath10k_err(ar,
|
||||
"failed to fetch board data for %s from %s/%s\n",
|
||||
ar->hw_params.fw.dir, boardname, filename);
|
||||
ret = -ENODATA;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
ath10k_core_free_board_files(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
if (ar->id.bmi_ids_valid) {
|
||||
scnprintf(name, name_len,
|
||||
"bus=%s,bmi-chip-id=%d,bmi-board-id=%d",
|
||||
ath10k_bus_str(ar->hif.bus),
|
||||
ar->id.bmi_chip_id,
|
||||
ar->id.bmi_board_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scnprintf(name, name_len,
|
||||
"bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x",
|
||||
ath10k_bus_str(ar->hif.bus),
|
||||
ar->id.vendor, ar->id.device,
|
||||
ar->id.subsystem_vendor, ar->id.subsystem_device);
|
||||
|
||||
out:
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_board_file(struct ath10k *ar)
|
||||
{
|
||||
char boardname[100];
|
||||
int ret;
|
||||
|
||||
if (strlen(ar->spec_board_id) > 0) {
|
||||
ret = ath10k_core_fetch_spec_board_file(ar);
|
||||
if (ret) {
|
||||
ath10k_info(ar, "failed to load spec board file, falling back to generic: %d\n",
|
||||
ret);
|
||||
goto generic;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found specific board file for %s\n",
|
||||
ar->spec_board_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
generic:
|
||||
ret = ath10k_core_fetch_generic_board_file(ar);
|
||||
ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname));
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch generic board data: %d\n", ret);
|
||||
ath10k_err(ar, "failed to create board name: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->bd_api = 2;
|
||||
ret = ath10k_core_fetch_board_data_api_n(ar, boardname,
|
||||
ATH10K_BOARD_API2_FILE);
|
||||
if (!ret)
|
||||
goto success;
|
||||
|
||||
ar->bd_api = 1;
|
||||
ret = ath10k_core_fetch_board_data_api_1(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch board data\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
success:
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -885,12 +1120,6 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
/* calibration file is optional, don't check for any errors */
|
||||
ath10k_fetch_cal_file(ar);
|
||||
|
||||
ret = ath10k_core_fetch_board_file(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch board file: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->fw_api = 5;
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
|
||||
|
||||
@ -1263,10 +1492,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
goto err;
|
||||
|
||||
/* Some of of qca988x solutions are having global reset issue
|
||||
* during target initialization. Bypassing PLL setting before
|
||||
* downloading firmware and letting the SoC run on REF_CLK is
|
||||
* fixing the problem. Corresponding firmware change is also needed
|
||||
* to set the clock source once the target is initialized.
|
||||
* during target initialization. Bypassing PLL setting before
|
||||
* downloading firmware and letting the SoC run on REF_CLK is
|
||||
* fixing the problem. Corresponding firmware change is also needed
|
||||
* to set the clock source once the target is initialized.
|
||||
*/
|
||||
if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
|
||||
ar->fw_features)) {
|
||||
@ -1500,6 +1729,19 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
||||
goto err_power_down;
|
||||
}
|
||||
|
||||
ret = ath10k_core_get_board_id_from_otp(ar);
|
||||
if (ret && ret != -EOPNOTSUPP) {
|
||||
ath10k_err(ar, "failed to get board id from otp for qca99x0: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_core_fetch_board_file(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch board file: %d\n", ret);
|
||||
goto err_free_firmware_files;
|
||||
}
|
||||
|
||||
ret = ath10k_core_init_firmware_features(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "fatal problem with firmware features: %d\n",
|
||||
@ -1627,6 +1869,7 @@ void ath10k_core_unregister(struct ath10k *ar)
|
||||
ath10k_testmode_destroy(ar);
|
||||
|
||||
ath10k_core_free_firmware_files(ar);
|
||||
ath10k_core_free_board_files(ar);
|
||||
|
||||
ath10k_debug_unregister(ar);
|
||||
}
|
||||
|
@ -250,6 +250,30 @@ struct ath10k_fw_stats {
|
||||
struct list_head peers;
|
||||
};
|
||||
|
||||
#define ATH10K_TPC_TABLE_TYPE_FLAG 1
|
||||
#define ATH10K_TPC_PREAM_TABLE_END 0xFFFF
|
||||
|
||||
struct ath10k_tpc_table {
|
||||
u32 pream_idx[WMI_TPC_RATE_MAX];
|
||||
u8 rate_code[WMI_TPC_RATE_MAX];
|
||||
char tpc_value[WMI_TPC_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct ath10k_tpc_stats {
|
||||
u32 reg_domain;
|
||||
u32 chan_freq;
|
||||
u32 phy_mode;
|
||||
u32 twice_antenna_reduction;
|
||||
u32 twice_max_rd_power;
|
||||
s32 twice_antenna_gain;
|
||||
u32 power_limit;
|
||||
u32 num_tx_chain;
|
||||
u32 ctl;
|
||||
u32 rate_max;
|
||||
u8 flag[WMI_TPC_FLAG];
|
||||
struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG];
|
||||
};
|
||||
|
||||
struct ath10k_dfs_stats {
|
||||
u32 phy_errors;
|
||||
u32 pulses_total;
|
||||
@ -378,6 +402,11 @@ struct ath10k_debug {
|
||||
struct ath10k_dfs_stats dfs_stats;
|
||||
struct ath_dfs_pool_stats dfs_pool_stats;
|
||||
|
||||
/* used for tpc-dump storage, protected by data-lock */
|
||||
struct ath10k_tpc_stats *tpc_stats;
|
||||
|
||||
struct completion tpc_complete;
|
||||
|
||||
/* protected by conf_mutex */
|
||||
u32 fw_dbglog_mask;
|
||||
u32 fw_dbglog_level;
|
||||
@ -647,10 +676,19 @@ struct ath10k {
|
||||
struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info;
|
||||
} swap;
|
||||
|
||||
char spec_board_id[100];
|
||||
bool spec_board_loaded;
|
||||
struct {
|
||||
u32 vendor;
|
||||
u32 device;
|
||||
u32 subsystem_vendor;
|
||||
u32 subsystem_device;
|
||||
|
||||
bool bmi_ids_valid;
|
||||
u8 bmi_board_id;
|
||||
u8 bmi_chip_id;
|
||||
} id;
|
||||
|
||||
int fw_api;
|
||||
int bd_api;
|
||||
enum ath10k_cal_mode cal_mode;
|
||||
|
||||
struct {
|
||||
|
@ -125,19 +125,25 @@ EXPORT_SYMBOL(ath10k_info);
|
||||
void ath10k_print_driver_info(struct ath10k *ar)
|
||||
{
|
||||
char fw_features[128] = {};
|
||||
char boardinfo[100];
|
||||
|
||||
ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));
|
||||
|
||||
ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n",
|
||||
if (ar->id.bmi_ids_valid)
|
||||
scnprintf(boardinfo, sizeof(boardinfo), "bmi %d:%d",
|
||||
ar->id.bmi_chip_id, ar->id.bmi_board_id);
|
||||
else
|
||||
scnprintf(boardinfo, sizeof(boardinfo), "sub %04x:%04x",
|
||||
ar->id.subsystem_vendor, ar->id.subsystem_device);
|
||||
|
||||
ath10k_info(ar, "%s (0x%08x, 0x%08x %s) fw %s fwapi %d bdapi %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n",
|
||||
ar->hw_params.name,
|
||||
ar->target_version,
|
||||
ar->chip_id,
|
||||
(strlen(ar->spec_board_id) > 0 ? ", " : ""),
|
||||
ar->spec_board_id,
|
||||
(strlen(ar->spec_board_id) > 0 && !ar->spec_board_loaded
|
||||
? " fallback" : ""),
|
||||
boardinfo,
|
||||
ar->hw->wiphy->fw_version,
|
||||
ar->fw_api,
|
||||
ar->bd_api,
|
||||
ar->htt.target_version_major,
|
||||
ar->htt.target_version_minor,
|
||||
ar->wmi.op_version,
|
||||
@ -285,28 +291,6 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head)
|
||||
{
|
||||
struct ath10k_fw_stats_peer *i;
|
||||
size_t num = 0;
|
||||
|
||||
list_for_each_entry(i, head, list)
|
||||
++num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head)
|
||||
{
|
||||
struct ath10k_fw_stats_vdev *i;
|
||||
size_t num = 0;
|
||||
|
||||
list_for_each_entry(i, head, list)
|
||||
++num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_fw_stats stats = {};
|
||||
@ -343,8 +327,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
goto free;
|
||||
}
|
||||
|
||||
num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers);
|
||||
num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
|
||||
num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers);
|
||||
num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
|
||||
is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
|
||||
!list_empty(&stats.pdevs));
|
||||
is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
|
||||
@ -429,240 +413,6 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: How to calculate the buffer size sanely? */
|
||||
#define ATH10K_FW_STATS_BUF_SIZE (1024*1024)
|
||||
|
||||
static void ath10k_fw_stats_fill(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *fw_stats,
|
||||
char *buf)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
const struct ath10k_fw_stats_pdev *pdev;
|
||||
const struct ath10k_fw_stats_vdev *vdev;
|
||||
const struct ath10k_fw_stats_peer *peer;
|
||||
size_t num_peers;
|
||||
size_t num_vdevs;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
pdev = list_first_entry_or_null(&fw_stats->pdevs,
|
||||
struct ath10k_fw_stats_pdev, list);
|
||||
if (!pdev) {
|
||||
ath10k_warn(ar, "failed to get pdev stats\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers);
|
||||
num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Channel noise floor", pdev->ch_noise_floor);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"Channel TX power", pdev->chan_tx_power);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"TX frame count", pdev->tx_frame_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RX frame count", pdev->rx_frame_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RX clear count", pdev->rx_clear_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"Cycle count", pdev->cycle_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"PHY error count", pdev->phy_err_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RTS bad count", pdev->rts_bad);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RTS good count", pdev->rts_good);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"FCS bad count", pdev->fcs_bad);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"No beacon count", pdev->no_beacons);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"MIB int count", pdev->mib_int_count);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV TX stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HTT cookies queued", pdev->comp_queued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HTT cookies disp.", pdev->comp_delivered);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDU queued", pdev->msdu_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU queued", pdev->mpdu_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs dropped", pdev->wmm_drop);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Local enqued", pdev->local_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Local freed", pdev->local_freed);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HW queued", pdev->hw_queued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PPDUs reaped", pdev->hw_reaped);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Num underruns", pdev->underrun);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PPDUs cleaned", pdev->tx_abort);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs requed", pdev->mpdus_requed);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Excessive retries", pdev->tx_ko);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HW rate", pdev->data_rc);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Sched self tiggers", pdev->self_triggers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Dropped due to SW retries",
|
||||
pdev->sw_retry_failure);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Illegal rate phy errors",
|
||||
pdev->illgl_rate_phy_err);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Pdev continous xretry", pdev->pdev_cont_xretry);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"TX timeout", pdev->pdev_tx_timeout);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PDEV resets", pdev->pdev_resets);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY underrun", pdev->phy_underrun);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU is more than txop limit", pdev->txop_ovf);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV RX stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Mid PPDU route change",
|
||||
pdev->mid_ppdu_route_change);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Tot. number of statuses", pdev->status_rcvd);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 0", pdev->r0_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 1", pdev->r1_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 2", pdev->r2_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 3", pdev->r3_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs delivered to HTT", pdev->htt_msdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to HTT", pdev->htt_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs delivered to stack", pdev->loc_msdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to stack", pdev->loc_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Oversized AMSUs", pdev->oversize_amsdu);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors", pdev->phy_errs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors drops", pdev->phy_err_drop);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
|
||||
"ath10k VDEV stats", num_vdevs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
list_for_each_entry(vdev, &fw_stats->vdevs, list) {
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"vdev id", vdev->vdev_id);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"beacon snr", vdev->beacon_snr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"data snr", vdev->data_snr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rx frames", vdev->num_rx_frames);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rts fail", vdev->num_rts_fail);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rts success", vdev->num_rts_success);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rx err", vdev->num_rx_err);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rx discard", vdev->num_rx_discard);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num tx not acked", vdev->num_tx_not_acked);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"num tx frames", i,
|
||||
vdev->num_tx_frames[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"num tx frames retries", i,
|
||||
vdev->num_tx_frames_retries[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"num tx frames failures", i,
|
||||
vdev->num_tx_frames_failures[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] 0x%08x\n",
|
||||
"tx rate history", i,
|
||||
vdev->tx_rate_history[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"beacon rssi history", i,
|
||||
vdev->beacon_rssi_history[i]);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
|
||||
"ath10k PEER stats", num_peers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
list_for_each_entry(peer, &fw_stats->peers, list) {
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
|
||||
"Peer MAC address", peer->peer_macaddr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer RSSI", peer->peer_rssi);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer TX rate", peer->peer_tx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer RX rate", peer->peer_rx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (len >= buf_len)
|
||||
buf[len - 1] = 0;
|
||||
else
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ath10k *ar = inode->i_private;
|
||||
@ -688,7 +438,12 @@ static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
|
||||
ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to fill fw stats: %d\n", ret);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
file->private_data = buf;
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
@ -1843,6 +1598,233 @@ static const struct file_operations fops_nf_cal_period = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#define ATH10K_TPC_CONFIG_BUF_SIZE (1024 * 1024)
|
||||
|
||||
static int ath10k_debug_tpc_stats_request(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
reinit_completion(&ar->debug.tpc_complete);
|
||||
|
||||
ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to request tpc config: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
|
||||
1 * HZ);
|
||||
if (time_left == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats)
|
||||
{
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
kfree(ar->debug.tpc_stats);
|
||||
ar->debug.tpc_stats = tpc_stats;
|
||||
complete(&ar->debug.tpc_complete);
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
|
||||
unsigned int j, char *buf, unsigned int *len)
|
||||
{
|
||||
unsigned int i, buf_len;
|
||||
static const char table_str[][5] = { "CDD",
|
||||
"STBC",
|
||||
"TXBF" };
|
||||
static const char pream_str[][6] = { "CCK",
|
||||
"OFDM",
|
||||
"HT20",
|
||||
"HT40",
|
||||
"VHT20",
|
||||
"VHT40",
|
||||
"VHT80",
|
||||
"HTCUP" };
|
||||
|
||||
buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
|
||||
*len += scnprintf(buf + *len, buf_len - *len,
|
||||
"********************************\n");
|
||||
*len += scnprintf(buf + *len, buf_len - *len,
|
||||
"******************* %s POWER TABLE ****************\n",
|
||||
table_str[j]);
|
||||
*len += scnprintf(buf + *len, buf_len - *len,
|
||||
"********************************\n");
|
||||
*len += scnprintf(buf + *len, buf_len - *len,
|
||||
"No. Preamble Rate_code tpc_value1 tpc_value2 tpc_value3\n");
|
||||
|
||||
for (i = 0; i < tpc_stats->rate_max; i++) {
|
||||
*len += scnprintf(buf + *len, buf_len - *len,
|
||||
"%8d %s 0x%2x %s\n", i,
|
||||
pream_str[tpc_stats->tpc_table[j].pream_idx[i]],
|
||||
tpc_stats->tpc_table[j].rate_code[i],
|
||||
tpc_stats->tpc_table[j].tpc_value[i]);
|
||||
}
|
||||
|
||||
*len += scnprintf(buf + *len, buf_len - *len,
|
||||
"***********************************\n");
|
||||
}
|
||||
|
||||
static void ath10k_tpc_stats_fill(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats,
|
||||
char *buf)
|
||||
{
|
||||
unsigned int len, j, buf_len;
|
||||
|
||||
len = 0;
|
||||
buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
if (!tpc_stats) {
|
||||
ath10k_warn(ar, "failed to get tpc stats\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"*************************************\n");
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"TPC config for channel %4d mode %d\n",
|
||||
tpc_stats->chan_freq,
|
||||
tpc_stats->phy_mode);
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"*************************************\n");
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"CTL = 0x%2x Reg. Domain = %2d\n",
|
||||
tpc_stats->ctl,
|
||||
tpc_stats->reg_domain);
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"Antenna Gain = %2d Reg. Max Antenna Gain = %2d\n",
|
||||
tpc_stats->twice_antenna_gain,
|
||||
tpc_stats->twice_antenna_reduction);
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"Power Limit = %2d Reg. Max Power = %2d\n",
|
||||
tpc_stats->power_limit,
|
||||
tpc_stats->twice_max_rd_power / 2);
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"Num tx chains = %2d Num supported rates = %2d\n",
|
||||
tpc_stats->num_tx_chain,
|
||||
tpc_stats->rate_max);
|
||||
|
||||
for (j = 0; j < tpc_stats->num_tx_chain ; j++) {
|
||||
switch (j) {
|
||||
case WMI_TPC_TABLE_TYPE_CDD:
|
||||
if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"CDD not supported\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_STBC:
|
||||
if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"STBC not supported\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_TXBF:
|
||||
if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"TXBF not supported\n***************************\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
|
||||
break;
|
||||
default:
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"Invalid Type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (len >= buf_len)
|
||||
buf[len - 1] = 0;
|
||||
else
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
static int ath10k_tpc_stats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ath10k *ar = inode->i_private;
|
||||
void *buf = NULL;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON) {
|
||||
ret = -ENETDOWN;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
ret = ath10k_debug_tpc_stats_request(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to request tpc config stats: %d\n",
|
||||
ret);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
|
||||
file->private_data = buf;
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
vfree(buf);
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_tpc_stats_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
vfree(file->private_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
const char *buf = file->private_data;
|
||||
unsigned int len = strlen(buf);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tpc_stats = {
|
||||
.open = ath10k_tpc_stats_open,
|
||||
.release = ath10k_tpc_stats_release,
|
||||
.read = ath10k_tpc_stats_read,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath10k_debug_start(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
@ -2111,6 +2093,8 @@ void ath10k_debug_destroy(struct ath10k *ar)
|
||||
ar->debug.fw_crash_data = NULL;
|
||||
|
||||
ath10k_debug_fw_stats_reset(ar);
|
||||
|
||||
kfree(ar->debug.tpc_stats);
|
||||
}
|
||||
|
||||
int ath10k_debug_register(struct ath10k *ar)
|
||||
@ -2127,6 +2111,7 @@ int ath10k_debug_register(struct ath10k *ar)
|
||||
INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
|
||||
ath10k_debug_htt_stats_dwork);
|
||||
|
||||
init_completion(&ar->debug.tpc_complete);
|
||||
init_completion(&ar->debug.fw_stats_complete);
|
||||
|
||||
debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
|
||||
@ -2195,6 +2180,9 @@ int ath10k_debug_register(struct ath10k *ar)
|
||||
debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_quiet_period);
|
||||
|
||||
debugfs_create_file("tpc_stats", S_IRUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_tpc_stats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,9 @@ enum ath10k_dbg_aggr_mode {
|
||||
ATH10K_DBG_AGGR_MODE_MAX,
|
||||
};
|
||||
|
||||
/* FIXME: How to calculate the buffer size sanely? */
|
||||
#define ATH10K_FW_STATS_BUF_SIZE (1024*1024)
|
||||
|
||||
extern unsigned int ath10k_debug_mask;
|
||||
|
||||
__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
|
||||
@ -70,6 +73,8 @@ void ath10k_debug_destroy(struct ath10k *ar);
|
||||
int ath10k_debug_register(struct ath10k *ar);
|
||||
void ath10k_debug_unregister(struct ath10k *ar);
|
||||
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats);
|
||||
struct ath10k_fw_crash_data *
|
||||
ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
|
||||
|
||||
@ -117,6 +122,12 @@ static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats)
|
||||
{
|
||||
kfree(tpc_stats);
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
|
||||
int len)
|
||||
{
|
||||
|
@ -30,13 +30,6 @@ struct ath10k_hif_sg_item {
|
||||
u16 len;
|
||||
};
|
||||
|
||||
struct ath10k_hif_cb {
|
||||
int (*tx_completion)(struct ath10k *ar,
|
||||
struct sk_buff *wbuf);
|
||||
int (*rx_completion)(struct ath10k *ar,
|
||||
struct sk_buff *wbuf);
|
||||
};
|
||||
|
||||
struct ath10k_hif_ops {
|
||||
/* send a scatter-gather list to the target */
|
||||
int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
|
||||
@ -65,8 +58,7 @@ struct ath10k_hif_ops {
|
||||
void (*stop)(struct ath10k *ar);
|
||||
|
||||
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe,
|
||||
int *ul_is_polled, int *dl_is_polled);
|
||||
u8 *ul_pipe, u8 *dl_pipe);
|
||||
|
||||
void (*get_default_pipe)(struct ath10k *ar, u8 *ul_pipe, u8 *dl_pipe);
|
||||
|
||||
@ -80,9 +72,6 @@ struct ath10k_hif_ops {
|
||||
*/
|
||||
void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force);
|
||||
|
||||
void (*set_callbacks)(struct ath10k *ar,
|
||||
struct ath10k_hif_cb *callbacks);
|
||||
|
||||
u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
|
||||
|
||||
u32 (*read32)(struct ath10k *ar, u32 address);
|
||||
@ -142,13 +131,10 @@ static inline void ath10k_hif_stop(struct ath10k *ar)
|
||||
|
||||
static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe,
|
||||
int *ul_is_polled,
|
||||
int *dl_is_polled)
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
return ar->hif.ops->map_service_to_pipe(ar, service_id,
|
||||
ul_pipe, dl_pipe,
|
||||
ul_is_polled, dl_is_polled);
|
||||
ul_pipe, dl_pipe);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_get_default_pipe(struct ath10k *ar,
|
||||
@ -163,12 +149,6 @@ static inline void ath10k_hif_send_complete_check(struct ath10k *ar,
|
||||
ar->hif.ops->send_complete_check(ar, pipe_id, force);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_set_callbacks(struct ath10k *ar,
|
||||
struct ath10k_hif_cb *callbacks)
|
||||
{
|
||||
ar->hif.ops->set_callbacks(ar, callbacks);
|
||||
}
|
||||
|
||||
static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
|
||||
u8 pipe_id)
|
||||
{
|
||||
|
@ -23,16 +23,6 @@
|
||||
/* Send */
|
||||
/********/
|
||||
|
||||
static inline void ath10k_htc_send_complete_check(struct ath10k_htc_ep *ep,
|
||||
int force)
|
||||
{
|
||||
/*
|
||||
* Check whether HIF has any prior sends that have finished,
|
||||
* have not had the post-processing done.
|
||||
*/
|
||||
ath10k_hif_send_complete_check(ep->htc->ar, ep->ul_pipe_id, force);
|
||||
}
|
||||
|
||||
static void ath10k_htc_control_tx_complete(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -181,24 +171,22 @@ err_pull:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htc *htc = &ar->htc;
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct ath10k_htc_ep *ep;
|
||||
|
||||
if (WARN_ON_ONCE(!skb))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
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 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htc_tx_completion_handler);
|
||||
|
||||
/***********/
|
||||
/* Receive */
|
||||
@ -304,8 +292,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
int status = 0;
|
||||
struct ath10k_htc *htc = &ar->htc;
|
||||
@ -326,21 +313,11 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid);
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "",
|
||||
hdr, sizeof(*hdr));
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ep = &htc->endpoint[eid];
|
||||
|
||||
/*
|
||||
* If this endpoint that received a message from the target has
|
||||
* a to-target HIF pipe whose send completions are polled rather
|
||||
* than interrupt-driven, this is a good point to ask HIF to check
|
||||
* whether it has any completed sends to handle.
|
||||
*/
|
||||
if (ep->ul_is_polled)
|
||||
ath10k_htc_send_complete_check(ep, 1);
|
||||
|
||||
payload_len = __le16_to_cpu(hdr->len);
|
||||
|
||||
if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
|
||||
@ -348,7 +325,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
payload_len + sizeof(*hdr));
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "",
|
||||
hdr, sizeof(*hdr));
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -358,7 +334,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
skb->len, payload_len);
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len",
|
||||
"", hdr, sizeof(*hdr));
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -374,7 +349,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
(trailer_len > payload_len)) {
|
||||
ath10k_warn(ar, "Invalid trailer length: %d\n",
|
||||
trailer_len);
|
||||
status = -EPROTO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -407,7 +381,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
* sending unsolicited messages on the ep 0
|
||||
*/
|
||||
ath10k_warn(ar, "HTC rx ctrl still processing\n");
|
||||
status = -EINVAL;
|
||||
complete(&htc->ctl_resp);
|
||||
goto out;
|
||||
}
|
||||
@ -439,9 +412,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
skb = NULL;
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htc_rx_completion_handler);
|
||||
|
||||
static void ath10k_htc_control_rx_complete(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
@ -767,9 +739,7 @@ setup:
|
||||
status = ath10k_hif_map_service_to_pipe(htc->ar,
|
||||
ep->service_id,
|
||||
&ep->ul_pipe_id,
|
||||
&ep->dl_pipe_id,
|
||||
&ep->ul_is_polled,
|
||||
&ep->dl_is_polled);
|
||||
&ep->dl_pipe_id);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@ -778,10 +748,6 @@ setup:
|
||||
htc_service_name(ep->service_id), ep->ul_pipe_id,
|
||||
ep->dl_pipe_id, ep->eid);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"boot htc ep %d ul polled %d dl polled %d\n",
|
||||
ep->eid, ep->ul_is_polled, ep->dl_is_polled);
|
||||
|
||||
if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
|
||||
ep->tx_credit_flow_enabled = false;
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
@ -841,7 +807,6 @@ int ath10k_htc_start(struct ath10k_htc *htc)
|
||||
/* registered target arrival callback from the HIF layer */
|
||||
int ath10k_htc_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_hif_cb htc_callbacks;
|
||||
struct ath10k_htc_ep *ep = NULL;
|
||||
struct ath10k_htc *htc = &ar->htc;
|
||||
|
||||
@ -849,15 +814,11 @@ int ath10k_htc_init(struct ath10k *ar)
|
||||
|
||||
ath10k_htc_reset_endpoint_states(htc);
|
||||
|
||||
/* setup HIF layer callbacks */
|
||||
htc_callbacks.rx_completion = ath10k_htc_rx_completion_handler;
|
||||
htc_callbacks.tx_completion = ath10k_htc_tx_completion_handler;
|
||||
htc->ar = ar;
|
||||
|
||||
/* Get HIF default pipe for HTC message exchange */
|
||||
ep = &htc->endpoint[ATH10K_HTC_EP_0];
|
||||
|
||||
ath10k_hif_set_callbacks(ar, &htc_callbacks);
|
||||
ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id);
|
||||
|
||||
init_completion(&htc->ctl_resp);
|
||||
|
@ -312,8 +312,6 @@ struct ath10k_htc_ep {
|
||||
int max_ep_message_len;
|
||||
u8 ul_pipe_id;
|
||||
u8 dl_pipe_id;
|
||||
int ul_is_polled; /* call HIF to get tx completions */
|
||||
int dl_is_polled; /* call HIF to fetch rx (not implemented) */
|
||||
|
||||
u8 seq_no; /* for debugging */
|
||||
int tx_credits;
|
||||
@ -355,5 +353,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *packet);
|
||||
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
|
||||
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
|
||||
#endif
|
||||
|
@ -1488,7 +1488,6 @@ struct ath10k_htt {
|
||||
int num_pending_mgmt_tx;
|
||||
struct idr pending_tx;
|
||||
wait_queue_head_t empty_tx_wq;
|
||||
struct dma_pool *tx_pool;
|
||||
|
||||
/* set if host-fw communication goes haywire
|
||||
* used to avoid further failures */
|
||||
@ -1509,6 +1508,11 @@ struct ath10k_htt {
|
||||
dma_addr_t paddr;
|
||||
struct htt_msdu_ext_desc *vaddr;
|
||||
} frag_desc;
|
||||
|
||||
struct {
|
||||
dma_addr_t paddr;
|
||||
struct ath10k_htt_txbuf *vaddr;
|
||||
} txbuf;
|
||||
};
|
||||
|
||||
#define RX_HTT_HDR_STATUS_LEN 64
|
||||
@ -1587,6 +1591,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);
|
||||
int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
|
||||
u8 max_subfrms_ampdu,
|
||||
u8 max_subfrms_amsdu);
|
||||
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb);
|
||||
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc);
|
||||
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
|
||||
|
@ -2125,6 +2125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
/* Free the indication buffer */
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler);
|
||||
|
||||
static void ath10k_htt_txrx_compl_task(unsigned long ptr)
|
||||
{
|
||||
|
@ -108,9 +108,12 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||
spin_lock_init(&htt->tx_lock);
|
||||
idr_init(&htt->pending_tx);
|
||||
|
||||
htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev,
|
||||
sizeof(struct ath10k_htt_txbuf), 4, 0);
|
||||
if (!htt->tx_pool) {
|
||||
size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf);
|
||||
htt->txbuf.vaddr = dma_alloc_coherent(ar->dev, size,
|
||||
&htt->txbuf.paddr,
|
||||
GFP_DMA);
|
||||
if (!htt->txbuf.vaddr) {
|
||||
ath10k_err(ar, "failed to alloc tx buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_idr_pending_tx;
|
||||
}
|
||||
@ -125,14 +128,17 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||
if (!htt->frag_desc.vaddr) {
|
||||
ath10k_warn(ar, "failed to alloc fragment desc memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_tx_pool;
|
||||
goto free_txbuf;
|
||||
}
|
||||
|
||||
skip_frag_desc_alloc:
|
||||
return 0;
|
||||
|
||||
free_tx_pool:
|
||||
dma_pool_destroy(htt->tx_pool);
|
||||
free_txbuf:
|
||||
size = htt->max_num_pending_tx *
|
||||
sizeof(struct ath10k_htt_txbuf);
|
||||
dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr,
|
||||
htt->txbuf.paddr);
|
||||
free_idr_pending_tx:
|
||||
idr_destroy(&htt->pending_tx);
|
||||
return ret;
|
||||
@ -160,7 +166,13 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
|
||||
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
|
||||
idr_destroy(&htt->pending_tx);
|
||||
dma_pool_destroy(htt->tx_pool);
|
||||
|
||||
if (htt->txbuf.vaddr) {
|
||||
size = htt->max_num_pending_tx *
|
||||
sizeof(struct ath10k_htt_txbuf);
|
||||
dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr,
|
||||
htt->txbuf.paddr);
|
||||
}
|
||||
|
||||
if (htt->frag_desc.vaddr) {
|
||||
size = htt->max_num_pending_tx *
|
||||
@ -175,6 +187,12 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htt_hif_tx_complete);
|
||||
|
||||
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
@ -454,9 +472,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
if (res < 0) {
|
||||
if (res < 0)
|
||||
goto err_tx_dec;
|
||||
}
|
||||
|
||||
msdu_id = res;
|
||||
|
||||
txdesc = ath10k_htc_alloc_skb(ar, len);
|
||||
@ -521,7 +539,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
int res;
|
||||
u8 flags0 = 0;
|
||||
u16 msdu_id, flags1 = 0;
|
||||
dma_addr_t paddr = 0;
|
||||
u32 frags_paddr = 0;
|
||||
struct htt_msdu_ext_desc *ext_desc = NULL;
|
||||
bool limit_mgmt_desc = false;
|
||||
@ -542,21 +559,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
if (res < 0) {
|
||||
if (res < 0)
|
||||
goto err_tx_dec;
|
||||
}
|
||||
|
||||
msdu_id = res;
|
||||
|
||||
prefetch_len = min(htt->prefetch_len, msdu->len);
|
||||
prefetch_len = roundup(prefetch_len, 4);
|
||||
|
||||
skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
|
||||
&paddr);
|
||||
if (!skb_cb->htt.txbuf) {
|
||||
res = -ENOMEM;
|
||||
goto err_free_msdu_id;
|
||||
}
|
||||
skb_cb->htt.txbuf_paddr = paddr;
|
||||
skb_cb->htt.txbuf = &htt->txbuf.vaddr[msdu_id];
|
||||
skb_cb->htt.txbuf_paddr = htt->txbuf.paddr +
|
||||
(sizeof(struct ath10k_htt_txbuf) * msdu_id);
|
||||
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
@ -574,7 +587,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
res = dma_mapping_error(dev, skb_cb->paddr);
|
||||
if (res) {
|
||||
res = -EIO;
|
||||
goto err_free_txbuf;
|
||||
goto err_free_msdu_id;
|
||||
}
|
||||
|
||||
switch (skb_cb->txmode) {
|
||||
@ -706,10 +719,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
|
||||
err_unmap_msdu:
|
||||
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
|
||||
err_free_txbuf:
|
||||
dma_pool_free(htt->tx_pool,
|
||||
skb_cb->htt.txbuf,
|
||||
skb_cb->htt.txbuf_paddr);
|
||||
err_free_msdu_id:
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
|
@ -97,6 +97,9 @@ enum qca6174_chip_id_rev {
|
||||
|
||||
/* includes also the null byte */
|
||||
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
|
||||
#define ATH10K_BOARD_MAGIC "QCA-ATH10K-BOARD"
|
||||
|
||||
#define ATH10K_BOARD_API2_FILE "board-2.bin"
|
||||
|
||||
#define REG_DUMP_COUNT_QCA988X 60
|
||||
|
||||
@ -159,6 +162,16 @@ enum ath10k_fw_htt_op_version {
|
||||
ATH10K_FW_HTT_OP_VERSION_MAX,
|
||||
};
|
||||
|
||||
enum ath10k_bd_ie_type {
|
||||
/* contains sub IEs of enum ath10k_bd_ie_board_type */
|
||||
ATH10K_BD_IE_BOARD = 0,
|
||||
};
|
||||
|
||||
enum ath10k_bd_ie_board_type {
|
||||
ATH10K_BD_IE_BOARD_NAME = 0,
|
||||
ATH10K_BD_IE_BOARD_DATA = 1,
|
||||
};
|
||||
|
||||
enum ath10k_hw_rev {
|
||||
ATH10K_HW_QCA988X,
|
||||
ATH10K_HW_QCA6174,
|
||||
|
@ -197,9 +197,8 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
||||
if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags))
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
}
|
||||
|
||||
if (cmd == DISABLE_KEY) {
|
||||
arg.key_cipher = WMI_CIPHER_NONE;
|
||||
@ -1111,7 +1110,8 @@ static int ath10k_monitor_recalc(struct ath10k *ar)
|
||||
|
||||
ret = ath10k_monitor_stop(ar);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to stop disallowed monitor: %d\n", ret);
|
||||
ath10k_warn(ar, "failed to stop disallowed monitor: %d\n",
|
||||
ret);
|
||||
/* not serious */
|
||||
}
|
||||
|
||||
@ -2084,7 +2084,8 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
||||
enum ieee80211_band band;
|
||||
const u8 *ht_mcs_mask;
|
||||
const u16 *vht_mcs_mask;
|
||||
int i, n, max_nss;
|
||||
int i, n;
|
||||
u8 max_nss;
|
||||
u32 stbc;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
@ -2169,7 +2170,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
||||
arg->peer_ht_rates.rates[i] = i;
|
||||
} else {
|
||||
arg->peer_ht_rates.num_rates = n;
|
||||
arg->peer_num_spatial_streams = max_nss;
|
||||
arg->peer_num_spatial_streams = min(sta->rx_nss, max_nss);
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
|
||||
@ -4065,6 +4066,7 @@ static u32 get_nss_from_chainmask(u16 chain_mask)
|
||||
static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
|
||||
{
|
||||
int nsts = ar->vht_cap_info;
|
||||
|
||||
nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
||||
nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
||||
|
||||
@ -4081,8 +4083,9 @@ static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
|
||||
static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
|
||||
{
|
||||
int sound_dim = ar->vht_cap_info;
|
||||
|
||||
sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
|
||||
sound_dim >>=IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
||||
sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
||||
|
||||
/* If the sounding dimension is not advertised by the firmware,
|
||||
* let's use a default value of 1
|
||||
@ -4656,7 +4659,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
info->use_cts_prot ? 1 : 0);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n",
|
||||
info->use_cts_prot, arvif->vdev_id, ret);
|
||||
info->use_cts_prot, arvif->vdev_id, ret);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||
@ -6268,8 +6271,8 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
|
||||
rcu_read_lock();
|
||||
if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) {
|
||||
ieee80211_iter_chan_contexts_atomic(ar->hw,
|
||||
ath10k_mac_get_any_chandef_iter,
|
||||
&def);
|
||||
ath10k_mac_get_any_chandef_iter,
|
||||
&def);
|
||||
|
||||
if (vifs)
|
||||
def = &vifs[0].new_ctx->def;
|
||||
@ -7301,7 +7304,7 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
ath10k_reg_notifier);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to initialise regulatory: %i\n", ret);
|
||||
goto err_free;
|
||||
goto err_dfs_detector_exit;
|
||||
}
|
||||
|
||||
ar->hw->wiphy->cipher_suites = cipher_suites;
|
||||
@ -7310,7 +7313,7 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
ret = ieee80211_register_hw(ar->hw);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
|
||||
goto err_free;
|
||||
goto err_dfs_detector_exit;
|
||||
}
|
||||
|
||||
if (!ath_is_world_regd(&ar->ath_common.regulatory)) {
|
||||
@ -7324,10 +7327,16 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
|
||||
err_unregister:
|
||||
ieee80211_unregister_hw(ar->hw);
|
||||
|
||||
err_dfs_detector_exit:
|
||||
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
|
||||
ar->dfs_detector->exit(ar->dfs_detector);
|
||||
|
||||
err_free:
|
||||
kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels);
|
||||
kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels);
|
||||
|
||||
SET_IEEE80211_DEV(ar->hw, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,10 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
|
||||
struct ath10k_ce_pipe *rx_pipe,
|
||||
struct bmi_xfer *xfer);
|
||||
static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar);
|
||||
static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
|
||||
static const struct ce_attr host_ce_config_wlan[] = {
|
||||
/* CE0: host->target HTC control and raw streams */
|
||||
@ -112,6 +116,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
|
||||
.src_nentries = 16,
|
||||
.src_sz_max = 256,
|
||||
.dest_nentries = 0,
|
||||
.send_cb = ath10k_pci_htc_tx_cb,
|
||||
},
|
||||
|
||||
/* CE1: target->host HTT + HTC control */
|
||||
@ -120,6 +125,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 2048,
|
||||
.dest_nentries = 512,
|
||||
.recv_cb = ath10k_pci_htc_rx_cb,
|
||||
},
|
||||
|
||||
/* CE2: target->host WMI */
|
||||
@ -128,6 +134,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 2048,
|
||||
.dest_nentries = 128,
|
||||
.recv_cb = ath10k_pci_htc_rx_cb,
|
||||
},
|
||||
|
||||
/* CE3: host->target WMI */
|
||||
@ -136,6 +143,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
|
||||
.src_nentries = 32,
|
||||
.src_sz_max = 2048,
|
||||
.dest_nentries = 0,
|
||||
.send_cb = ath10k_pci_htc_tx_cb,
|
||||
},
|
||||
|
||||
/* CE4: host->target HTT */
|
||||
@ -144,14 +152,16 @@ static const struct ce_attr host_ce_config_wlan[] = {
|
||||
.src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES,
|
||||
.src_sz_max = 256,
|
||||
.dest_nentries = 0,
|
||||
.send_cb = ath10k_pci_htt_tx_cb,
|
||||
},
|
||||
|
||||
/* CE5: unused */
|
||||
/* CE5: target->host HTT (HIF->HTT) */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 0,
|
||||
.dest_nentries = 0,
|
||||
.src_sz_max = 512,
|
||||
.dest_nentries = 512,
|
||||
.recv_cb = ath10k_pci_htt_rx_cb,
|
||||
},
|
||||
|
||||
/* CE6: target autonomous hif_memcpy */
|
||||
@ -257,12 +267,12 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
|
||||
|
||||
/* NB: 50% of src nentries, since tx has 2 frags */
|
||||
|
||||
/* CE5: unused */
|
||||
/* CE5: target->host HTT (HIF->HTT) */
|
||||
{
|
||||
.pipenum = __cpu_to_le32(5),
|
||||
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
|
||||
.pipedir = __cpu_to_le32(PIPEDIR_IN),
|
||||
.nentries = __cpu_to_le32(32),
|
||||
.nbytes_max = __cpu_to_le32(2048),
|
||||
.nbytes_max = __cpu_to_le32(512),
|
||||
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
|
||||
.reserved = __cpu_to_le32(0),
|
||||
},
|
||||
@ -396,7 +406,7 @@ static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
|
||||
{
|
||||
__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
|
||||
__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
|
||||
__cpu_to_le32(1),
|
||||
__cpu_to_le32(5),
|
||||
},
|
||||
|
||||
/* (Additions here) */
|
||||
@ -452,8 +462,12 @@ static int ath10k_pci_wake_wait(struct ath10k *ar)
|
||||
int curr_delay = 5;
|
||||
|
||||
while (tot_delay < PCIE_WAKE_TIMEOUT) {
|
||||
if (ath10k_pci_is_awake(ar))
|
||||
if (ath10k_pci_is_awake(ar)) {
|
||||
if (tot_delay > PCIE_WAKE_LATE_US)
|
||||
ath10k_warn(ar, "device wakeup took %d ms which is unusally long, otherwise it works normally.\n",
|
||||
tot_delay / 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
udelay(curr_delay);
|
||||
tot_delay += curr_delay;
|
||||
@ -465,12 +479,53 @@ static int ath10k_pci_wake_wait(struct ath10k *ar)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int ath10k_pci_force_wake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
if (!ar_pci->ps_awake) {
|
||||
iowrite32(PCIE_SOC_WAKE_V_MASK,
|
||||
ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
|
||||
PCIE_SOC_WAKE_ADDRESS);
|
||||
|
||||
ret = ath10k_pci_wake_wait(ar);
|
||||
if (ret == 0)
|
||||
ar_pci->ps_awake = true;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_pci_force_sleep(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
iowrite32(PCIE_SOC_WAKE_RESET,
|
||||
ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
|
||||
PCIE_SOC_WAKE_ADDRESS);
|
||||
ar_pci->ps_awake = false;
|
||||
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
}
|
||||
|
||||
static int ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (ar_pci->pci_ps == 0)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n",
|
||||
@ -502,6 +557,9 @@ static void ath10k_pci_sleep(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
if (ar_pci->pci_ps == 0)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n",
|
||||
@ -544,6 +602,11 @@ static void ath10k_pci_sleep_sync(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
if (ar_pci->pci_ps == 0) {
|
||||
ath10k_pci_force_sleep(ar);
|
||||
return;
|
||||
}
|
||||
|
||||
del_timer_sync(&ar_pci->ps_timer);
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
@ -682,8 +745,6 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
|
||||
dma_addr_t paddr;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar_pci->ce_lock);
|
||||
|
||||
skb = dev_alloc_skb(pipe->buf_sz);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
@ -701,9 +762,10 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
|
||||
|
||||
ATH10K_SKB_RXCB(skb)->paddr = paddr;
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
|
||||
dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
@ -713,25 +775,27 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||
static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||
{
|
||||
struct ath10k *ar = pipe->hif_ce_state;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
|
||||
int ret, num;
|
||||
|
||||
lockdep_assert_held(&ar_pci->ce_lock);
|
||||
|
||||
if (pipe->buf_sz == 0)
|
||||
return;
|
||||
|
||||
if (!ce_pipe->dest_ring)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
while (num--) {
|
||||
ret = __ath10k_pci_rx_post_buf(pipe);
|
||||
if (ret) {
|
||||
if (ret == -ENOSPC)
|
||||
break;
|
||||
ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
|
||||
mod_timer(&ar_pci->rx_post_retry, jiffies +
|
||||
ATH10K_PCI_RX_POST_RETRY_MS);
|
||||
@ -740,25 +804,13 @@ static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||
{
|
||||
struct ath10k *ar = pipe->hif_ce_state;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
__ath10k_pci_rx_post_pipe(pipe);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
}
|
||||
|
||||
static void ath10k_pci_rx_post(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
for (i = 0; i < CE_COUNT; i++)
|
||||
__ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
|
||||
}
|
||||
|
||||
static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
|
||||
@ -1102,11 +1154,9 @@ static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when a send to Target completes. */
|
||||
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
|
||||
static void ath10k_pci_htc_tx_cb(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;
|
||||
struct sk_buff_head list;
|
||||
struct sk_buff *skb;
|
||||
u32 ce_data;
|
||||
@ -1124,16 +1174,16 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
|
||||
}
|
||||
|
||||
while ((skb = __skb_dequeue(&list)))
|
||||
cb->tx_completion(ar, skb);
|
||||
ath10k_htc_tx_completion_handler(ar, skb);
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when data is received from the Target. */
|
||||
static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
|
||||
static void ath10k_pci_process_rx_cb(struct ath10k_ce_pipe *ce_state,
|
||||
void (*callback)(struct ath10k *ar,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
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;
|
||||
@ -1168,12 +1218,56 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
|
||||
skb->data, skb->len);
|
||||
|
||||
cb->rx_completion(ar, skb);
|
||||
callback(ar, skb);
|
||||
}
|
||||
|
||||
ath10k_pci_rx_post_pipe(pipe_info);
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when data is received from the Target. */
|
||||
static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when a send to HTT Target completes. */
|
||||
static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct sk_buff *skb;
|
||||
u32 ce_data;
|
||||
unsigned int nbytes;
|
||||
unsigned int transfer_id;
|
||||
|
||||
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 (!skb)
|
||||
continue;
|
||||
|
||||
dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
ath10k_htt_hif_tx_complete(ar, skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_pci_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
|
||||
ath10k_htt_t2h_msg_handler(ar, skb);
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when HTT data is received from the Target. */
|
||||
static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
/* CE4 polling needs to be done whenever CE pipe which transports
|
||||
* HTT Rx (target->host) is processed.
|
||||
*/
|
||||
ath10k_ce_per_engine_service(ce_state->ar, 4);
|
||||
|
||||
ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver);
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
struct ath10k_hif_sg_item *items, int n_items)
|
||||
{
|
||||
@ -1343,17 +1437,6 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||
ath10k_ce_per_engine_service(ar, pipe);
|
||||
}
|
||||
|
||||
static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
|
||||
struct ath10k_hif_cb *callbacks)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n");
|
||||
|
||||
memcpy(&ar_pci->msg_callbacks_current, callbacks,
|
||||
sizeof(ar_pci->msg_callbacks_current));
|
||||
}
|
||||
|
||||
static void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
@ -1368,10 +1451,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
||||
del_timer_sync(&ar_pci->rx_post_retry);
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
u16 service_id, u8 *ul_pipe,
|
||||
u8 *dl_pipe, int *ul_is_polled,
|
||||
int *dl_is_polled)
|
||||
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
const struct service_to_pipe *entry;
|
||||
bool ul_set = false, dl_set = false;
|
||||
@ -1379,9 +1460,6 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
|
||||
|
||||
/* polling for received messages not supported */
|
||||
*dl_is_polled = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
|
||||
entry = &target_service_to_ce_map_wlan[i];
|
||||
|
||||
@ -1415,25 +1493,17 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
if (WARN_ON(!ul_set || !dl_set))
|
||||
return -ENOENT;
|
||||
|
||||
*ul_is_polled =
|
||||
(host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
int ul_is_polled, dl_is_polled;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
|
||||
|
||||
(void)ath10k_pci_hif_map_service_to_pipe(ar,
|
||||
ATH10K_HTC_SVC_ID_RSVD_CTRL,
|
||||
ul_pipe,
|
||||
dl_pipe,
|
||||
&ul_is_polled,
|
||||
&dl_is_polled);
|
||||
ul_pipe, dl_pipe);
|
||||
}
|
||||
|
||||
static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
|
||||
@ -1504,6 +1574,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
|
||||
static int ath10k_pci_hif_start(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
|
||||
|
||||
ath10k_pci_irq_enable(ar);
|
||||
@ -1579,7 +1650,7 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
|
||||
|
||||
ce_ring->per_transfer_context[i] = NULL;
|
||||
|
||||
ar_pci->msg_callbacks_current.tx_completion(ar, skb);
|
||||
ath10k_htc_tx_completion_handler(ar, skb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1999,9 +2070,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
||||
pipe->pipe_num = i;
|
||||
pipe->hif_ce_state = ar;
|
||||
|
||||
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i],
|
||||
ath10k_pci_ce_send_done,
|
||||
ath10k_pci_ce_recv_data);
|
||||
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
|
||||
i, ret);
|
||||
@ -2257,7 +2326,7 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar)
|
||||
ret = ath10k_pci_wait_for_target_init(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",
|
||||
ret);
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2397,6 +2466,15 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct pci_dev *pdev = ar_pci->pdev;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
if (ar_pci->pci_ps == 0) {
|
||||
ret = ath10k_pci_force_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to wake up target: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Suspend/Resume resets the PCI configuration space, so we have to
|
||||
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
|
||||
@ -2407,7 +2485,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2421,7 +2499,6 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
|
||||
.map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe,
|
||||
.get_default_pipe = ath10k_pci_hif_get_default_pipe,
|
||||
.send_complete_check = ath10k_pci_hif_send_complete_check,
|
||||
.set_callbacks = ath10k_pci_hif_set_callbacks,
|
||||
.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,
|
||||
@ -2501,6 +2578,16 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
|
||||
{
|
||||
struct ath10k *ar = arg;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
if (ar_pci->pci_ps == 0) {
|
||||
ret = ath10k_pci_force_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake device up on irq: %d\n",
|
||||
ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ar_pci->num_msi_intrs == 0) {
|
||||
if (!ath10k_pci_irq_pending(ar))
|
||||
@ -2900,17 +2987,21 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
struct ath10k_pci *ar_pci;
|
||||
enum ath10k_hw_rev hw_rev;
|
||||
u32 chip_id;
|
||||
bool pci_ps;
|
||||
|
||||
switch (pci_dev->device) {
|
||||
case QCA988X_2_0_DEVICE_ID:
|
||||
hw_rev = ATH10K_HW_QCA988X;
|
||||
pci_ps = false;
|
||||
break;
|
||||
case QCA6164_2_1_DEVICE_ID:
|
||||
case QCA6174_2_1_DEVICE_ID:
|
||||
hw_rev = ATH10K_HW_QCA6174;
|
||||
pci_ps = true;
|
||||
break;
|
||||
case QCA99X0_2_0_DEVICE_ID:
|
||||
hw_rev = ATH10K_HW_QCA99X0;
|
||||
pci_ps = false;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
@ -2924,19 +3015,21 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n");
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
|
||||
pdev->vendor, pdev->device,
|
||||
pdev->subsystem_vendor, pdev->subsystem_device);
|
||||
|
||||
ar_pci = ath10k_pci_priv(ar);
|
||||
ar_pci->pdev = pdev;
|
||||
ar_pci->dev = &pdev->dev;
|
||||
ar_pci->ar = ar;
|
||||
ar->dev_id = pci_dev->device;
|
||||
ar_pci->pci_ps = pci_ps;
|
||||
|
||||
if (pdev->subsystem_vendor || pdev->subsystem_device)
|
||||
scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id),
|
||||
"%04x:%04x:%04x:%04x",
|
||||
pdev->vendor, pdev->device,
|
||||
pdev->subsystem_vendor, pdev->subsystem_device);
|
||||
ar->id.vendor = pdev->vendor;
|
||||
ar->id.device = pdev->device;
|
||||
ar->id.subsystem_vendor = pdev->subsystem_vendor;
|
||||
ar->id.subsystem_device = pdev->subsystem_device;
|
||||
|
||||
spin_lock_init(&ar_pci->ce_lock);
|
||||
spin_lock_init(&ar_pci->ps_lock);
|
||||
@ -2962,6 +3055,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
ath10k_pci_irq_disable(ar);
|
||||
|
||||
if (ar_pci->pci_ps == 0) {
|
||||
ret = ath10k_pci_force_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake up device : %d\n", ret);
|
||||
goto err_free_pipes;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath10k_pci_init_irq(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to init irqs: %d\n", ret);
|
||||
@ -3090,13 +3191,16 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
|
||||
|
||||
/* QCA6174 2.1 firmware files */
|
||||
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE);
|
||||
|
||||
/* QCA6174 3.1 firmware files */
|
||||
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
|
||||
|
@ -175,8 +175,6 @@ struct ath10k_pci {
|
||||
|
||||
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
|
||||
|
||||
struct ath10k_hif_cb msg_callbacks_current;
|
||||
|
||||
/* Copy Engine used for Diagnostic Accesses */
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
|
||||
@ -221,6 +219,12 @@ struct ath10k_pci {
|
||||
* powersave register state changes.
|
||||
*/
|
||||
bool ps_awake;
|
||||
|
||||
/* pci power save, disable for QCA988X and QCA99X0.
|
||||
* Writing 'false' to this variable avoids frequent locking
|
||||
* on MMIO read/write.
|
||||
*/
|
||||
bool pci_ps;
|
||||
};
|
||||
|
||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
@ -230,7 +234,8 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
|
||||
#define ATH10K_PCI_RX_POST_RETRY_MS 50
|
||||
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
|
||||
#define PCIE_WAKE_TIMEOUT 10000 /* 10ms */
|
||||
#define PCIE_WAKE_TIMEOUT 30000 /* 30ms */
|
||||
#define PCIE_WAKE_LATE_US 10000 /* 10ms */
|
||||
|
||||
#define BAR_NUM 0
|
||||
|
||||
|
@ -215,6 +215,6 @@ err_cooling_destroy:
|
||||
|
||||
void ath10k_thermal_unregister(struct ath10k *ar)
|
||||
{
|
||||
thermal_cooling_device_unregister(ar->thermal.cdev);
|
||||
sysfs_remove_link(&ar->dev->kobj, "cooling_device");
|
||||
thermal_cooling_device_unregister(ar->thermal.cdev);
|
||||
}
|
||||
|
@ -92,11 +92,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
skb_cb = ATH10K_SKB_CB(msdu);
|
||||
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
|
||||
|
||||
if (skb_cb->htt.txbuf)
|
||||
dma_pool_free(htt->tx_pool,
|
||||
skb_cb->htt.txbuf,
|
||||
skb_cb->htt.txbuf_paddr);
|
||||
|
||||
ath10k_report_offchan_tx(htt->ar, msdu);
|
||||
|
||||
info = IEEE80211_SKB_CB(msdu);
|
||||
|
@ -177,6 +177,11 @@ struct wmi_ops {
|
||||
const struct wmi_tdls_peer_capab_arg *cap,
|
||||
const struct wmi_channel_arg *chan);
|
||||
struct sk_buff *(*gen_adaptive_qcs)(struct ath10k *ar, bool enable);
|
||||
struct sk_buff *(*gen_pdev_get_tpc_config)(struct ath10k *ar,
|
||||
u32 param);
|
||||
void (*fw_stats_fill)(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *fw_stats,
|
||||
char *buf);
|
||||
};
|
||||
|
||||
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
|
||||
@ -1270,4 +1275,31 @@ ath10k_wmi_adaptive_qcs(struct ath10k *ar, bool enable)
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->adaptive_qcs_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_pdev_get_tpc_config(struct ath10k *ar, u32 param)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!ar->wmi.ops->gen_pdev_get_tpc_config)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
skb = ar->wmi.ops->gen_pdev_get_tpc_config(ar, param);
|
||||
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb,
|
||||
ar->wmi.cmd->pdev_get_tpc_config_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats,
|
||||
char *buf)
|
||||
{
|
||||
if (!ar->wmi.ops->fw_stats_fill)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ar->wmi.ops->fw_stats_fill(ar, fw_stats, buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -3468,6 +3468,7 @@ static const struct wmi_ops wmi_tlv_ops = {
|
||||
.gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
|
||||
.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
|
||||
.gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
|
||||
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
|
||||
};
|
||||
|
||||
/************/
|
||||
|
@ -3018,8 +3018,6 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
|
||||
memcpy(skb_put(bcn, arvif->u.ap.noa_len),
|
||||
arvif->u.ap.noa_data,
|
||||
arvif->u.ap.noa_len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
|
||||
@ -3507,7 +3505,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
|
||||
tsf);
|
||||
if (res < 0) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "failed to process fft report: %d\n",
|
||||
res);
|
||||
res);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -3835,9 +3833,258 @@ void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb)
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
|
||||
}
|
||||
|
||||
static u8 ath10k_tpc_config_get_rate(struct ath10k *ar,
|
||||
struct wmi_pdev_tpc_config_event *ev,
|
||||
u32 rate_idx, u32 num_chains,
|
||||
u32 rate_code, u8 type)
|
||||
{
|
||||
u8 tpc, num_streams, preamble, ch, stm_idx;
|
||||
|
||||
num_streams = ATH10K_HW_NSS(rate_code);
|
||||
preamble = ATH10K_HW_PREAMBLE(rate_code);
|
||||
ch = num_chains - 1;
|
||||
|
||||
tpc = min_t(u8, ev->rates_array[rate_idx], ev->max_reg_allow_pow[ch]);
|
||||
|
||||
if (__le32_to_cpu(ev->num_tx_chain) <= 1)
|
||||
goto out;
|
||||
|
||||
if (preamble == WMI_RATE_PREAMBLE_CCK)
|
||||
goto out;
|
||||
|
||||
stm_idx = num_streams - 1;
|
||||
if (num_chains <= num_streams)
|
||||
goto out;
|
||||
|
||||
switch (type) {
|
||||
case WMI_TPC_TABLE_TYPE_STBC:
|
||||
tpc = min_t(u8, tpc,
|
||||
ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx]);
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_TXBF:
|
||||
tpc = min_t(u8, tpc,
|
||||
ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx]);
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_CDD:
|
||||
tpc = min_t(u8, tpc,
|
||||
ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx]);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "unknown wmi tpc table type: %d\n", type);
|
||||
tpc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return tpc;
|
||||
}
|
||||
|
||||
static void ath10k_tpc_config_disp_tables(struct ath10k *ar,
|
||||
struct wmi_pdev_tpc_config_event *ev,
|
||||
struct ath10k_tpc_stats *tpc_stats,
|
||||
u8 *rate_code, u16 *pream_table, u8 type)
|
||||
{
|
||||
u32 i, j, pream_idx, flags;
|
||||
u8 tpc[WMI_TPC_TX_N_CHAIN];
|
||||
char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
|
||||
char buff[WMI_TPC_BUF_SIZE];
|
||||
|
||||
flags = __le32_to_cpu(ev->flags);
|
||||
|
||||
switch (type) {
|
||||
case WMI_TPC_TABLE_TYPE_CDD:
|
||||
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n");
|
||||
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_STBC:
|
||||
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n");
|
||||
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_TXBF:
|
||||
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n");
|
||||
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"invalid table type in wmi tpc event: %d\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
pream_idx = 0;
|
||||
for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
|
||||
memset(tpc_value, 0, sizeof(tpc_value));
|
||||
memset(buff, 0, sizeof(buff));
|
||||
if (i == pream_table[pream_idx])
|
||||
pream_idx++;
|
||||
|
||||
for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
|
||||
if (j >= __le32_to_cpu(ev->num_tx_chain))
|
||||
break;
|
||||
|
||||
tpc[j] = ath10k_tpc_config_get_rate(ar, ev, i, j + 1,
|
||||
rate_code[i],
|
||||
type);
|
||||
snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
|
||||
strncat(tpc_value, buff, strlen(buff));
|
||||
}
|
||||
tpc_stats->tpc_table[type].pream_idx[i] = pream_idx;
|
||||
tpc_stats->tpc_table[type].rate_code[i] = rate_code[i];
|
||||
memcpy(tpc_stats->tpc_table[type].tpc_value[i],
|
||||
tpc_value, sizeof(tpc_value));
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
|
||||
u32 i, j, pream_idx, num_tx_chain;
|
||||
u8 rate_code[WMI_TPC_RATE_MAX], rate_idx;
|
||||
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
||||
struct wmi_pdev_tpc_config_event *ev;
|
||||
struct ath10k_tpc_stats *tpc_stats;
|
||||
|
||||
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
|
||||
|
||||
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
||||
if (!tpc_stats)
|
||||
return;
|
||||
|
||||
/* Create the rate code table based on the chains supported */
|
||||
rate_idx = 0;
|
||||
pream_idx = 0;
|
||||
|
||||
/* Fill CCK rate code */
|
||||
for (i = 0; i < 4; i++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(i, 0, WMI_RATE_PREAMBLE_CCK);
|
||||
rate_idx++;
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
/* Fill OFDM rate code */
|
||||
for (i = 0; i < 8; i++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(i, 0, WMI_RATE_PREAMBLE_OFDM);
|
||||
rate_idx++;
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
||||
|
||||
/* Fill HT20 rate code */
|
||||
for (i = 0; i < num_tx_chain; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_HT);
|
||||
rate_idx++;
|
||||
}
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
/* Fill HT40 rate code */
|
||||
for (i = 0; i < num_tx_chain; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_HT);
|
||||
rate_idx++;
|
||||
}
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
/* Fill VHT20 rate code */
|
||||
for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) {
|
||||
for (j = 0; j < 10; j++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
|
||||
rate_idx++;
|
||||
}
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
/* Fill VHT40 rate code */
|
||||
for (i = 0; i < num_tx_chain; i++) {
|
||||
for (j = 0; j < 10; j++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
|
||||
rate_idx++;
|
||||
}
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
/* Fill VHT80 rate code */
|
||||
for (i = 0; i < num_tx_chain; i++) {
|
||||
for (j = 0; j < 10; j++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
|
||||
rate_idx++;
|
||||
}
|
||||
}
|
||||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
rate_code[rate_idx++] =
|
||||
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_CCK);
|
||||
rate_code[rate_idx++] =
|
||||
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
|
||||
rate_code[rate_idx++] =
|
||||
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_CCK);
|
||||
rate_code[rate_idx++] =
|
||||
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
|
||||
rate_code[rate_idx++] =
|
||||
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
|
||||
|
||||
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END;
|
||||
|
||||
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
|
||||
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
|
||||
tpc_stats->ctl = __le32_to_cpu(ev->ctl);
|
||||
tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain);
|
||||
tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain);
|
||||
tpc_stats->twice_antenna_reduction =
|
||||
__le32_to_cpu(ev->twice_antenna_reduction);
|
||||
tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
|
||||
tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
|
||||
tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
||||
tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
|
||||
|
||||
ath10k_tpc_config_disp_tables(ar, ev, tpc_stats,
|
||||
rate_code, pream_table,
|
||||
WMI_TPC_TABLE_TYPE_CDD);
|
||||
ath10k_tpc_config_disp_tables(ar, ev, tpc_stats,
|
||||
rate_code, pream_table,
|
||||
WMI_TPC_TABLE_TYPE_STBC);
|
||||
ath10k_tpc_config_disp_tables(ar, ev, tpc_stats,
|
||||
rate_code, pream_table,
|
||||
WMI_TPC_TABLE_TYPE_TXBF);
|
||||
|
||||
ath10k_debug_tpc_stats_process(ar, tpc_stats);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi event tpc config channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n",
|
||||
__le32_to_cpu(ev->chan_freq),
|
||||
__le32_to_cpu(ev->phy_mode),
|
||||
__le32_to_cpu(ev->ctl),
|
||||
__le32_to_cpu(ev->reg_domain),
|
||||
a_sle32_to_cpu(ev->twice_antenna_gain),
|
||||
__le32_to_cpu(ev->twice_antenna_reduction),
|
||||
__le32_to_cpu(ev->power_limit),
|
||||
__le32_to_cpu(ev->twice_max_rd_power) / 2,
|
||||
__le32_to_cpu(ev->num_tx_chain),
|
||||
__le32_to_cpu(ev->rate_max));
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
|
||||
@ -5090,7 +5337,7 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar)
|
||||
config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
|
||||
config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI);
|
||||
|
||||
config.rx_decap_mode = __cpu_to_le32(TARGET_10_4_RX_DECAP_MODE);
|
||||
config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode);
|
||||
config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS);
|
||||
config.bmiss_offload_max_vdev =
|
||||
__cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV);
|
||||
@ -6356,6 +6603,399 @@ ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config(struct ath10k *ar, u32 param)
|
||||
{
|
||||
struct wmi_pdev_get_tpc_config_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cmd = (struct wmi_pdev_get_tpc_config_cmd *)skb->data;
|
||||
cmd->param = __cpu_to_le32(param);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi pdev get tcp config param:%d\n", param);
|
||||
return skb;
|
||||
}
|
||||
|
||||
size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head)
|
||||
{
|
||||
struct ath10k_fw_stats_peer *i;
|
||||
size_t num = 0;
|
||||
|
||||
list_for_each_entry(i, head, list)
|
||||
++num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head)
|
||||
{
|
||||
struct ath10k_fw_stats_vdev *i;
|
||||
size_t num = 0;
|
||||
|
||||
list_for_each_entry(i, head, list)
|
||||
++num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_fw_pdev_base_stats_fill(const struct ath10k_fw_stats_pdev *pdev,
|
||||
char *buf, u32 *length)
|
||||
{
|
||||
u32 len = *length;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Channel noise floor", pdev->ch_noise_floor);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"Channel TX power", pdev->chan_tx_power);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"TX frame count", pdev->tx_frame_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RX frame count", pdev->rx_frame_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RX clear count", pdev->rx_clear_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"Cycle count", pdev->cycle_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"PHY error count", pdev->phy_err_count);
|
||||
|
||||
*length = len;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_fw_pdev_extra_stats_fill(const struct ath10k_fw_stats_pdev *pdev,
|
||||
char *buf, u32 *length)
|
||||
{
|
||||
u32 len = *length;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RTS bad count", pdev->rts_bad);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RTS good count", pdev->rts_good);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"FCS bad count", pdev->fcs_bad);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"No beacon count", pdev->no_beacons);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"MIB int count", pdev->mib_int_count);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
*length = len;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_fw_pdev_tx_stats_fill(const struct ath10k_fw_stats_pdev *pdev,
|
||||
char *buf, u32 *length)
|
||||
{
|
||||
u32 len = *length;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n%30s\n",
|
||||
"ath10k PDEV TX stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HTT cookies queued", pdev->comp_queued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HTT cookies disp.", pdev->comp_delivered);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDU queued", pdev->msdu_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU queued", pdev->mpdu_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs dropped", pdev->wmm_drop);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Local enqued", pdev->local_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Local freed", pdev->local_freed);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HW queued", pdev->hw_queued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PPDUs reaped", pdev->hw_reaped);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Num underruns", pdev->underrun);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PPDUs cleaned", pdev->tx_abort);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs requed", pdev->mpdus_requed);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Excessive retries", pdev->tx_ko);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HW rate", pdev->data_rc);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Sched self tiggers", pdev->self_triggers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Dropped due to SW retries",
|
||||
pdev->sw_retry_failure);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Illegal rate phy errors",
|
||||
pdev->illgl_rate_phy_err);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Pdev continuous xretry", pdev->pdev_cont_xretry);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"TX timeout", pdev->pdev_tx_timeout);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PDEV resets", pdev->pdev_resets);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY underrun", pdev->phy_underrun);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU is more than txop limit", pdev->txop_ovf);
|
||||
*length = len;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_fw_pdev_rx_stats_fill(const struct ath10k_fw_stats_pdev *pdev,
|
||||
char *buf, u32 *length)
|
||||
{
|
||||
u32 len = *length;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n%30s\n",
|
||||
"ath10k PDEV RX stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Mid PPDU route change",
|
||||
pdev->mid_ppdu_route_change);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Tot. number of statuses", pdev->status_rcvd);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 0", pdev->r0_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 1", pdev->r1_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 2", pdev->r2_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 3", pdev->r3_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs delivered to HTT", pdev->htt_msdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to HTT", pdev->htt_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs delivered to stack", pdev->loc_msdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to stack", pdev->loc_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Oversized AMSUs", pdev->oversize_amsdu);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors", pdev->phy_errs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors drops", pdev->phy_err_drop);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
|
||||
*length = len;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_fw_vdev_stats_fill(const struct ath10k_fw_stats_vdev *vdev,
|
||||
char *buf, u32 *length)
|
||||
{
|
||||
u32 len = *length;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
int i;
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"vdev id", vdev->vdev_id);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"beacon snr", vdev->beacon_snr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"data snr", vdev->data_snr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rx frames", vdev->num_rx_frames);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rts fail", vdev->num_rts_fail);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rts success", vdev->num_rts_success);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rx err", vdev->num_rx_err);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num rx discard", vdev->num_rx_discard);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"num tx not acked", vdev->num_tx_not_acked);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"num tx frames", i,
|
||||
vdev->num_tx_frames[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"num tx frames retries", i,
|
||||
vdev->num_tx_frames_retries[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"num tx frames failures", i,
|
||||
vdev->num_tx_frames_failures[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] 0x%08x\n",
|
||||
"tx rate history", i,
|
||||
vdev->tx_rate_history[i]);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++)
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"%25s [%02d] %u\n",
|
||||
"beacon rssi history", i,
|
||||
vdev->beacon_rssi_history[i]);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
*length = len;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer,
|
||||
char *buf, u32 *length)
|
||||
{
|
||||
u32 len = *length;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
|
||||
"Peer MAC address", peer->peer_macaddr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer RSSI", peer->peer_rssi);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer TX rate", peer->peer_tx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer RX rate", peer->peer_rx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
*length = len;
|
||||
}
|
||||
|
||||
void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *fw_stats,
|
||||
char *buf)
|
||||
{
|
||||
u32 len = 0;
|
||||
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
const struct ath10k_fw_stats_pdev *pdev;
|
||||
const struct ath10k_fw_stats_vdev *vdev;
|
||||
const struct ath10k_fw_stats_peer *peer;
|
||||
size_t num_peers;
|
||||
size_t num_vdevs;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
pdev = list_first_entry_or_null(&fw_stats->pdevs,
|
||||
struct ath10k_fw_stats_pdev, list);
|
||||
if (!pdev) {
|
||||
ath10k_warn(ar, "failed to get pdev stats\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers);
|
||||
num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs);
|
||||
|
||||
ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len);
|
||||
ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len);
|
||||
ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
|
||||
"ath10k VDEV stats", num_vdevs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
list_for_each_entry(vdev, &fw_stats->vdevs, list) {
|
||||
ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len);
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
|
||||
"ath10k PEER stats", num_peers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
list_for_each_entry(peer, &fw_stats->peers, list) {
|
||||
ath10k_wmi_fw_peer_stats_fill(peer, buf, &len);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (len >= buf_len)
|
||||
buf[len - 1] = 0;
|
||||
else
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *fw_stats,
|
||||
char *buf)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
|
||||
const struct ath10k_fw_stats_pdev *pdev;
|
||||
const struct ath10k_fw_stats_vdev *vdev;
|
||||
const struct ath10k_fw_stats_peer *peer;
|
||||
size_t num_peers;
|
||||
size_t num_vdevs;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
pdev = list_first_entry_or_null(&fw_stats->pdevs,
|
||||
struct ath10k_fw_stats_pdev, list);
|
||||
if (!pdev) {
|
||||
ath10k_warn(ar, "failed to get pdev stats\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers);
|
||||
num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs);
|
||||
|
||||
ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len);
|
||||
ath10k_wmi_fw_pdev_extra_stats_fill(pdev, buf, &len);
|
||||
ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len);
|
||||
ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
|
||||
"ath10k VDEV stats", num_vdevs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
list_for_each_entry(vdev, &fw_stats->vdevs, list) {
|
||||
ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len);
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
|
||||
"ath10k PEER stats", num_peers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
list_for_each_entry(peer, &fw_stats->peers, list) {
|
||||
ath10k_wmi_fw_peer_stats_fill(peer, buf, &len);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (len >= buf_len)
|
||||
buf[len - 1] = 0;
|
||||
else
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
static const struct wmi_ops wmi_ops = {
|
||||
.rx = ath10k_wmi_op_rx,
|
||||
.map_svc = wmi_main_svc_map,
|
||||
@ -6414,6 +7054,7 @@ static const struct wmi_ops wmi_ops = {
|
||||
.gen_addba_send = ath10k_wmi_op_gen_addba_send,
|
||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
|
||||
/* .gen_bcn_tmpl not implemented */
|
||||
/* .gen_prb_tmpl not implemented */
|
||||
/* .gen_p2p_go_bcn_ie not implemented */
|
||||
@ -6479,6 +7120,7 @@ static const struct wmi_ops wmi_10_1_ops = {
|
||||
.gen_addba_send = ath10k_wmi_op_gen_addba_send,
|
||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
||||
/* .gen_bcn_tmpl not implemented */
|
||||
/* .gen_prb_tmpl not implemented */
|
||||
/* .gen_p2p_go_bcn_ie not implemented */
|
||||
@ -6545,6 +7187,7 @@ static const struct wmi_ops wmi_10_2_ops = {
|
||||
.gen_addba_send = ath10k_wmi_op_gen_addba_send,
|
||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
||||
};
|
||||
|
||||
static const struct wmi_ops wmi_10_2_4_ops = {
|
||||
@ -6606,6 +7249,8 @@ static const struct wmi_ops wmi_10_2_4_ops = {
|
||||
.gen_addba_send = ath10k_wmi_op_gen_addba_send,
|
||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||
.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
|
||||
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
||||
/* .gen_bcn_tmpl not implemented */
|
||||
/* .gen_prb_tmpl not implemented */
|
||||
/* .gen_p2p_go_bcn_ie not implemented */
|
||||
|
@ -73,6 +73,25 @@ struct wmi_cmd_hdr {
|
||||
#define HTC_PROTOCOL_VERSION 0x0002
|
||||
#define WMI_PROTOCOL_VERSION 0x0002
|
||||
|
||||
/*
|
||||
* There is no signed version of __le32, so for a temporary solution come
|
||||
* up with our own version. The idea is from fs/ntfs/types.h.
|
||||
*
|
||||
* Use a_ prefix so that it doesn't conflict if we get proper support to
|
||||
* linux/types.h.
|
||||
*/
|
||||
typedef __s32 __bitwise a_sle32;
|
||||
|
||||
static inline a_sle32 a_cpu_to_sle32(s32 val)
|
||||
{
|
||||
return (__force a_sle32)cpu_to_le32(val);
|
||||
}
|
||||
|
||||
static inline s32 a_sle32_to_cpu(a_sle32 val)
|
||||
{
|
||||
return le32_to_cpu((__force __le32)val);
|
||||
}
|
||||
|
||||
enum wmi_service {
|
||||
WMI_SERVICE_BEACON_OFFLOAD = 0,
|
||||
WMI_SERVICE_SCAN_OFFLOAD,
|
||||
@ -3642,8 +3661,18 @@ struct wmi_pdev_get_tpc_config_cmd {
|
||||
__le32 param;
|
||||
} __packed;
|
||||
|
||||
#define WMI_TPC_CONFIG_PARAM 1
|
||||
#define WMI_TPC_RATE_MAX 160
|
||||
#define WMI_TPC_TX_N_CHAIN 4
|
||||
#define WMI_TPC_PREAM_TABLE_MAX 10
|
||||
#define WMI_TPC_FLAG 3
|
||||
#define WMI_TPC_BUF_SIZE 10
|
||||
|
||||
enum wmi_tpc_table_type {
|
||||
WMI_TPC_TABLE_TYPE_CDD = 0,
|
||||
WMI_TPC_TABLE_TYPE_STBC = 1,
|
||||
WMI_TPC_TABLE_TYPE_TXBF = 2,
|
||||
};
|
||||
|
||||
enum wmi_tpc_config_event_flag {
|
||||
WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD = 0x1,
|
||||
@ -3657,7 +3686,7 @@ struct wmi_pdev_tpc_config_event {
|
||||
__le32 phy_mode;
|
||||
__le32 twice_antenna_reduction;
|
||||
__le32 twice_max_rd_power;
|
||||
s32 twice_antenna_gain;
|
||||
a_sle32 twice_antenna_gain;
|
||||
__le32 power_limit;
|
||||
__le32 rate_max;
|
||||
__le32 num_tx_chain;
|
||||
@ -4253,6 +4282,11 @@ enum wmi_rate_preamble {
|
||||
WMI_RATE_PREAMBLE_VHT,
|
||||
};
|
||||
|
||||
#define ATH10K_HW_NSS(rate) (1 + (((rate) >> 4) & 0x3))
|
||||
#define ATH10K_HW_PREAMBLE(rate) (((rate) >> 6) & 0x3)
|
||||
#define ATH10K_HW_RATECODE(rate, nss, preamble) \
|
||||
(((preamble) << 6) | ((nss) << 4) | (rate))
|
||||
|
||||
/* Value to disable fixed rate setting */
|
||||
#define WMI_FIXED_RATE_NONE (0xff)
|
||||
|
||||
@ -6064,6 +6098,7 @@ struct ath10k;
|
||||
struct ath10k_vif;
|
||||
struct ath10k_fw_stats_pdev;
|
||||
struct ath10k_fw_stats_peer;
|
||||
struct ath10k_fw_stats;
|
||||
|
||||
int ath10k_wmi_attach(struct ath10k *ar);
|
||||
void ath10k_wmi_detach(struct ath10k *ar);
|
||||
@ -6145,4 +6180,13 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf,
|
||||
int left_len, struct wmi_phyerr_ev_arg *arg);
|
||||
void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *fw_stats,
|
||||
char *buf);
|
||||
void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *fw_stats,
|
||||
char *buf);
|
||||
size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head);
|
||||
size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head);
|
||||
|
||||
#endif /* _WMI_H_ */
|
||||
|
@ -2217,7 +2217,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
|
||||
/* enter / leave wow suspend on first vif always */
|
||||
first_vif = ath6kl_vif_first(ar);
|
||||
if (WARN_ON(unlikely(!first_vif)) ||
|
||||
if (WARN_ON(!first_vif) ||
|
||||
!ath6kl_cfg80211_ready(first_vif))
|
||||
return -EIO;
|
||||
|
||||
@ -2297,7 +2297,7 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
int ret;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (WARN_ON(unlikely(!vif)) ||
|
||||
if (WARN_ON(!vif) ||
|
||||
!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
|
@ -1085,9 +1085,7 @@ static int htc_setup_tx_complete(struct htc_target *target)
|
||||
send_pkt->completion = NULL;
|
||||
ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0);
|
||||
status = ath6kl_htc_tx_issue(target, send_pkt);
|
||||
|
||||
if (send_pkt != NULL)
|
||||
htc_reclaim_txctrl_buf(target, send_pkt);
|
||||
htc_reclaim_txctrl_buf(target, send_pkt);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -284,10 +284,10 @@ dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event)
|
||||
if (cd == NULL)
|
||||
return false;
|
||||
|
||||
dpd->last_pulse_ts = event->ts;
|
||||
/* reset detector on time stamp wraparound, caused by TSF reset */
|
||||
if (event->ts < dpd->last_pulse_ts)
|
||||
dpd_reset(dpd);
|
||||
dpd->last_pulse_ts = event->ts;
|
||||
|
||||
/* do type individual pattern matching */
|
||||
for (i = 0; i < dpd->num_radar_types; i++) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
config WIL6210
|
||||
tristate "Wilocity 60g WiFi card wil6210 support"
|
||||
select WANT_DEV_COREDUMP
|
||||
depends on CFG80211
|
||||
depends on PCI
|
||||
default n
|
||||
|
@ -17,6 +17,7 @@ wil6210-y += pmc.o
|
||||
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
|
||||
wil6210-y += wil_platform.o
|
||||
wil6210-y += ethtool.o
|
||||
wil6210-y += wil_crash_dump.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
@ -1373,6 +1373,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&p->tid_rx_lock);
|
||||
seq_printf(s,
|
||||
"Rx invalid frame: non-data %lu, short %lu, large %lu\n",
|
||||
p->stats.rx_non_data_frame,
|
||||
p->stats.rx_short_frame,
|
||||
p->stats.rx_large_frame);
|
||||
|
||||
seq_puts(s, "Rx/MCS:");
|
||||
for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
|
||||
mcs++)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -347,7 +347,12 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||
wil6210_mask_irq_misc(wil);
|
||||
|
||||
if (isr & ISR_MISC_FW_ERROR) {
|
||||
wil_err(wil, "Firmware error detected\n");
|
||||
u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE);
|
||||
u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE);
|
||||
|
||||
wil_err(wil,
|
||||
"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
|
||||
fw_assert_code, ucode_assert_code);
|
||||
clear_bit(wil_status_fwready, wil->status);
|
||||
/*
|
||||
* do not clear @isr here - we do 2-nd part in thread
|
||||
@ -386,6 +391,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
|
||||
wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
|
||||
|
||||
if (isr & ISR_MISC_FW_ERROR) {
|
||||
wil_fw_core_dump(wil);
|
||||
wil_notify_fw_error(wil);
|
||||
isr &= ~ISR_MISC_FW_ERROR;
|
||||
wil_fw_error_recovery(wil);
|
||||
|
@ -203,11 +203,13 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
* - disconnect single STA, already disconnected
|
||||
* - disconnect all
|
||||
*
|
||||
* For "disconnect all", there are 2 options:
|
||||
* For "disconnect all", there are 3 options:
|
||||
* - bssid == NULL
|
||||
* - bssid is broadcast address (ff:ff:ff:ff:ff:ff)
|
||||
* - bssid is our MAC address
|
||||
*/
|
||||
if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) {
|
||||
if (bssid && !is_broadcast_ether_addr(bssid) &&
|
||||
!ether_addr_equal_unaligned(ndev->dev_addr, bssid)) {
|
||||
cid = wil_find_cid(wil, bssid);
|
||||
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
|
||||
bssid, cid, reason_code);
|
||||
@ -765,6 +767,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
if (wil->hw_version == HW_VER_UNKNOWN)
|
||||
return -ENODEV;
|
||||
|
||||
set_bit(wil_status_resetting, wil->status);
|
||||
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil_bcast_fini(wil);
|
||||
@ -851,6 +855,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
void wil_fw_error_recovery(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "starting fw error recovery\n");
|
||||
|
||||
if (test_bit(wil_status_resetting, wil->status)) {
|
||||
wil_info(wil, "Reset already in progress\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wil->recovery_state = fw_recovery_pending;
|
||||
schedule_work(&wil->fw_error_worker);
|
||||
}
|
||||
|
@ -260,6 +260,7 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
|
||||
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int wil6210_suspend(struct device *dev, bool is_runtime)
|
||||
{
|
||||
@ -307,7 +308,6 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int wil6210_pm_suspend(struct device *dev)
|
||||
{
|
||||
return wil6210_suspend(dev, false);
|
||||
|
@ -110,7 +110,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
|
||||
*/
|
||||
for (i = 0; i < num_descriptors; i++) {
|
||||
struct vring_tx_desc *_d = &pmc->pring_va[i];
|
||||
struct vring_tx_desc dd, *d = ⅆ
|
||||
struct vring_tx_desc dd = {}, *d = ⅆ
|
||||
int j = 0;
|
||||
|
||||
pmc->descriptors[i].va = dma_alloc_coherent(dev,
|
||||
|
@ -205,6 +205,32 @@ out:
|
||||
spin_unlock(&sta->tid_rx_lock);
|
||||
}
|
||||
|
||||
/* process BAR frame, called in NAPI context */
|
||||
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
|
||||
{
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
struct wil_tid_ampdu_rx *r;
|
||||
|
||||
spin_lock(&sta->tid_rx_lock);
|
||||
|
||||
r = sta->tid_rx[tid];
|
||||
if (!r) {
|
||||
wil_err(wil, "BAR for non-existing CID %d TID %d\n", cid, tid);
|
||||
goto out;
|
||||
}
|
||||
if (seq_less(seq, r->head_seq_num)) {
|
||||
wil_err(wil, "BAR Seq 0x%03x preceding head 0x%03x\n",
|
||||
seq, r->head_seq_num);
|
||||
goto out;
|
||||
}
|
||||
wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n",
|
||||
cid, tid, seq, r->head_seq_num);
|
||||
wil_release_reorder_frames(wil, r, seq);
|
||||
|
||||
out:
|
||||
spin_unlock(&sta->tid_rx_lock);
|
||||
}
|
||||
|
||||
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
|
||||
int size, u16 ssn)
|
||||
{
|
||||
|
@ -358,6 +358,13 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
|
||||
}
|
||||
}
|
||||
|
||||
/* similar to ieee80211_ version, but FC contain only 1-st byte */
|
||||
static inline int wil_is_back_req(u8 fc)
|
||||
{
|
||||
return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
|
||||
(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* reap 1 frame from @swhead
|
||||
*
|
||||
@ -379,14 +386,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
||||
u16 dmalen;
|
||||
u8 ftype;
|
||||
int cid;
|
||||
int i = (int)vring->swhead;
|
||||
int i;
|
||||
struct wil_net_stats *stats;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
|
||||
|
||||
again:
|
||||
if (unlikely(wil_vring_is_empty(vring)))
|
||||
return NULL;
|
||||
|
||||
i = (int)vring->swhead;
|
||||
_d = &vring->va[i].rx;
|
||||
if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) {
|
||||
/* it is not error, we just reached end of Rx done area */
|
||||
@ -398,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
||||
wil_vring_advance_head(vring, 1);
|
||||
if (!skb) {
|
||||
wil_err(wil, "No Rx skb at [%d]\n", i);
|
||||
return NULL;
|
||||
goto again;
|
||||
}
|
||||
d = wil_skb_rxdesc(skb);
|
||||
*d = *_d;
|
||||
@ -409,13 +418,17 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
||||
|
||||
trace_wil6210_rx(i, d);
|
||||
wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", i, dmalen);
|
||||
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
|
||||
wil_hex_dump_txrx("RxD ", DUMP_PREFIX_NONE, 32, 4,
|
||||
(const void *)d, sizeof(*d), false);
|
||||
|
||||
cid = wil_rxdesc_cid(d);
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
if (unlikely(dmalen > sz)) {
|
||||
wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
|
||||
stats->rx_large_frame++;
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
goto again;
|
||||
}
|
||||
skb_trim(skb, dmalen);
|
||||
|
||||
@ -424,8 +437,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
||||
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
|
||||
cid = wil_rxdesc_cid(d);
|
||||
stats = &wil->sta[cid].stats;
|
||||
stats->last_mcs_rx = wil_rxdesc_mcs(d);
|
||||
if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
|
||||
stats->rx_per_mcs[stats->last_mcs_rx]++;
|
||||
@ -437,24 +448,47 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
||||
/* no extra checks if in sniffer mode */
|
||||
if (ndev->type != ARPHRD_ETHER)
|
||||
return skb;
|
||||
/*
|
||||
* Non-data frames may be delivered through Rx DMA channel (ex: BAR)
|
||||
/* Non-data frames may be delivered through Rx DMA channel (ex: BAR)
|
||||
* Driver should recognize it by frame type, that is found
|
||||
* in Rx descriptor. If type is not data, it is 802.11 frame as is
|
||||
*/
|
||||
ftype = wil_rxdesc_ftype(d) << 2;
|
||||
if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
|
||||
wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
|
||||
/* TODO: process it */
|
||||
u8 fc1 = wil_rxdesc_fc1(d);
|
||||
int mid = wil_rxdesc_mid(d);
|
||||
int tid = wil_rxdesc_tid(d);
|
||||
u16 seq = wil_rxdesc_seq(d);
|
||||
|
||||
wil_dbg_txrx(wil,
|
||||
"Non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n",
|
||||
fc1, mid, cid, tid, seq);
|
||||
stats->rx_non_data_frame++;
|
||||
if (wil_is_back_req(fc1)) {
|
||||
wil_dbg_txrx(wil,
|
||||
"BAR: MID %d CID %d TID %d Seq 0x%03x\n",
|
||||
mid, cid, tid, seq);
|
||||
wil_rx_bar(wil, cid, tid, seq);
|
||||
} else {
|
||||
/* print again all info. One can enable only this
|
||||
* without overhead for printing every Rx frame
|
||||
*/
|
||||
wil_dbg_txrx(wil,
|
||||
"Unhandled non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n",
|
||||
fc1, mid, cid, tid, seq);
|
||||
wil_hex_dump_txrx("RxD ", DUMP_PREFIX_NONE, 32, 4,
|
||||
(const void *)d, sizeof(*d), false);
|
||||
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN + snaplen)) {
|
||||
wil_err(wil, "Short frame, len = %d\n", skb->len);
|
||||
/* TODO: process it (i.e. BAR) */
|
||||
stats->rx_short_frame++;
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* L4 IDENT is on when HW calculated checksum, check status
|
||||
@ -1633,7 +1667,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) {
|
||||
wil_err(wil, "FW not connected\n");
|
||||
wil_err_ratelimited(wil, "FW not connected\n");
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) {
|
||||
|
@ -464,6 +464,12 @@ static inline int wil_rxdesc_subtype(struct vring_rx_desc *d)
|
||||
return WIL_GET_BITS(d->mac.d0, 12, 15);
|
||||
}
|
||||
|
||||
/* 1-st byte (with frame type/subtype) of FC field */
|
||||
static inline u8 wil_rxdesc_fc1(struct vring_rx_desc *d)
|
||||
{
|
||||
return (u8)(WIL_GET_BITS(d->mac.d0, 10, 15) << 2);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_seq(struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d0, 16, 27);
|
||||
@ -501,6 +507,7 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
|
||||
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
|
||||
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
|
||||
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq);
|
||||
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
|
||||
int size, u16 ssn);
|
||||
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
|
||||
|
@ -246,6 +246,10 @@ struct RGF_ICR {
|
||||
#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */
|
||||
#define JTAG_DEV_ID_SPARROW_B0 (0x2632072f)
|
||||
|
||||
/* crash codes for FW/Ucode stored here */
|
||||
#define RGF_FW_ASSERT_CODE (0x91f020)
|
||||
#define RGF_UCODE_ASSERT_CODE (0x91f028)
|
||||
|
||||
enum {
|
||||
HW_VER_UNKNOWN,
|
||||
HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */
|
||||
@ -405,6 +409,7 @@ enum { /* for wil6210_priv.status */
|
||||
wil_status_reset_done,
|
||||
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
|
||||
wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
|
||||
wil_status_resetting, /* reset in progress */
|
||||
wil_status_last /* keep last */
|
||||
};
|
||||
|
||||
@ -465,6 +470,9 @@ struct wil_net_stats {
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_errors;
|
||||
unsigned long rx_dropped;
|
||||
unsigned long rx_non_data_frame;
|
||||
unsigned long rx_short_frame;
|
||||
unsigned long rx_large_frame;
|
||||
u16 last_mcs_rx;
|
||||
u64 rx_per_mcs[WIL_MCS_MAX + 1];
|
||||
};
|
||||
@ -820,4 +828,6 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
|
||||
int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
|
||||
int wil_resume(struct wil6210_priv *wil, bool is_runtime);
|
||||
|
||||
void wil_fw_core_dump(struct wil6210_priv *wil);
|
||||
|
||||
#endif /* __WIL6210_H__ */
|
||||
|
115
drivers/net/wireless/ath/wil6210/wil_crash_dump.c
Normal file
115
drivers/net/wireless/ath/wil6210/wil_crash_dump.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "wil6210.h"
|
||||
#include <linux/devcoredump.h>
|
||||
|
||||
static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,
|
||||
u32 *out_dump_size, u32 *out_host_min)
|
||||
{
|
||||
int i;
|
||||
const struct fw_map *map;
|
||||
u32 host_min, host_max, tmp_max;
|
||||
|
||||
if (!out_dump_size)
|
||||
return -EINVAL;
|
||||
|
||||
/* calculate the total size of the unpacked crash dump */
|
||||
BUILD_BUG_ON(ARRAY_SIZE(fw_mapping) == 0);
|
||||
map = &fw_mapping[0];
|
||||
host_min = map->host;
|
||||
host_max = map->host + (map->to - map->from);
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) {
|
||||
map = &fw_mapping[i];
|
||||
|
||||
if (map->host < host_min)
|
||||
host_min = map->host;
|
||||
|
||||
tmp_max = map->host + (map->to - map->from);
|
||||
if (tmp_max > host_max)
|
||||
host_max = tmp_max;
|
||||
}
|
||||
|
||||
*out_dump_size = host_max - host_min;
|
||||
if (out_host_min)
|
||||
*out_host_min = host_min;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest,
|
||||
u32 size)
|
||||
{
|
||||
int i;
|
||||
const struct fw_map *map;
|
||||
void *data;
|
||||
u32 host_min, dump_size, offset, len;
|
||||
|
||||
if (wil_fw_get_crash_dump_bounds(wil, &dump_size, &host_min)) {
|
||||
wil_err(wil, "%s: fail to obtain crash dump size\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dump_size > size) {
|
||||
wil_err(wil, "%s: not enough space for dump. Need %d have %d\n",
|
||||
__func__, dump_size, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* copy to crash dump area */
|
||||
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
|
||||
map = &fw_mapping[i];
|
||||
|
||||
data = (void * __force)wil->csr + HOSTADDR(map->host);
|
||||
len = map->to - map->from;
|
||||
offset = map->host - host_min;
|
||||
|
||||
wil_dbg_misc(wil, "%s() - dump %s, size %d, offset %d\n",
|
||||
__func__, fw_mapping[i].name, len, offset);
|
||||
|
||||
wil_memcpy_fromio_32((void * __force)(dest + offset),
|
||||
(const void __iomem * __force)data, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_fw_core_dump(struct wil6210_priv *wil)
|
||||
{
|
||||
void *fw_dump_data;
|
||||
u32 fw_dump_size;
|
||||
|
||||
if (wil_fw_get_crash_dump_bounds(wil, &fw_dump_size, NULL)) {
|
||||
wil_err(wil, "%s: fail to get fw dump size\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
fw_dump_data = vzalloc(fw_dump_size);
|
||||
if (!fw_dump_data)
|
||||
return;
|
||||
|
||||
if (wil_fw_copy_crash_dump(wil, fw_dump_data, fw_dump_size)) {
|
||||
vfree(fw_dump_data);
|
||||
return;
|
||||
}
|
||||
/* fw_dump_data will be free in device coredump release function
|
||||
* after 5 min
|
||||
*/
|
||||
dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL);
|
||||
wil_info(wil, "%s: fw core dumped, size %d bytes\n", __func__,
|
||||
fw_dump_size);
|
||||
}
|
@ -1120,7 +1120,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
|
||||
cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
|
||||
cmd.sniffer_cfg.phy_support =
|
||||
cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
|
||||
? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
|
||||
? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS);
|
||||
} else {
|
||||
/* Initialize offload (in non-sniffer mode).
|
||||
* Linux IP stack always calculates IP checksum
|
||||
|
Loading…
Reference in New Issue
Block a user