提交 a9f89463 编写于 作者: K Kalle Valo

Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for 4.16. Major changes:

ath10k

* more preparation work for wcn3990 support

* add memory dump to firmware coredump files

wil6210

* support scheduled scan

* support 40-bit DMA addresses
......@@ -21,6 +21,7 @@ ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
ath10k_core-$(CONFIG_THERMAL) += thermal.o
ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
ath10k_core-$(CONFIG_PM) += wow.o
ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \
......
/*
* Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved.
* Copyright (c) 2016-2017 Qualcomm Atheros, Inc. All rights reserved.
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2014,2016-2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2015,2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -36,6 +36,10 @@ struct ath10k_ce_pipe;
#define CE_DESC_FLAGS_GATHER (1 << 0)
#define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
#define CE_WCN3990_DESC_FLAGS_GATHER BIT(31)
#define CE_DESC_FLAGS_GET_MASK GENMASK(4, 0)
#define CE_DESC_37BIT_ADDR_MASK GENMASK_ULL(37, 0)
/* Following desc flags are used in QCA99X0 */
#define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2)
......@@ -50,6 +54,16 @@ struct ce_desc {
__le16 flags; /* %CE_DESC_FLAGS_ */
};
struct ce_desc_64 {
__le64 addr;
__le16 nbytes; /* length in register map */
__le16 flags; /* fw_metadata_high */
__le32 toeplitz_hash_result;
};
#define CE_DESC_SIZE sizeof(struct ce_desc)
#define CE_DESC_SIZE_64 sizeof(struct ce_desc_64)
struct ath10k_ce_ring {
/* Number of entries in this ring; must be power of 2 */
unsigned int nentries;
......@@ -117,6 +131,7 @@ struct ath10k_ce_pipe {
unsigned int src_sz_max;
struct ath10k_ce_ring *src_ring;
struct ath10k_ce_ring *dest_ring;
const struct ath10k_ce_ops *ops;
};
/* Copy Engine settable attributes */
......@@ -160,7 +175,7 @@ struct ath10k_ce {
*/
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
void *per_transfer_send_context,
u32 buffer,
dma_addr_t buffer,
unsigned int nbytes,
/* 14 bits */
unsigned int transfer_id,
......@@ -168,7 +183,7 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
void *per_transfer_context,
u32 buffer,
dma_addr_t buffer,
unsigned int nbytes,
unsigned int transfer_id,
unsigned int flags);
......@@ -180,8 +195,8 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
/*==================Recv=======================*/
int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx,
dma_addr_t paddr);
void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries);
/* recv flags */
......@@ -222,7 +237,7 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
*/
int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp);
dma_addr_t *bufferp);
int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
......@@ -235,7 +250,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
*/
int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
dma_addr_t *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp);
......@@ -281,6 +296,31 @@ struct ce_attr {
void (*recv_cb)(struct ath10k_ce_pipe *);
};
struct ath10k_ce_ops {
struct ath10k_ce_ring *(*ce_alloc_src_ring)(struct ath10k *ar,
u32 ce_id,
const struct ce_attr *attr);
struct ath10k_ce_ring *(*ce_alloc_dst_ring)(struct ath10k *ar,
u32 ce_id,
const struct ce_attr *attr);
int (*ce_rx_post_buf)(struct ath10k_ce_pipe *pipe, void *ctx,
dma_addr_t paddr);
int (*ce_completed_recv_next_nolock)(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *nbytesp);
int (*ce_revoke_recv_next)(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
dma_addr_t *nbytesp);
void (*ce_extract_desc_data)(struct ath10k *ar,
struct ath10k_ce_ring *src_ring,
u32 sw_index, dma_addr_t *bufferp,
u32 *nbytesp, u32 *transfer_idp);
void (*ce_free_pipe)(struct ath10k *ar, int ce_id);
int (*ce_send_nolock)(struct ath10k_ce_pipe *pipe,
void *per_transfer_context,
dma_addr_t buffer, u32 nbytes,
u32 transfer_id, u32 flags);
};
static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
{
return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
......@@ -292,6 +332,12 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
#define CE_DEST_RING_TO_DESC(baddr, idx) \
(&(((struct ce_desc *)baddr)[idx]))
#define CE_SRC_RING_TO_DESC_64(baddr, idx) \
(&(((struct ce_desc_64 *)baddr)[idx]))
#define CE_DEST_RING_TO_DESC_64(baddr, idx) \
(&(((struct ce_desc_64 *)baddr)[idx]))
/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */
#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \
(((int)(toidx) - (int)(fromidx)) & (nentries_mask))
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -32,6 +32,7 @@
#include "htt.h"
#include "testmode.h"
#include "wmi-ops.h"
#include "coredump.h"
unsigned int ath10k_debug_mask;
static unsigned int ath10k_cryptmode_param;
......@@ -39,17 +40,25 @@ static bool uart_print;
static bool skip_otp;
static bool rawmode;
/* Enable ATH10K_FW_CRASH_DUMP_REGISTERS and ATH10K_FW_CRASH_DUMP_CE_DATA
* by default.
*/
unsigned long ath10k_coredump_mask = 0x3;
/* FIXME: most of these should be readonly */
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
module_param(uart_print, bool, 0644);
module_param(skip_otp, bool, 0644);
module_param(rawmode, bool, 0644);
module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);
MODULE_PARM_DESC(debug_mask, "Debugging mask");
MODULE_PARM_DESC(uart_print, "Uart target debugging");
MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
......@@ -78,6 +87,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA9887_HW_1_0_VERSION,
......@@ -105,6 +116,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA6174_HW_2_1_VERSION,
......@@ -131,6 +144,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA6174_HW_2_1_VERSION,
......@@ -157,6 +172,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA6174_HW_3_0_VERSION,
......@@ -183,6 +200,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA6174_HW_3_2_VERSION,
......@@ -212,6 +231,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
......@@ -244,6 +265,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA9984_HW_1_0_DEV_VERSION,
......@@ -281,6 +304,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
......@@ -317,6 +342,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
......@@ -343,6 +370,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
......@@ -371,6 +400,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = QCA4019_HW_1_0_DEV_VERSION,
......@@ -404,6 +435,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
},
{
.id = WCN3990_HW_1_0_DEV_VERSION,
......@@ -422,6 +455,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.num_peers = TARGET_HL_10_TLV_NUM_PEERS,
.ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT,
.num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES,
.target_64bit = true,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC,
},
};
......@@ -445,6 +480,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",
[ATH10K_FW_FEATURE_NO_PS] = "no-ps",
[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",
};
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
......@@ -1524,8 +1560,8 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
data += ie_len;
}
if (!fw_file->firmware_data ||
!fw_file->firmware_len) {
if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, fw_file->fw_features) &&
(!fw_file->firmware_data || !fw_file->firmware_len)) {
ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
ar->hw_params.fw.dir, name);
ret = -ENOMEDIUM;
......@@ -1551,6 +1587,7 @@ static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,
break;
case ATH10K_BUS_PCI:
case ATH10K_BUS_AHB:
case ATH10K_BUS_SNOC:
scnprintf(fw_name, fw_name_len, "%s-%d.bin",
ATH10K_FW_FILE_BASE, fw_api);
break;
......@@ -1836,7 +1873,7 @@ static void ath10k_core_restart(struct work_struct *work)
mutex_unlock(&ar->conf_mutex);
ret = ath10k_debug_fw_devcoredump(ar);
ret = ath10k_coredump_submit(ar);
if (ret)
ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d",
ret);
......@@ -2078,43 +2115,47 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
ar->running_fw = fw;
ath10k_bmi_start(ar);
if (ath10k_init_configure_target(ar)) {
status = -EINVAL;
goto err;
}
if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
ar->running_fw->fw_file.fw_features)) {
ath10k_bmi_start(ar);
status = ath10k_download_cal_data(ar);
if (status)
goto err;
if (ath10k_init_configure_target(ar)) {
status = -EINVAL;
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.
*/
if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
ar->running_fw->fw_file.fw_features)) {
status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);
if (status) {
ath10k_err(ar, "could not write to skip_clock_init: %d\n",
status);
status = ath10k_download_cal_data(ar);
if (status)
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.
*/
if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
ar->running_fw->fw_file.fw_features)) {
status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);
if (status) {
ath10k_err(ar, "could not write to skip_clock_init: %d\n",
status);
goto err;
}
}
}
status = ath10k_download_fw(ar);
if (status)
goto err;
status = ath10k_download_fw(ar);
if (status)
goto err;
status = ath10k_init_uart(ar);
if (status)
goto err;
status = ath10k_init_uart(ar);
if (status)
goto err;
if (ar->hif.bus == ATH10K_BUS_SDIO)
ath10k_init_sdio(ar);
if (ar->hif.bus == ATH10K_BUS_SDIO)
ath10k_init_sdio(ar);
}
ar->htc.htc_ops.target_send_suspend_complete =
ath10k_send_suspend_complete;
......@@ -2125,9 +2166,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
goto err;
}
status = ath10k_bmi_done(ar);
if (status)
goto err;
if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
ar->running_fw->fw_file.fw_features)) {
status = ath10k_bmi_done(ar);
if (status)
goto err;
}
status = ath10k_wmi_attach(ar);
if (status) {
......@@ -2370,19 +2414,35 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
return ret;
}
memset(&target_info, 0, sizeof(target_info));
if (ar->hif.bus == ATH10K_BUS_SDIO)
switch (ar->hif.bus) {
case ATH10K_BUS_SDIO:
memset(&target_info, 0, sizeof(target_info));
ret = ath10k_bmi_get_target_info_sdio(ar, &target_info);
else
if (ret) {
ath10k_err(ar, "could not get target info (%d)\n", ret);
goto err_power_down;
}
ar->target_version = target_info.version;
ar->hw->wiphy->hw_version = target_info.version;
break;
case ATH10K_BUS_PCI:
case ATH10K_BUS_AHB:
case ATH10K_BUS_USB:
memset(&target_info, 0, sizeof(target_info));
ret = ath10k_bmi_get_target_info(ar, &target_info);
if (ret) {
ath10k_err(ar, "could not get target info (%d)\n", ret);
goto err_power_down;
if (ret) {
ath10k_err(ar, "could not get target info (%d)\n", ret);
goto err_power_down;
}
ar->target_version = target_info.version;
ar->hw->wiphy->hw_version = target_info.version;
break;
case ATH10K_BUS_SNOC:
break;
default:
ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus);
}
ar->target_version = target_info.version;
ar->hw->wiphy->hw_version = target_info.version;
ret = ath10k_init_hw_params(ar);
if (ret) {
ath10k_err(ar, "could not get hw params (%d)\n", ret);
......@@ -2402,37 +2462,40 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ath10k_debug_print_hwfw_info(ar);
ret = ath10k_core_pre_cal_download(ar);
if (ret) {
/* pre calibration data download is not necessary
* for all the chipsets. Ignore failures and continue.
*/
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"could not load pre cal data: %d\n", ret);
}
if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
ar->normal_mode_fw.fw_file.fw_features)) {
ret = ath10k_core_pre_cal_download(ar);
if (ret) {
/* pre calibration data download is not necessary
* for all the chipsets. Ignore failures and continue.
*/
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"could not load pre cal data: %d\n", ret);
}
ret = ath10k_core_get_board_id_from_otp(ar);
if (ret && ret != -EOPNOTSUPP) {
ath10k_err(ar, "failed to get board id from otp: %d\n",
ret);
goto err_free_firmware_files;
}
ret = ath10k_core_get_board_id_from_otp(ar);
if (ret && ret != -EOPNOTSUPP) {
ath10k_err(ar, "failed to get board id from otp: %d\n",
ret);
goto err_free_firmware_files;
}
ret = ath10k_core_check_smbios(ar);
if (ret)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n");
ret = ath10k_core_check_smbios(ar);
if (ret)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n");
ret = ath10k_core_check_dt(ar);
if (ret)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");
ret = ath10k_core_check_dt(ar);
if (ret)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");
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_fetch_board_file(ar);
if (ret) {
ath10k_err(ar, "failed to fetch board file: %d\n", ret);
goto err_free_firmware_files;
}
ath10k_debug_print_board_info(ar);
ath10k_debug_print_board_info(ar);
}
ret = ath10k_core_init_firmware_features(ar);
if (ret) {
......@@ -2441,11 +2504,15 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_free_firmware_files;
}
ret = ath10k_swap_code_seg_init(ar, &ar->normal_mode_fw.fw_file);
if (ret) {
ath10k_err(ar, "failed to initialize code swap segment: %d\n",
ret);
goto err_free_firmware_files;
if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
ar->normal_mode_fw.fw_file.fw_features)) {
ret = ath10k_swap_code_seg_init(ar,
&ar->normal_mode_fw.fw_file);
if (ret) {
ath10k_err(ar, "failed to initialize code swap segment: %d\n",
ret);
goto err_free_firmware_files;
}
}
mutex_lock(&ar->conf_mutex);
......@@ -2497,10 +2564,16 @@ static void ath10k_core_register_work(struct work_struct *work)
goto err_release_fw;
}
status = ath10k_coredump_register(ar);
if (status) {
ath10k_err(ar, "unable to register coredump\n");
goto err_unregister_mac;
}
status = ath10k_debug_register(ar);
if (status) {
ath10k_err(ar, "unable to initialize debugfs\n");
goto err_unregister_mac;
goto err_unregister_coredump;
}
status = ath10k_spectral_create(ar);
......@@ -2523,6 +2596,8 @@ static void ath10k_core_register_work(struct work_struct *work)
ath10k_spectral_destroy(ar);
err_debug_destroy:
ath10k_debug_destroy(ar);
err_unregister_coredump:
ath10k_coredump_unregister(ar);
err_unregister_mac:
ath10k_mac_unregister(ar);
err_release_fw:
......@@ -2677,12 +2752,19 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_dummy_netdev(&ar->napi_dev);
ret = ath10k_debug_create(ar);
ret = ath10k_coredump_create(ar);
if (ret)
goto err_free_aux_wq;
ret = ath10k_debug_create(ar);
if (ret)
goto err_free_coredump;
return ar;
err_free_coredump:
ath10k_coredump_destroy(ar);
err_free_aux_wq:
destroy_workqueue(ar->workqueue_aux);
err_free_wq:
......@@ -2704,6 +2786,7 @@ void ath10k_core_destroy(struct ath10k *ar)
destroy_workqueue(ar->workqueue_aux);
ath10k_debug_destroy(ar);
ath10k_coredump_destroy(ar);
ath10k_htt_tx_destroy(&ar->htt);
ath10k_wmi_free_host_mem(ar);
ath10k_mac_destroy(ar);
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -92,6 +92,7 @@ enum ath10k_bus {
ATH10K_BUS_AHB,
ATH10K_BUS_SDIO,
ATH10K_BUS_USB,
ATH10K_BUS_SNOC,
};
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
......@@ -105,6 +106,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
return "sdio";
case ATH10K_BUS_USB:
return "usb";
case ATH10K_BUS_SNOC:
return "snoc";
}
return "unknown";
......@@ -457,14 +460,17 @@ struct ath10k_ce_crash_hdr {
struct ath10k_ce_crash_data entries[];
};
#define MAX_MEM_DUMP_TYPE 5
/* used for crash-dump storage, protected by data-lock */
struct ath10k_fw_crash_data {
bool crashed_since_read;
guid_t guid;
struct timespec64 timestamp;
__le32 registers[REG_DUMP_COUNT_QCA988X];
struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX];
u8 *ramdump_buf;
size_t ramdump_buf_len;
};
struct ath10k_debug {
......@@ -490,8 +496,6 @@ struct ath10k_debug {
u32 reg_addr;
u32 nf_cal_period;
void *cal_data;
struct ath10k_fw_crash_data *fw_crash_data;
};
enum ath10k_state {
......@@ -616,6 +620,9 @@ enum ath10k_fw_features {
/* Firmware allows management tx by reference instead of by value. */
ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18,
/* Firmware load is done externally, not by bmi */
ATH10K_FW_FEATURE_NON_BMI = 19,
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
......@@ -965,6 +972,13 @@ struct ath10k {
#endif
u32 pktlog_filter;
#ifdef CONFIG_DEV_COREDUMP
struct {
struct ath10k_fw_crash_data *fw_crash_data;
} coredump;
#endif
struct {
/* protected by conf_mutex */
struct ath10k_fw_components utf_mode_fw;
......@@ -1018,6 +1032,8 @@ static inline bool ath10k_peer_stats_enabled(struct ath10k *ar)
return false;
}
extern unsigned long ath10k_coredump_mask;
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
enum ath10k_bus bus,
enum ath10k_hw_rev hw_rev,
......
此差异已折叠。
/*
* Copyright (c) 2011-2017 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.
*/
#ifndef _COREDUMP_H_
#define _COREDUMP_H_
#include "core.h"
#define ATH10K_FW_CRASH_DUMP_VERSION 1
/**
* enum ath10k_fw_crash_dump_type - types of data in the dump file
* @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
*/
enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
ATH10K_FW_CRASH_DUMP_CE_DATA = 1,
/* contains multiple struct ath10k_dump_ram_data_hdr */
ATH10K_FW_CRASH_DUMP_RAM_DATA = 2,
ATH10K_FW_CRASH_DUMP_MAX,
};
struct ath10k_tlv_dump_data {
/* see ath10k_fw_crash_dump_type above */
__le32 type;
/* in bytes */
__le32 tlv_len;
/* pad to 32-bit boundaries as needed */
u8 tlv_data[];
} __packed;
struct ath10k_dump_file_data {
/* dump file information */
/* "ATH10K-FW-DUMP" */
char df_magic[16];
__le32 len;
/* file dump version */
__le32 version;
/* some info we can get from ath10k struct that might help */
guid_t guid;
__le32 chip_id;
/* 0 for now, in place for later hardware */
__le32 bus_type;
__le32 target_version;
__le32 fw_version_major;
__le32 fw_version_minor;
__le32 fw_version_release;
__le32 fw_version_build;
__le32 phy_capability;
__le32 hw_min_tx_power;
__le32 hw_max_tx_power;
__le32 ht_cap_info;
__le32 vht_cap_info;
__le32 num_rf_chains;
/* firmware version string */
char fw_ver[ETHTOOL_FWVERS_LEN];
/* Kernel related information */
/* time-of-day stamp */
__le64 tv_sec;
/* time-of-day stamp, nano-seconds */
__le64 tv_nsec;
/* LINUX_VERSION_CODE */
__le32 kernel_ver_code;
/* VERMAGIC_STRING */
char kernel_ver[64];
/* room for growth w/out changing binary format */
u8 unused[128];
/* struct ath10k_tlv_dump_data + more */
u8 data[0];
} __packed;
struct ath10k_dump_ram_data_hdr {
/* enum ath10k_mem_region_type */
__le32 region_type;
__le32 start;
/* length of payload data, not including this header */
__le32 length;
u8 data[0];
};
/* magic number to fill the holes not copied due to sections in regions */
#define ATH10K_MAGIC_NOT_COPIED 0xAA
/* part of user space ABI */
enum ath10k_mem_region_type {
ATH10K_MEM_REGION_TYPE_REG = 1,
ATH10K_MEM_REGION_TYPE_DRAM = 2,
ATH10K_MEM_REGION_TYPE_AXI = 3,
ATH10K_MEM_REGION_TYPE_IRAM1 = 4,
ATH10K_MEM_REGION_TYPE_IRAM2 = 5,
};
/* Define a section of the region which should be copied. As not all parts
* of the memory is possible to copy, for example some of the registers can
* be like that, sections can be used to define what is safe to copy.
*
* To minimize the size of the array, the list must obey the format:
* '{start0,stop0},{start1,stop1},{start2,stop2}....' The values below must
* also obey to 'start0 < stop0 < start1 < stop1 < start2 < ...', otherwise
* we may encouter error in the dump processing.
*/
struct ath10k_mem_section {
u32 start;
u32 end;
};
/* One region of a memory layout. If the sections field is null entire
* region is copied. If sections is non-null only the areas specified in
* sections are copied and rest of the areas are filled with
* ATH10K_MAGIC_NOT_COPIED.
*/
struct ath10k_mem_region {
enum ath10k_mem_region_type type;
u32 start;
u32 len;
const char *name;
struct {
const struct ath10k_mem_section *sections;
u32 size;
} section_table;
};
/* Contains the memory layout of a hardware version identified with the
* hardware id, split into regions.
*/
struct ath10k_hw_mem_layout {
u32 hw_id;
struct {
const struct ath10k_mem_region *regions;
int size;
} region_table;
};
/* FIXME: where to put this? */
extern unsigned long ath10k_coredump_mask;
#ifdef CONFIG_DEV_COREDUMP
int ath10k_coredump_submit(struct ath10k *ar);
struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar);
int ath10k_coredump_create(struct ath10k *ar);
int ath10k_coredump_register(struct ath10k *ar);
void ath10k_coredump_unregister(struct ath10k *ar);
void ath10k_coredump_destroy(struct ath10k *ar);
const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar);
#else /* CONFIG_DEV_COREDUMP */
static inline int ath10k_coredump_submit(struct ath10k *ar)
{
return 0;
}
static inline struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
{
return NULL;
}
static inline int ath10k_coredump_create(struct ath10k *ar)
{
return 0;
}
static inline int ath10k_coredump_register(struct ath10k *ar)
{
return 0;
}
static inline void ath10k_coredump_unregister(struct ath10k *ar)
{
}
static inline void ath10k_coredump_destroy(struct ath10k *ar)
{
}
static inline const struct ath10k_hw_mem_layout *
ath10k_coredump_get_mem_layout(struct ath10k *ar)
{
return NULL;
}
#endif /* CONFIG_DEV_COREDUMP */
#endif /* _COREDUMP_H_ */
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -18,10 +18,8 @@
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/utsname.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/devcoredump.h>
#include "core.h"
#include "debug.h"
......@@ -33,86 +31,6 @@
#define ATH10K_DEBUG_CAL_DATA_LEN 12064
#define ATH10K_FW_CRASH_DUMP_VERSION 1
/**
* enum ath10k_fw_crash_dump_type - types of data in the dump file
* @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
*/
enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
ATH10K_FW_CRASH_DUMP_CE_DATA = 1,
ATH10K_FW_CRASH_DUMP_MAX,
};
struct ath10k_tlv_dump_data {
/* see ath10k_fw_crash_dump_type above */
__le32 type;
/* in bytes */
__le32 tlv_len;
/* pad to 32-bit boundaries as needed */
u8 tlv_data[];
} __packed;
struct ath10k_dump_file_data {
/* dump file information */
/* "ATH10K-FW-DUMP" */
char df_magic[16];
__le32 len;
/* file dump version */
__le32 version;
/* some info we can get from ath10k struct that might help */
guid_t guid;
__le32 chip_id;
/* 0 for now, in place for later hardware */
__le32 bus_type;
__le32 target_version;
__le32 fw_version_major;
__le32 fw_version_minor;
__le32 fw_version_release;
__le32 fw_version_build;
__le32 phy_capability;
__le32 hw_min_tx_power;
__le32 hw_max_tx_power;
__le32 ht_cap_info;
__le32 vht_cap_info;
__le32 num_rf_chains;
/* firmware version string */
char fw_ver[ETHTOOL_FWVERS_LEN];
/* Kernel related information */
/* time-of-day stamp */
__le64 tv_sec;
/* time-of-day stamp, nano-seconds */
__le64 tv_nsec;
/* LINUX_VERSION_CODE */
__le32 kernel_ver_code;
/* VERMAGIC_STRING */
char kernel_ver[64];
/* room for growth w/out changing binary format */
u8 unused[128];
/* struct ath10k_tlv_dump_data + more */
u8 data[0];
} __packed;
void ath10k_info(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
......@@ -711,189 +629,6 @@ static const struct file_operations fops_chip_id = {
.llseek = default_llseek,
};
struct ath10k_fw_crash_data *
ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
{
struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
lockdep_assert_held(&ar->data_lock);
crash_data->crashed_since_read = true;
guid_gen(&crash_data->guid);
ktime_get_real_ts64(&crash_data->timestamp);
return crash_data;
}
EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar,
bool mark_read)
{
struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
struct ath10k_ce_crash_hdr *ce_hdr;
struct ath10k_dump_file_data *dump_data;
struct ath10k_tlv_dump_data *dump_tlv;
size_t hdr_len = sizeof(*dump_data);
size_t len, sofar = 0;
unsigned char *buf;
len = hdr_len;
len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
len += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
CE_COUNT * sizeof(ce_hdr->entries[0]);
sofar += hdr_len;
/* This is going to get big when we start dumping FW RAM and such,
* so go ahead and use vmalloc.
*/
buf = vzalloc(len);
if (!buf)
return NULL;
spin_lock_bh(&ar->data_lock);
if (!crash_data->crashed_since_read) {
spin_unlock_bh(&ar->data_lock);
vfree(buf);
return NULL;
}
dump_data = (struct ath10k_dump_file_data *)(buf);
strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
sizeof(dump_data->df_magic));
dump_data->len = cpu_to_le32(len);
dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
guid_copy(&dump_data->guid, &crash_data->guid);
dump_data->chip_id = cpu_to_le32(ar->chip_id);
dump_data->bus_type = cpu_to_le32(0);
dump_data->target_version = cpu_to_le32(ar->target_version);
dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
sizeof(dump_data->fw_ver));
dump_data->kernel_ver_code = 0;
strlcpy(dump_data->kernel_ver, init_utsname()->release,
sizeof(dump_data->kernel_ver));
dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
/* Gather crash-dump */
dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
memcpy(dump_tlv->tlv_data, &crash_data->registers,
sizeof(crash_data->registers));
sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA);
dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) +
CE_COUNT * sizeof(ce_hdr->entries[0]));
ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data);
ce_hdr->ce_count = cpu_to_le32(CE_COUNT);
memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved));
memcpy(ce_hdr->entries, crash_data->ce_crash_data,
CE_COUNT * sizeof(ce_hdr->entries[0]));
sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
CE_COUNT * sizeof(ce_hdr->entries[0]);
ar->debug.fw_crash_data->crashed_since_read = !mark_read;
spin_unlock_bh(&ar->data_lock);
return dump_data;
}
int ath10k_debug_fw_devcoredump(struct ath10k *ar)
{
struct ath10k_dump_file_data *dump;
void *dump_ptr;
u32 dump_len;
/* To keep the dump file available also for debugfs don't mark the
* file read, only debugfs should do that.
*/
dump = ath10k_build_dump_file(ar, false);
if (!dump) {
ath10k_warn(ar, "no crash dump data found for devcoredump");
return -ENODATA;
}
/* Make a copy of the dump file for dev_coredumpv() as during the
* transition period we need to own the original file. Once
* fw_crash_dump debugfs file is removed no need to have a copy
* anymore.
*/
dump_len = le32_to_cpu(dump->len);
dump_ptr = vzalloc(dump_len);
if (!dump_ptr)
return -ENOMEM;
memcpy(dump_ptr, dump, dump_len);
dev_coredumpv(ar->dev, dump_ptr, dump_len, GFP_KERNEL);
return 0;
}
static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
{
struct ath10k *ar = inode->i_private;
struct ath10k_dump_file_data *dump;
ath10k_warn(ar, "fw_crash_dump debugfs file is deprecated, please use /sys/class/devcoredump instead.");
dump = ath10k_build_dump_file(ar, true);
if (!dump)
return -ENODATA;
file->private_data = dump;
return 0;
}
static ssize_t ath10k_fw_crash_dump_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k_dump_file_data *dump_file = file->private_data;
return simple_read_from_buffer(user_buf, count, ppos,
dump_file,
le32_to_cpu(dump_file->len));
}
static int ath10k_fw_crash_dump_release(struct inode *inode,
struct file *file)
{
vfree(file->private_data);
return 0;
}
static const struct file_operations fops_fw_crash_dump = {
.open = ath10k_fw_crash_dump_open,
.read = ath10k_fw_crash_dump_read,
.release = ath10k_fw_crash_dump_release,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath10k_reg_addr_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
......@@ -2402,10 +2137,6 @@ static const struct file_operations fops_fw_checksums = {
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
if (!ar->debug.fw_crash_data)
return -ENOMEM;
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
if (!ar->debug.cal_data)
return -ENOMEM;
......@@ -2420,9 +2151,6 @@ int ath10k_debug_create(struct ath10k *ar)
void ath10k_debug_destroy(struct ath10k *ar)
{
vfree(ar->debug.fw_crash_data);
ar->debug.fw_crash_data = NULL;
vfree(ar->debug.cal_data);
ar->debug.cal_data = NULL;
......@@ -2460,9 +2188,6 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar,
&fops_simulate_fw_crash);
debugfs_create_file("fw_crash_dump", 0400, ar->debug.debugfs_phy, ar,
&fops_fw_crash_dump);
debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar,
&fops_reg_addr);
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -42,6 +42,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_SDIO_DUMP = 0x00020000,
ATH10K_DBG_USB = 0x00040000,
ATH10K_DBG_USB_BULK = 0x00080000,
ATH10K_DBG_SNOC = 0x00100000,
ATH10K_DBG_ANY = 0xffffffff,
};
......@@ -100,13 +101,8 @@ 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);
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
int ath10k_debug_fw_devcoredump(struct ath10k *ar);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
......@@ -173,12 +169,6 @@ static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
{
}
static inline struct ath10k_fw_crash_data *
ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
{
return NULL;
}
static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
{
return 0;
......@@ -189,11 +179,6 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar)
return 0;
}
static inline int ath10k_debug_fw_devcoredump(struct ath10k *ar)
{
return 0;
}
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#define ath10k_debug_get_et_strings NULL
......
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
* Copyright (c) 2014-2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2015,2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2016 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -207,6 +207,9 @@ int ath10k_htt_init(struct ath10k *ar)
WARN_ON(1);
return -EINVAL;
}
ath10k_htt_set_tx_ops(htt);
ath10k_htt_set_rx_ops(htt);
return 0;
}
......@@ -254,11 +257,11 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
return status;
}
status = ath10k_htt_send_frag_desc_bank_cfg(htt);
status = htt->tx_ops->htt_send_frag_desc_bank_cfg(htt);
if (status)
return status;
status = ath10k_htt_send_rx_ring_cfg_ll(htt);
status = htt->tx_ops->htt_send_rx_ring_cfg(htt);
if (status) {
ath10k_warn(ar, "failed to setup rx ring: %d\n",
status);
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -107,6 +107,14 @@ struct htt_msdu_ext_desc {
struct htt_data_tx_desc_frag frags[6];
};
struct htt_msdu_ext_desc_64 {
__le32 tso_flag[5];
__le16 ip_identification;
u8 flags;
u8 reserved;
struct htt_data_tx_desc_frag frags[6];
};
#define HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE BIT(0)
#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE BIT(1)
#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE BIT(2)
......@@ -179,6 +187,22 @@ struct htt_data_tx_desc {
u8 prefetch[0]; /* start of frame, for FW classification engine */
} __packed;
struct htt_data_tx_desc_64 {
u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */
__le16 flags1; /* %HTT_DATA_TX_DESC_FLAGS1_ */
__le16 len;
__le16 id;
__le64 frags_paddr;
union {
__le32 peerid;
struct {
__le16 peerid;
__le16 freq;
} __packed offchan_tx;
} __packed;
u8 prefetch[0]; /* start of frame, for FW classification engine */
} __packed;
enum htt_rx_ring_flags {
HTT_RX_RING_FLAGS_MAC80211_HDR = 1 << 0,
HTT_RX_RING_FLAGS_MSDU_PAYLOAD = 1 << 1,
......@@ -200,8 +224,11 @@ enum htt_rx_ring_flags {
#define HTT_RX_RING_SIZE_MIN 128
#define HTT_RX_RING_SIZE_MAX 2048
#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX
#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1)
#define HTT_RX_RING_FILL_LEVEL_DUAL_MAC (HTT_RX_RING_SIZE - 1)
struct htt_rx_ring_setup_ring {
struct htt_rx_ring_setup_ring32 {
__le32 fw_idx_shadow_reg_paddr;
__le32 rx_ring_base_paddr;
__le16 rx_ring_len; /* in 4-byte words */
......@@ -222,14 +249,40 @@ struct htt_rx_ring_setup_ring {
__le16 frag_info_offset;
} __packed;
struct htt_rx_ring_setup_ring64 {
__le64 fw_idx_shadow_reg_paddr;
__le64 rx_ring_base_paddr;
__le16 rx_ring_len; /* in 4-byte words */
__le16 rx_ring_bufsize; /* rx skb size - in bytes */
__le16 flags; /* %HTT_RX_RING_FLAGS_ */
__le16 fw_idx_init_val;
/* the following offsets are in 4-byte units */
__le16 mac80211_hdr_offset;
__le16 msdu_payload_offset;
__le16 ppdu_start_offset;
__le16 ppdu_end_offset;
__le16 mpdu_start_offset;
__le16 mpdu_end_offset;
__le16 msdu_start_offset;
__le16 msdu_end_offset;
__le16 rx_attention_offset;
__le16 frag_info_offset;
} __packed;
struct htt_rx_ring_setup_hdr {
u8 num_rings; /* supported values: 1, 2 */
__le16 rsvd0;
} __packed;
struct htt_rx_ring_setup {
struct htt_rx_ring_setup_32 {
struct htt_rx_ring_setup_hdr hdr;
struct htt_rx_ring_setup_ring32 rings[0];
} __packed;
struct htt_rx_ring_setup_64 {
struct htt_rx_ring_setup_hdr hdr;
struct htt_rx_ring_setup_ring rings[0];
struct htt_rx_ring_setup_ring64 rings[0];
} __packed;
/*
......@@ -855,13 +908,23 @@ struct htt_rx_in_ord_msdu_desc {
u8 reserved;
} __packed;
struct htt_rx_in_ord_msdu_desc_ext {
__le64 msdu_paddr;
__le16 msdu_len;
u8 fw_desc;
u8 reserved;
} __packed;
struct htt_rx_in_ord_ind {
u8 info;
__le16 peer_id;
u8 vdev_id;
u8 reserved;
__le16 msdu_count;
struct htt_rx_in_ord_msdu_desc msdu_descs[0];
union {
struct htt_rx_in_ord_msdu_desc msdu_descs32[0];
struct htt_rx_in_ord_msdu_desc_ext msdu_descs64[0];
} __packed;
} __packed;
#define HTT_RX_IN_ORD_IND_INFO_TID_MASK 0x0000001f
......@@ -1351,7 +1414,7 @@ struct htt_q_state_conf {
u8 pad[2];
} __packed;
struct htt_frag_desc_bank_cfg {
struct htt_frag_desc_bank_cfg32 {
u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */
u8 num_banks;
u8 desc_size;
......@@ -1360,6 +1423,15 @@ struct htt_frag_desc_bank_cfg {
struct htt_q_state_conf q_state;
} __packed;
struct htt_frag_desc_bank_cfg64 {
u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */
u8 num_banks;
u8 desc_size;
__le64 bank_base_addrs[HTT_FRAG_DESC_BANK_MAX];
struct htt_frag_desc_bank_id bank_id[HTT_FRAG_DESC_BANK_MAX];
struct htt_q_state_conf q_state;
} __packed;
#define HTT_TX_Q_STATE_ENTRY_COEFFICIENT 128
#define HTT_TX_Q_STATE_ENTRY_FACTOR_MASK 0x3f
#define HTT_TX_Q_STATE_ENTRY_FACTOR_LSB 0
......@@ -1531,11 +1603,13 @@ struct htt_cmd {
struct htt_ver_req ver_req;
struct htt_mgmt_tx_desc mgmt_tx;
struct htt_data_tx_desc data_tx;
struct htt_rx_ring_setup rx_setup;
struct htt_rx_ring_setup_32 rx_setup_32;
struct htt_rx_ring_setup_64 rx_setup_64;
struct htt_stats_req stats_req;
struct htt_oob_sync_req oob_sync_req;
struct htt_aggr_conf aggr_conf;
struct htt_frag_desc_bank_cfg frag_desc_bank_cfg;
struct htt_frag_desc_bank_cfg32 frag_desc_bank_cfg32;
struct htt_frag_desc_bank_cfg64 frag_desc_bank_cfg64;
struct htt_tx_fetch_resp tx_fetch_resp;
};
} __packed;
......@@ -1593,13 +1667,20 @@ struct htt_peer_unmap_event {
u16 peer_id;
};
struct ath10k_htt_txbuf {
struct ath10k_htt_txbuf_32 {
struct htt_data_tx_desc_frag frags[2];
struct ath10k_htc_hdr htc_hdr;
struct htt_cmd_hdr cmd_hdr;
struct htt_data_tx_desc cmd_tx;
} __packed;
struct ath10k_htt_txbuf_64 {
struct htt_data_tx_desc_frag frags[2];
struct ath10k_htc_hdr htc_hdr;
struct htt_cmd_hdr cmd_hdr;
struct htt_data_tx_desc_64 cmd_tx;
} __packed;
struct ath10k_htt {
struct ath10k *ar;
enum ath10k_htc_ep_id eid;
......@@ -1644,7 +1725,10 @@ struct ath10k_htt {
* rx buffers the host SW provides for the MAC HW to
* fill.
*/
__le32 *paddrs_ring;
union {
__le64 *paddrs_ring_64;
__le32 *paddrs_ring_32;
};
/*
* Base address of ring, as a "physical" device address
......@@ -1721,12 +1805,20 @@ struct ath10k_htt {
struct {
dma_addr_t paddr;
struct htt_msdu_ext_desc *vaddr;
union {
struct htt_msdu_ext_desc *vaddr_desc_32;
struct htt_msdu_ext_desc_64 *vaddr_desc_64;
};
size_t size;
} frag_desc;
struct {
dma_addr_t paddr;
struct ath10k_htt_txbuf *vaddr;
union {
struct ath10k_htt_txbuf_32 *vaddr_txbuff_32;
struct ath10k_htt_txbuf_64 *vaddr_txbuff_64;
};
size_t size;
} txbuf;
struct {
......@@ -1741,8 +1833,29 @@ struct ath10k_htt {
} tx_q_state;
bool tx_mem_allocated;
const struct ath10k_htt_tx_ops *tx_ops;
const struct ath10k_htt_rx_ops *rx_ops;
};
struct ath10k_htt_tx_ops {
int (*htt_send_rx_ring_cfg)(struct ath10k_htt *htt);
int (*htt_send_frag_desc_bank_cfg)(struct ath10k_htt *htt);
int (*htt_alloc_frag_desc)(struct ath10k_htt *htt);
void (*htt_free_frag_desc)(struct ath10k_htt *htt);
int (*htt_tx)(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
struct sk_buff *msdu);
int (*htt_alloc_txbuff)(struct ath10k_htt *htt);
void (*htt_free_txbuff)(struct ath10k_htt *htt);
};
struct ath10k_htt_rx_ops {
size_t (*htt_get_rx_ring_size)(struct ath10k_htt *htt);
void (*htt_config_paddrs_ring)(struct ath10k_htt *htt, void *vaddr);
void (*htt_set_paddrs_ring)(struct ath10k_htt *htt, dma_addr_t paddr,
int idx);
void* (*htt_get_vaddr_ring)(struct ath10k_htt *htt);
void (*htt_reset_paddrs_ring)(struct ath10k_htt *htt, int idx);
};
#define RX_HTT_HDR_STATUS_LEN 64
/* This structure layout is programmed via rx ring setup
......@@ -1820,8 +1933,6 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt);
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);
......@@ -1846,11 +1957,9 @@ int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu);
int ath10k_htt_tx(struct ath10k_htt *htt,
enum ath10k_hw_txrx_mode txmode,
struct sk_buff *msdu);
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
struct sk_buff *skb);
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget);
void ath10k_htt_set_tx_ops(struct ath10k_htt *htt);
void ath10k_htt_set_rx_ops(struct ath10k_htt *htt);
#endif
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -25,9 +25,6 @@
#include <linux/log2.h>
#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX
#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1)
/* when under memory pressure rx ring refill may fail and needs a retry */
#define HTT_RX_RING_REFILL_RETRY_MS 50
......@@ -36,7 +33,7 @@
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
static struct sk_buff *
ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr)
ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u64 paddr)
{
struct ath10k_skb_rxcb *rxcb;
......@@ -84,6 +81,60 @@ static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt)
htt->rx_ring.size * sizeof(htt->rx_ring.netbufs_ring[0]));
}
static size_t ath10k_htt_get_rx_ring_size_32(struct ath10k_htt *htt)
{
return htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring_32);
}
static size_t ath10k_htt_get_rx_ring_size_64(struct ath10k_htt *htt)
{
return htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring_64);
}
static void ath10k_htt_config_paddrs_ring_32(struct ath10k_htt *htt,
void *vaddr)
{
htt->rx_ring.paddrs_ring_32 = vaddr;
}
static void ath10k_htt_config_paddrs_ring_64(struct ath10k_htt *htt,
void *vaddr)
{
htt->rx_ring.paddrs_ring_64 = vaddr;
}
static void ath10k_htt_set_paddrs_ring_32(struct ath10k_htt *htt,
dma_addr_t paddr, int idx)
{
htt->rx_ring.paddrs_ring_32[idx] = __cpu_to_le32(paddr);
}
static void ath10k_htt_set_paddrs_ring_64(struct ath10k_htt *htt,
dma_addr_t paddr, int idx)
{
htt->rx_ring.paddrs_ring_64[idx] = __cpu_to_le64(paddr);
}
static void ath10k_htt_reset_paddrs_ring_32(struct ath10k_htt *htt, int idx)
{
htt->rx_ring.paddrs_ring_32[idx] = 0;
}
static void ath10k_htt_reset_paddrs_ring_64(struct ath10k_htt *htt, int idx)
{
htt->rx_ring.paddrs_ring_64[idx] = 0;
}
static void *ath10k_htt_get_vaddr_ring_32(struct ath10k_htt *htt)
{
return (void *)htt->rx_ring.paddrs_ring_32;
}
static void *ath10k_htt_get_vaddr_ring_64(struct ath10k_htt *htt)
{
return (void *)htt->rx_ring.paddrs_ring_64;
}
static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
{
struct htt_rx_desc *rx_desc;
......@@ -129,13 +180,13 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
rxcb = ATH10K_SKB_RXCB(skb);
rxcb->paddr = paddr;
htt->rx_ring.netbufs_ring[idx] = skb;
htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr);
htt->rx_ops->htt_set_paddrs_ring(htt, paddr, idx);
htt->rx_ring.fill_cnt++;
if (htt->rx_ring.in_ord_rx) {
hash_add(htt->rx_ring.skb_table,
&ATH10K_SKB_RXCB(skb)->hlist,
(u32)paddr);
paddr);
}
num--;
......@@ -234,9 +285,8 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
ath10k_htt_rx_ring_free(htt);
dma_free_coherent(htt->ar->dev,
(htt->rx_ring.size *
sizeof(htt->rx_ring.paddrs_ring)),
htt->rx_ring.paddrs_ring,
htt->rx_ops->htt_get_rx_ring_size(htt),
htt->rx_ops->htt_get_vaddr_ring(htt),
htt->rx_ring.base_paddr);
dma_free_coherent(htt->ar->dev,
......@@ -263,7 +313,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
idx = htt->rx_ring.sw_rd_idx.msdu_payld;
msdu = htt->rx_ring.netbufs_ring[idx];
htt->rx_ring.netbufs_ring[idx] = NULL;
htt->rx_ring.paddrs_ring[idx] = 0;
htt->rx_ops->htt_reset_paddrs_ring(htt, idx);
idx++;
idx &= htt->rx_ring.size_mask;
......@@ -383,7 +433,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
}
static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt,
u32 paddr)
u64 paddr)
{
struct ath10k *ar = htt->ar;
struct ath10k_skb_rxcb *rxcb;
......@@ -408,12 +458,12 @@ static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt,
return msdu;
}
static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt,
struct htt_rx_in_ord_ind *ev,
struct sk_buff_head *list)
static int ath10k_htt_rx_pop_paddr32_list(struct ath10k_htt *htt,
struct htt_rx_in_ord_ind *ev,
struct sk_buff_head *list)
{
struct ath10k *ar = htt->ar;
struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs;
struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs32;
struct htt_rx_desc *rxd;
struct sk_buff *msdu;
int msdu_count;
......@@ -458,11 +508,60 @@ static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt,
return 0;
}
static int ath10k_htt_rx_pop_paddr64_list(struct ath10k_htt *htt,
struct htt_rx_in_ord_ind *ev,
struct sk_buff_head *list)
{
struct ath10k *ar = htt->ar;
struct htt_rx_in_ord_msdu_desc_ext *msdu_desc = ev->msdu_descs64;
struct htt_rx_desc *rxd;
struct sk_buff *msdu;
int msdu_count;
bool is_offload;
u64 paddr;
lockdep_assert_held(&htt->rx_ring.lock);
msdu_count = __le16_to_cpu(ev->msdu_count);
is_offload = !!(ev->info & HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK);
while (msdu_count--) {
paddr = __le64_to_cpu(msdu_desc->msdu_paddr);
msdu = ath10k_htt_rx_pop_paddr(htt, paddr);
if (!msdu) {
__skb_queue_purge(list);
return -ENOENT;
}
__skb_queue_tail(list, msdu);
if (!is_offload) {
rxd = (void *)msdu->data;
trace_ath10k_htt_rx_desc(ar, rxd, sizeof(*rxd));
skb_put(msdu, sizeof(*rxd));
skb_pull(msdu, sizeof(*rxd));
skb_put(msdu, __le16_to_cpu(msdu_desc->msdu_len));
if (!(__le32_to_cpu(rxd->attention.flags) &
RX_ATTENTION_FLAGS_MSDU_DONE)) {
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
return -EIO;
}
}
msdu_desc++;
}
return 0;
}
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
dma_addr_t paddr;
void *vaddr;
void *vaddr, *vaddr_ring;
size_t size;
struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
......@@ -473,7 +572,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
*/
htt->rx_ring.size = HTT_RX_RING_SIZE;
htt->rx_ring.size_mask = htt->rx_ring.size - 1;
htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL;
htt->rx_ring.fill_level = ar->hw_params.rx_ring_fill_level;
if (!is_power_of_2(htt->rx_ring.size)) {
ath10k_warn(ar, "htt rx ring size is not power of 2\n");
......@@ -486,13 +585,13 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
if (!htt->rx_ring.netbufs_ring)
goto err_netbuf;
size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring);
size = htt->rx_ops->htt_get_rx_ring_size(htt);
vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_KERNEL);
if (!vaddr)
vaddr_ring = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_KERNEL);
if (!vaddr_ring)
goto err_dma_ring;
htt->rx_ring.paddrs_ring = vaddr;
htt->rx_ops->htt_config_paddrs_ring(htt, vaddr_ring);
htt->rx_ring.base_paddr = paddr;
vaddr = dma_alloc_coherent(htt->ar->dev,
......@@ -526,9 +625,8 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
err_dma_idx:
dma_free_coherent(htt->ar->dev,
(htt->rx_ring.size *
sizeof(htt->rx_ring.paddrs_ring)),
htt->rx_ring.paddrs_ring,
htt->rx_ops->htt_get_rx_ring_size(htt),
vaddr_ring,
htt->rx_ring.base_paddr);
err_dma_ring:
kfree(htt->rx_ring.netbufs_ring);
......@@ -1986,7 +2084,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
"htt rx in ord vdev %i peer %i tid %i offload %i frag %i msdu count %i\n",
vdev_id, peer_id, tid, offload, frag, msdu_count);
if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) {
if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs32)) {
ath10k_warn(ar, "dropping invalid in order rx indication\n");
return -EINVAL;
}
......@@ -1995,7 +2093,13 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
* extracted and processed.
*/
__skb_queue_head_init(&list);
ret = ath10k_htt_rx_pop_paddr_list(htt, &resp->rx_in_ord_ind, &list);
if (ar->hw_params.target_64bit)
ret = ath10k_htt_rx_pop_paddr64_list(htt, &resp->rx_in_ord_ind,
&list);
else
ret = ath10k_htt_rx_pop_paddr32_list(htt, &resp->rx_in_ord_ind,
&list);
if (ret < 0) {
ath10k_warn(ar, "failed to pop paddr list: %d\n", ret);
htt->rx_confused = true;
......@@ -2795,3 +2899,29 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
return done;
}
EXPORT_SYMBOL(ath10k_htt_txrx_compl_task);
static const struct ath10k_htt_rx_ops htt_rx_ops_32 = {
.htt_get_rx_ring_size = ath10k_htt_get_rx_ring_size_32,
.htt_config_paddrs_ring = ath10k_htt_config_paddrs_ring_32,
.htt_set_paddrs_ring = ath10k_htt_set_paddrs_ring_32,
.htt_get_vaddr_ring = ath10k_htt_get_vaddr_ring_32,
.htt_reset_paddrs_ring = ath10k_htt_reset_paddrs_ring_32,
};
static const struct ath10k_htt_rx_ops htt_rx_ops_64 = {
.htt_get_rx_ring_size = ath10k_htt_get_rx_ring_size_64,
.htt_config_paddrs_ring = ath10k_htt_config_paddrs_ring_64,
.htt_set_paddrs_ring = ath10k_htt_set_paddrs_ring_64,
.htt_get_vaddr_ring = ath10k_htt_get_vaddr_ring_64,
.htt_reset_paddrs_ring = ath10k_htt_reset_paddrs_ring_64,
};
void ath10k_htt_set_rx_ops(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
if (ar->hw_params.target_64bit)
htt->rx_ops = &htt_rx_ops_64;
else
htt->rx_ops = &htt_rx_ops_32;
}
/*
* Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
* Copyright (c) 2014-2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -561,6 +561,12 @@ struct ath10k_hw_params {
u32 num_peers;
u32 ast_skid_limit;
u32 num_wds_entries;
/* Targets supporting physical addressing capability above 32-bits */
bool target_64bit;
/* Target rx ring fill level */
u32 rx_ring_fill_level;
};
struct htt_rx_desc;
......@@ -882,6 +888,7 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
#define PCIE_INTR_CLR_ADDRESS ar->regs->pcie_intr_clr_address
#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
#define CPU_INTR_ADDRESS 0x0010
#define FW_RAM_CONFIG_ADDRESS 0x0018
#define CCNT_TO_MSEC(ar, x) ((x) / ar->hw_params.channel_counters_freq_hz)
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -3597,7 +3597,7 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,
switch (txpath) {
case ATH10K_MAC_TX_HTT:
ret = ath10k_htt_tx(htt, txmode, skb);
ret = htt->tx_ops->htt_tx(htt, txmode, skb);
break;
case ATH10K_MAC_TX_HTT_MGMT:
ret = ath10k_htt_mgmt_tx(htt, skb);
......@@ -8294,7 +8294,8 @@ int ath10k_mac_register(struct ath10k *ar)
if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map) ||
test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, ar->wmi.svc_map)) {
ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
ieee80211_hw_set(ar->hw, TDLS_WIDER_BW);
if (test_bit(WMI_SERVICE_TDLS_WIDER_BANDWIDTH, ar->wmi.svc_map))
ieee80211_hw_set(ar->hw, TDLS_WIDER_BW);
}
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -23,6 +23,7 @@
#include "core.h"
#include "debug.h"
#include "coredump.h"
#include "targaddrs.h"
#include "bmi.h"
......@@ -51,6 +52,11 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
#define ATH10K_PCI_TARGET_WAIT 3000
#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
/* Maximum number of bytes that can be handled atomically by
* diag read and write.
*/
#define ATH10K_DIAG_TRANSFER_LIMIT 0x5000
static const struct pci_device_id ath10k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
{ PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
......@@ -785,7 +791,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
ATH10K_SKB_RXCB(skb)->paddr = paddr;
spin_lock_bh(&ce->ce_lock);
ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr);
spin_unlock_bh(&ce->ce_lock);
if (ret) {
dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
......@@ -923,7 +929,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
nbytes = min_t(unsigned int, remaining_bytes,
DIAG_TRANSFER_LIMIT);
ret = __ath10k_ce_rx_post_buf(ce_diag, &ce_data, ce_data);
ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &ce_data, ce_data);
if (ret != 0)
goto done;
......@@ -1089,7 +1095,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
/* Set up to receive directly into Target(!) address */
ret = __ath10k_ce_rx_post_buf(ce_diag, &address, address);
ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &address, address);
if (ret != 0)
goto done;
......@@ -1461,6 +1467,218 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
crash_data->registers[i] = reg_dump_values[i];
}
static int ath10k_pci_dump_memory_section(struct ath10k *ar,
const struct ath10k_mem_region *mem_region,
u8 *buf, size_t buf_len)
{
const struct ath10k_mem_section *cur_section, *next_section;
unsigned int count, section_size, skip_size;
int ret, i, j;
if (!mem_region || !buf)
return 0;
if (mem_region->section_table.size < 0)
return 0;
cur_section = &mem_region->section_table.sections[0];
if (mem_region->start > cur_section->start) {
ath10k_warn(ar, "incorrect memdump region 0x%x with section start addrress 0x%x.\n",
mem_region->start, cur_section->start);
return 0;
}
skip_size = cur_section->start - mem_region->start;
/* fill the gap between the first register section and register
* start address
*/
for (i = 0; i < skip_size; i++) {
*buf = ATH10K_MAGIC_NOT_COPIED;
buf++;
}
count = 0;
for (i = 0; cur_section != NULL; i++) {
section_size = cur_section->end - cur_section->start;
if (section_size <= 0) {
ath10k_warn(ar, "incorrect ramdump format with start address 0x%x and stop address 0x%x\n",
cur_section->start,
cur_section->end);
break;
}
if ((i + 1) == mem_region->section_table.size) {
/* last section */
next_section = NULL;
skip_size = 0;
} else {
next_section = cur_section + 1;
if (cur_section->end > next_section->start) {
ath10k_warn(ar, "next ramdump section 0x%x is smaller than current end address 0x%x\n",
next_section->start,
cur_section->end);
break;
}
skip_size = next_section->start - cur_section->end;
}
if (buf_len < (skip_size + section_size)) {
ath10k_warn(ar, "ramdump buffer is too small: %zu\n", buf_len);
break;
}
buf_len -= skip_size + section_size;
/* read section to dest memory */
ret = ath10k_pci_diag_read_mem(ar, cur_section->start,
buf, section_size);
if (ret) {
ath10k_warn(ar, "failed to read ramdump from section 0x%x: %d\n",
cur_section->start, ret);
break;
}
buf += section_size;
count += section_size;
/* fill in the gap between this section and the next */
for (j = 0; j < skip_size; j++) {
*buf = ATH10K_MAGIC_NOT_COPIED;
buf++;
}
count += skip_size;
if (!next_section)
/* this was the last section */
break;
cur_section = next_section;
}
return count;
}
static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config)
{
u32 val;
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
FW_RAM_CONFIG_ADDRESS, config);
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
FW_RAM_CONFIG_ADDRESS);
if (val != config) {
ath10k_warn(ar, "failed to set RAM config from 0x%x to 0x%x\n",
val, config);
return -EIO;
}
return 0;
}
static void ath10k_pci_dump_memory(struct ath10k *ar,
struct ath10k_fw_crash_data *crash_data)
{
const struct ath10k_hw_mem_layout *mem_layout;
const struct ath10k_mem_region *current_region;
struct ath10k_dump_ram_data_hdr *hdr;
u32 count, shift;
size_t buf_len;
int ret, i;
u8 *buf;
lockdep_assert_held(&ar->data_lock);
if (!crash_data)
return;
mem_layout = ath10k_coredump_get_mem_layout(ar);
if (!mem_layout)
return;
current_region = &mem_layout->region_table.regions[0];
buf = crash_data->ramdump_buf;
buf_len = crash_data->ramdump_buf_len;
memset(buf, 0, buf_len);
for (i = 0; i < mem_layout->region_table.size; i++) {
count = 0;
if (current_region->len > buf_len) {
ath10k_warn(ar, "memory region %s size %d is larger that remaining ramdump buffer size %zu\n",
current_region->name,
current_region->len,
buf_len);
break;
}
/* To get IRAM dump, the host driver needs to switch target
* ram config from DRAM to IRAM.
*/
if (current_region->type == ATH10K_MEM_REGION_TYPE_IRAM1 ||
current_region->type == ATH10K_MEM_REGION_TYPE_IRAM2) {
shift = current_region->start >> 20;
ret = ath10k_pci_set_ram_config(ar, shift);
if (ret) {
ath10k_warn(ar, "failed to switch ram config to IRAM for section %s: %d\n",
current_region->name, ret);
break;
}
}
/* Reserve space for the header. */
hdr = (void *)buf;
buf += sizeof(*hdr);
buf_len -= sizeof(*hdr);
if (current_region->section_table.size > 0) {
/* Copy each section individually. */
count = ath10k_pci_dump_memory_section(ar,
current_region,
buf,
current_region->len);
} else {
/* No individiual memory sections defined so we can
* copy the entire memory region.
*/
ret = ath10k_pci_diag_read_mem(ar,
current_region->start,
buf,
current_region->len);
if (ret) {
ath10k_warn(ar, "failed to copy ramdump region %s: %d\n",
current_region->name, ret);
break;
}
count = current_region->len;
}
hdr->region_type = cpu_to_le32(current_region->type);
hdr->start = cpu_to_le32(current_region->start);
hdr->length = cpu_to_le32(count);
if (count == 0)
/* Note: the header remains, just with zero length. */
break;
buf += count;
buf_len -= count;
current_region++;
}
}
static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
{
struct ath10k_fw_crash_data *crash_data;
......@@ -1470,7 +1688,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
ar->stats.fw_crash_counter++;
crash_data = ath10k_debug_get_new_fw_crash_data(ar);
crash_data = ath10k_coredump_new(ar);
if (crash_data)
scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);
......@@ -1481,6 +1699,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
ath10k_print_driver_info(ar);
ath10k_pci_dump_registers(ar, crash_data);
ath10k_ce_dump_registers(ar, crash_data);
ath10k_pci_dump_memory(ar, crash_data);
spin_unlock_bh(&ar->data_lock);
......@@ -1858,7 +2077,7 @@ int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
ret = ath10k_pci_bmi_wait(ar, ce_tx, ce_rx, &xfer);
if (ret) {
u32 unused_buffer;
dma_addr_t unused_buffer;
unsigned int unused_nbytes;
unsigned int unused_id;
......@@ -1871,7 +2090,7 @@ int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
err_resp:
if (resp) {
u32 unused_buffer;
dma_addr_t unused_buffer;
ath10k_ce_revoke_recv_next(ce_rx, NULL, &unused_buffer);
dma_unmap_single(ar->dev, resp_paddr,
......
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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
......@@ -210,6 +210,10 @@ struct rx_frag_info {
u8 ring1_more_count;
u8 ring2_more_count;
u8 ring3_more_count;
u8 ring4_more_count;
u8 ring5_more_count;
u8 ring6_more_count;
u8 ring7_more_count;
} __packed;
/*
......@@ -471,10 +475,16 @@ struct rx_msdu_start_qca99x0 {
__le32 info2; /* %RX_MSDU_START_INFO2_ */
} __packed;
struct rx_msdu_start_wcn3990 {
__le32 info2; /* %RX_MSDU_START_INFO2_ */
__le32 info3; /* %RX_MSDU_START_INFO3_ */
} __packed;
struct rx_msdu_start {
struct rx_msdu_start_common common;
union {
struct rx_msdu_start_qca99x0 qca99x0;
struct rx_msdu_start_wcn3990 wcn3990;
} __packed;
} __packed;
......@@ -595,10 +605,23 @@ struct rx_msdu_end_qca99x0 {
__le32 info2;
} __packed;
struct rx_msdu_end_wcn3990 {
__le32 ipv6_crc;
__le32 tcp_seq_no;
__le32 tcp_ack_no;
__le32 info1;
__le32 info2;
__le32 rule_indication_0;
__le32 rule_indication_1;
__le32 rule_indication_2;
__le32 rule_indication_3;
} __packed;
struct rx_msdu_end {
struct rx_msdu_end_common common;
union {
struct rx_msdu_end_qca99x0 qca99x0;
struct rx_msdu_end_wcn3990 wcn3990;
} __packed;
} __packed;
......@@ -963,6 +986,12 @@ struct rx_pkt_end {
__le32 phy_timestamp_2;
} __packed;
struct rx_pkt_end_wcn3990 {
__le32 info0; /* %RX_PKT_END_INFO0_ */
__le64 phy_timestamp_1;
__le64 phy_timestamp_2;
} __packed;
#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_MASK 0x00003fff
#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_LSB 0
#define RX_LOCATION_INFO0_RTT_FAC_VHT_MASK 0x1fff8000
......@@ -998,6 +1027,12 @@ struct rx_location_info {
__le32 rx_location_info1; /* %RX_LOCATION_INFO1_ */
} __packed;
struct rx_location_info_wcn3990 {
__le32 rx_location_info0; /* %RX_LOCATION_INFO0_ */
__le32 rx_location_info1; /* %RX_LOCATION_INFO1_ */
__le32 rx_location_info2; /* %RX_LOCATION_INFO2_ */
} __packed;
enum rx_phy_ppdu_end_info0 {
RX_PHY_PPDU_END_INFO0_ERR_RADAR = BIT(2),
RX_PHY_PPDU_END_INFO0_ERR_RX_ABORT = BIT(3),
......@@ -1086,6 +1121,20 @@ struct rx_ppdu_end_qca9984 {
__le16 info1; /* %RX_PPDU_END_INFO1_ */
} __packed;
struct rx_ppdu_end_wcn3990 {
struct rx_pkt_end_wcn3990 rx_pkt_end;
struct rx_location_info_wcn3990 rx_location_info;
struct rx_phy_ppdu_end rx_phy_ppdu_end;
__le32 rx_timing_offset;
__le32 reserved_info_0;
__le32 reserved_info_1;
__le32 rx_antenna_info;
__le32 rx_coex_info;
__le32 rx_mpdu_cnt_info;
__le64 phy_timestamp_tx;
__le32 rx_bb_length;
} __packed;
struct rx_ppdu_end {
struct rx_ppdu_end_common common;
union {
......@@ -1093,6 +1142,7 @@ struct rx_ppdu_end {
struct rx_ppdu_end_qca6174 qca6174;
struct rx_ppdu_end_qca99x0 qca99x0;
struct rx_ppdu_end_qca9984 qca9984;
struct rx_ppdu_end_wcn3990 wcn3990;
} __packed;
} __packed;
......
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
* Copyright (c) 2013-2017 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 (c) 2013 Qualcomm Atheros, Inc.
* Copyright (c) 2013-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 (c) 2015 Qualcomm Atheros, Inc.
* Copyright (c) 2015-2016 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 (c) 2015 Qualcomm Atheros, Inc.
* Copyright (c) 2015-2016 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2016 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 (c) 2014 Qualcomm Atheros, Inc.
* Copyright (c) 2014-2017 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 (c) 2014 Qualcomm Atheros, Inc.
* Copyright (c) 2014,2017 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 (c) 2014 Qualcomm Atheros, Inc.
* Copyright (c) 2014-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 (c) 2014 Qualcomm Atheros, Inc.
* Copyright (c) 2014-2016 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2016 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2016 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2014,2016 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 (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
* Copyright (c) 2011-2017 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 (c) 2015 Qualcomm Atheros, Inc.
* Copyright (c) 2015-2017 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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册