Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 4.21. Major changes: ath10k * add support for WCN3990 firmware crash recovery * add firmware memory dump support for QCA4019 wil6210 * add firmware error recovery while in AP mode ath9k * remove experimental notice from dynack feature
This commit is contained in:
commit
bb38177cb6
@ -561,6 +561,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.hw_ops = &wcn3990_ops,
|
||||
.decap_align_bytes = 1,
|
||||
.num_peers = TARGET_HL_10_TLV_NUM_PEERS,
|
||||
.n_cipher_suites = 8,
|
||||
.ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT,
|
||||
.num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES,
|
||||
.target_64bit = true,
|
||||
@ -594,6 +595,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
|
||||
[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",
|
||||
[ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel",
|
||||
};
|
||||
|
||||
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
|
||||
@ -2183,6 +2185,8 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d",
|
||||
ret);
|
||||
|
||||
complete(&ar->driver_recovery);
|
||||
}
|
||||
|
||||
static void ath10k_core_set_coverage_class_work(struct work_struct *work)
|
||||
@ -3046,6 +3050,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
init_completion(&ar->driver_recovery);
|
||||
init_completion(&ar->wow.wakeup_completed);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
|
@ -474,6 +474,7 @@ struct ath10k_htt_data_stats {
|
||||
u64 bw[ATH10K_COUNTER_TYPE_MAX][ATH10K_BW_NUM];
|
||||
u64 nss[ATH10K_COUNTER_TYPE_MAX][ATH10K_NSS_NUM];
|
||||
u64 gi[ATH10K_COUNTER_TYPE_MAX][ATH10K_GI_NUM];
|
||||
u64 rate_table[ATH10K_COUNTER_TYPE_MAX][ATH10K_RATE_TABLE_NUM];
|
||||
};
|
||||
|
||||
struct ath10k_htt_tx_stats {
|
||||
@ -760,6 +761,9 @@ enum ath10k_fw_features {
|
||||
/* Firmware load is done externally, not by bmi */
|
||||
ATH10K_FW_FEATURE_NON_BMI = 19,
|
||||
|
||||
/* Firmware sends only one chan_info event per channel */
|
||||
ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL = 20,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
@ -960,6 +964,7 @@ struct ath10k {
|
||||
} hif;
|
||||
|
||||
struct completion target_suspend;
|
||||
struct completion driver_recovery;
|
||||
|
||||
const struct ath10k_hw_regs *regs;
|
||||
const struct ath10k_hw_ce_regs *hw_ce_regs;
|
||||
|
@ -867,9 +867,105 @@ static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ath10k_mem_section ipq4019_soc_reg_range[] = {
|
||||
{0x080000, 0x080004},
|
||||
{0x080020, 0x080024},
|
||||
{0x080028, 0x080050},
|
||||
{0x0800d4, 0x0800ec},
|
||||
{0x08010c, 0x080118},
|
||||
{0x080284, 0x080290},
|
||||
{0x0802a8, 0x0802b8},
|
||||
{0x0802dc, 0x08030c},
|
||||
{0x082000, 0x083fff}
|
||||
};
|
||||
|
||||
static const struct ath10k_mem_region qca4019_hw10_mem_regions[] = {
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_DRAM,
|
||||
.start = 0x400000,
|
||||
.len = 0x68000,
|
||||
.name = "DRAM",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_REG,
|
||||
.start = 0xC0000,
|
||||
.len = 0x40000,
|
||||
.name = "SRAM",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_REG,
|
||||
.start = 0x98000,
|
||||
.len = 0x50000,
|
||||
.name = "IRAM",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_IOREG,
|
||||
.start = 0x30000,
|
||||
.len = 0x7000,
|
||||
.name = "APB REG 1",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_IOREG,
|
||||
.start = 0x3f000,
|
||||
.len = 0x3000,
|
||||
.name = "APB REG 2",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_IOREG,
|
||||
.start = 0x43000,
|
||||
.len = 0x3000,
|
||||
.name = "WIFI REG",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_IOREG,
|
||||
.start = 0x4A000,
|
||||
.len = 0x5000,
|
||||
.name = "CE REG",
|
||||
.section_table = {
|
||||
.sections = NULL,
|
||||
.size = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = ATH10K_MEM_REGION_TYPE_REG,
|
||||
.start = 0x080000,
|
||||
.len = 0x083fff - 0x080000,
|
||||
.name = "REG_TOTAL",
|
||||
.section_table = {
|
||||
.sections = ipq4019_soc_reg_range,
|
||||
.size = ARRAY_SIZE(ipq4019_soc_reg_range),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
{
|
||||
.hw_id = QCA6174_HW_1_0_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA6174,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw10_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw10_mem_regions),
|
||||
@ -877,6 +973,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA6174_HW_1_1_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA6174,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw10_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw10_mem_regions),
|
||||
@ -884,6 +981,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA6174_HW_1_3_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA6174,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw10_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw10_mem_regions),
|
||||
@ -891,6 +989,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA6174_HW_2_1_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA6174,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw21_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw21_mem_regions),
|
||||
@ -898,6 +997,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA6174_HW_3_0_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA6174,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw30_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw30_mem_regions),
|
||||
@ -905,6 +1005,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA6174_HW_3_2_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA6174,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw30_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw30_mem_regions),
|
||||
@ -912,6 +1013,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA9377_HW_1_1_DEV_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA9377,
|
||||
.region_table = {
|
||||
.regions = qca6174_hw30_mem_regions,
|
||||
.size = ARRAY_SIZE(qca6174_hw30_mem_regions),
|
||||
@ -919,6 +1021,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA988X_HW_2_0_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA988X,
|
||||
.region_table = {
|
||||
.regions = qca988x_hw20_mem_regions,
|
||||
.size = ARRAY_SIZE(qca988x_hw20_mem_regions),
|
||||
@ -926,6 +1029,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA9984_HW_1_0_DEV_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA9984,
|
||||
.region_table = {
|
||||
.regions = qca9984_hw10_mem_regions,
|
||||
.size = ARRAY_SIZE(qca9984_hw10_mem_regions),
|
||||
@ -933,6 +1037,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA9888_HW_2_0_DEV_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA9888,
|
||||
.region_table = {
|
||||
.regions = qca9984_hw10_mem_regions,
|
||||
.size = ARRAY_SIZE(qca9984_hw10_mem_regions),
|
||||
@ -940,12 +1045,20 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
|
||||
},
|
||||
{
|
||||
.hw_id = QCA99X0_HW_2_0_DEV_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA99X0,
|
||||
.region_table = {
|
||||
.regions = qca99x0_hw20_mem_regions,
|
||||
.size = ARRAY_SIZE(qca99x0_hw20_mem_regions),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
.hw_id = QCA4019_HW_1_0_DEV_VERSION,
|
||||
.hw_rev = ATH10K_HW_QCA4019,
|
||||
.region_table = {
|
||||
.regions = qca4019_hw10_mem_regions,
|
||||
.size = ARRAY_SIZE(qca4019_hw10_mem_regions),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)
|
||||
@ -987,7 +1100,8 @@ const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hw_mem_layouts); i++) {
|
||||
if (ar->target_version == hw_mem_layouts[i].hw_id)
|
||||
if (ar->target_version == hw_mem_layouts[i].hw_id &&
|
||||
ar->hw_rev == hw_mem_layouts[i].hw_rev)
|
||||
return &hw_mem_layouts[i];
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,7 @@ struct ath10k_mem_region {
|
||||
*/
|
||||
struct ath10k_hw_mem_layout {
|
||||
u32 hw_id;
|
||||
u32 hw_rev;
|
||||
|
||||
struct {
|
||||
const struct ath10k_mem_region *regions;
|
||||
|
@ -665,7 +665,7 @@ static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
|
||||
"retry", "ampdu"};
|
||||
const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
|
||||
int len = 0, i, j, k, retval = 0;
|
||||
const int size = 2 * 4096;
|
||||
const int size = 16 * 4096;
|
||||
char *buf;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
@ -719,6 +719,16 @@ static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
|
||||
len += scnprintf(buf + len, size - len, "%llu ",
|
||||
stats->legacy[j][i]);
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" Rate table %s (1,2 ... Mbps)\n ",
|
||||
str[j]);
|
||||
for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) {
|
||||
len += scnprintf(buf + len, size - len, "%llu ",
|
||||
stats->rate_table[j][i]);
|
||||
if (!((i + 1) % 8))
|
||||
len +=
|
||||
scnprintf(buf + len, size - len, "\n ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2650,7 +2650,7 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
|
||||
{
|
||||
struct rate_info *txrate = &arsta->txrate;
|
||||
struct ath10k_htt_tx_stats *tx_stats;
|
||||
int ht_idx, gi, mcs, bw, nss;
|
||||
int idx, ht_idx, gi, mcs, bw, nss;
|
||||
|
||||
if (!arsta->tx_stats)
|
||||
return;
|
||||
@ -2661,6 +2661,8 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
|
||||
mcs = txrate->mcs;
|
||||
bw = txrate->bw;
|
||||
nss = txrate->nss;
|
||||
idx = mcs * 8 + 8 * 10 * nss;
|
||||
idx += bw * 2 + gi;
|
||||
|
||||
#define STATS_OP_FMT(name) tx_stats->stats[ATH10K_STATS_TYPE_##name]
|
||||
|
||||
@ -2709,12 +2711,16 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
|
||||
pstats->succ_bytes + pstats->retry_bytes;
|
||||
STATS_OP_FMT(AMPDU).gi[0][gi] +=
|
||||
pstats->succ_bytes + pstats->retry_bytes;
|
||||
STATS_OP_FMT(AMPDU).rate_table[0][idx] +=
|
||||
pstats->succ_bytes + pstats->retry_bytes;
|
||||
STATS_OP_FMT(AMPDU).bw[1][bw] +=
|
||||
pstats->succ_pkts + pstats->retry_pkts;
|
||||
STATS_OP_FMT(AMPDU).nss[1][nss] +=
|
||||
pstats->succ_pkts + pstats->retry_pkts;
|
||||
STATS_OP_FMT(AMPDU).gi[1][gi] +=
|
||||
pstats->succ_pkts + pstats->retry_pkts;
|
||||
STATS_OP_FMT(AMPDU).rate_table[1][idx] +=
|
||||
pstats->succ_pkts + pstats->retry_pkts;
|
||||
} else {
|
||||
tx_stats->ack_fails +=
|
||||
ATH10K_HW_BA_FAIL(pstats->flags);
|
||||
@ -2743,6 +2749,15 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
|
||||
STATS_OP_FMT(RETRY).bw[1][bw] += pstats->retry_pkts;
|
||||
STATS_OP_FMT(RETRY).nss[1][nss] += pstats->retry_pkts;
|
||||
STATS_OP_FMT(RETRY).gi[1][gi] += pstats->retry_pkts;
|
||||
|
||||
if (txrate->flags >= RATE_INFO_FLAGS_MCS) {
|
||||
STATS_OP_FMT(SUCC).rate_table[0][idx] += pstats->succ_bytes;
|
||||
STATS_OP_FMT(SUCC).rate_table[1][idx] += pstats->succ_pkts;
|
||||
STATS_OP_FMT(FAIL).rate_table[0][idx] += pstats->failed_bytes;
|
||||
STATS_OP_FMT(FAIL).rate_table[1][idx] += pstats->failed_pkts;
|
||||
STATS_OP_FMT(RETRY).rate_table[0][idx] += pstats->retry_bytes;
|
||||
STATS_OP_FMT(RETRY).rate_table[1][idx] += pstats->retry_pkts;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -6296,8 +6296,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
if (ath10k_debug_is_extd_tx_stats_enabled(ar)) {
|
||||
arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats),
|
||||
GFP_KERNEL);
|
||||
if (!arsta->tx_stats)
|
||||
if (!arsta->tx_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
|
||||
@ -6385,8 +6387,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
"mac vdev %d peer delete %pM sta %pK (sta gone)\n",
|
||||
arvif->vdev_id, sta->addr, sta);
|
||||
|
||||
if (ath10k_debug_is_extd_tx_stats_enabled(ar))
|
||||
if (ath10k_debug_is_extd_tx_stats_enabled(ar)) {
|
||||
kfree(arsta->tx_stats);
|
||||
arsta->tx_stats = NULL;
|
||||
}
|
||||
|
||||
if (sta->tdls) {
|
||||
ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id,
|
||||
@ -8313,7 +8317,6 @@ static u32 ath10k_mac_wrdd_get_mcc(struct ath10k *ar, union acpi_object *wrdd)
|
||||
|
||||
static int ath10k_mac_get_wrdd_regulatory(struct ath10k *ar, u16 *rd)
|
||||
{
|
||||
struct pci_dev __maybe_unused *pdev = to_pci_dev(ar->dev);
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
@ -8321,7 +8324,7 @@ static int ath10k_mac_get_wrdd_regulatory(struct ath10k *ar, u16 *rd)
|
||||
u32 alpha2_code;
|
||||
char alpha2[3];
|
||||
|
||||
root_handle = ACPI_HANDLE(&pdev->dev);
|
||||
root_handle = ACPI_HANDLE(ar->dev);
|
||||
if (!root_handle)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
@ -543,7 +543,7 @@ static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
|
||||
goto out;
|
||||
|
||||
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath10k_err(ar, "capablity req rejected: %d\n", resp->resp.error);
|
||||
ath10k_err(ar, "capability req rejected: %d\n", resp->resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -623,7 +623,7 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capablity request completed\n");
|
||||
ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capability request completed\n");
|
||||
return 0;
|
||||
|
||||
out:
|
||||
@ -657,7 +657,7 @@ ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi)
|
||||
wlfw_ind_register_req_msg_v01_ei, &req);
|
||||
if (ret < 0) {
|
||||
qmi_txn_cancel(&txn);
|
||||
ath10k_err(ar, "failed to send indication registed request: %d\n", ret);
|
||||
ath10k_err(ar, "failed to send indication registered request: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -931,7 +931,7 @@ static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size)
|
||||
qmi->msa_mem_size = resource_size(&r);
|
||||
qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size,
|
||||
MEMREMAP_WT);
|
||||
if (!qmi->msa_pa) {
|
||||
if (!qmi->msa_va) {
|
||||
dev_err(dev, "failed to map memory region: %pa\n", &r.start);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -46,14 +46,14 @@ static char *const ce_name[] = {
|
||||
"WLAN_CE_11",
|
||||
};
|
||||
|
||||
static struct ath10k_wcn3990_vreg_info vreg_cfg[] = {
|
||||
{NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false},
|
||||
{NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false},
|
||||
{NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false},
|
||||
{NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false},
|
||||
static struct ath10k_vreg_info vreg_cfg[] = {
|
||||
{NULL, "vdd-0.8-cx-mx", 800000, 850000, 0, 0, false},
|
||||
{NULL, "vdd-1.8-xo", 1800000, 1850000, 0, 0, false},
|
||||
{NULL, "vdd-1.3-rfa", 1300000, 1350000, 0, 0, false},
|
||||
{NULL, "vdd-3.3-ch0", 3300000, 3350000, 0, 0, false},
|
||||
};
|
||||
|
||||
static struct ath10k_wcn3990_clk_info clk_cfg[] = {
|
||||
static struct ath10k_clk_info clk_cfg[] = {
|
||||
{NULL, "cxo_ref_clk_pin", 0, false},
|
||||
};
|
||||
|
||||
@ -474,14 +474,14 @@ static struct service_to_pipe target_service_to_ce_map_wlan[] = {
|
||||
},
|
||||
};
|
||||
|
||||
void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||
static void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
|
||||
iowrite32(value, ar_snoc->mem + offset);
|
||||
}
|
||||
|
||||
u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset)
|
||||
static u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
u32 val;
|
||||
@ -918,7 +918,9 @@ static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)
|
||||
|
||||
static void ath10k_snoc_hif_stop(struct ath10k *ar)
|
||||
{
|
||||
ath10k_snoc_irq_disable(ar);
|
||||
if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
|
||||
ath10k_snoc_irq_disable(ar);
|
||||
|
||||
napi_synchronize(&ar->napi);
|
||||
napi_disable(&ar->napi);
|
||||
ath10k_snoc_buffer_cleanup(ar);
|
||||
@ -927,10 +929,14 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar)
|
||||
|
||||
static int ath10k_snoc_hif_start(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
|
||||
napi_enable(&ar->napi);
|
||||
ath10k_snoc_irq_enable(ar);
|
||||
ath10k_snoc_rx_post(ar);
|
||||
|
||||
clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
|
||||
|
||||
return 0;
|
||||
@ -994,7 +1000,8 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar)
|
||||
|
||||
static void ath10k_snoc_wlan_disable(struct ath10k *ar)
|
||||
{
|
||||
ath10k_qmi_wlan_disable(ar);
|
||||
if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
|
||||
ath10k_qmi_wlan_disable(ar);
|
||||
}
|
||||
|
||||
static void ath10k_snoc_hif_power_down(struct ath10k *ar)
|
||||
@ -1091,6 +1098,11 @@ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)
|
||||
struct ath10k *ar = container_of(ctx, struct ath10k, napi);
|
||||
int done = 0;
|
||||
|
||||
if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
|
||||
napi_complete(ctx);
|
||||
return done;
|
||||
}
|
||||
|
||||
ath10k_ce_per_engine_service_any(ar);
|
||||
done = ath10k_htt_txrx_compl_task(ar, budget);
|
||||
|
||||
@ -1187,17 +1199,29 @@ int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
|
||||
struct ath10k_bus_params bus_params;
|
||||
int ret;
|
||||
|
||||
if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
case ATH10K_QMI_EVENT_FW_READY_IND:
|
||||
if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {
|
||||
queue_work(ar->workqueue, &ar->restart_work);
|
||||
break;
|
||||
}
|
||||
|
||||
bus_params.dev_type = ATH10K_DEV_TYPE_LL;
|
||||
bus_params.chip_id = ar_snoc->target_info.soc_version;
|
||||
ret = ath10k_core_register(ar, &bus_params);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to register driver core: %d\n",
|
||||
ath10k_err(ar, "Failed to register driver core: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
set_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags);
|
||||
break;
|
||||
case ATH10K_QMI_EVENT_FW_DOWN_IND:
|
||||
set_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);
|
||||
set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
|
||||
break;
|
||||
default:
|
||||
ath10k_err(ar, "invalid fw indication: %llx\n", type);
|
||||
@ -1246,7 +1270,7 @@ static void ath10k_snoc_release_resource(struct ath10k *ar)
|
||||
}
|
||||
|
||||
static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev,
|
||||
struct ath10k_wcn3990_vreg_info *vreg_info)
|
||||
struct ath10k_vreg_info *vreg_info)
|
||||
{
|
||||
struct regulator *reg;
|
||||
int ret = 0;
|
||||
@ -1284,7 +1308,7 @@ done:
|
||||
}
|
||||
|
||||
static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev,
|
||||
struct ath10k_wcn3990_clk_info *clk_info)
|
||||
struct ath10k_clk_info *clk_info)
|
||||
{
|
||||
struct clk *handle;
|
||||
int ret = 0;
|
||||
@ -1311,10 +1335,80 @@ static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_wcn3990_vreg_on(struct ath10k *ar)
|
||||
static int __ath10k_snoc_vreg_on(struct ath10k *ar,
|
||||
struct ath10k_vreg_info *vreg_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
|
||||
vreg_info->max_v);
|
||||
if (ret) {
|
||||
ath10k_err(ar,
|
||||
"failed to set regulator %s voltage-min: %d voltage-max: %d\n",
|
||||
vreg_info->name, vreg_info->min_v, vreg_info->max_v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vreg_info->load_ua) {
|
||||
ret = regulator_set_load(vreg_info->reg, vreg_info->load_ua);
|
||||
if (ret < 0) {
|
||||
ath10k_err(ar, "failed to set regulator %s load: %d\n",
|
||||
vreg_info->name, vreg_info->load_ua);
|
||||
goto err_set_load;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regulator_enable(vreg_info->reg);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to enable regulator %s\n",
|
||||
vreg_info->name);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
if (vreg_info->settle_delay)
|
||||
udelay(vreg_info->settle_delay);
|
||||
|
||||
return 0;
|
||||
|
||||
err_enable:
|
||||
regulator_set_load(vreg_info->reg, 0);
|
||||
err_set_load:
|
||||
regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __ath10k_snoc_vreg_off(struct ath10k *ar,
|
||||
struct ath10k_vreg_info *vreg_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being disabled\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_disable(vreg_info->reg);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to disable regulator %s\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_set_load(vreg_info->reg, 0);
|
||||
if (ret < 0)
|
||||
ath10k_err(ar, "failed to set load %s\n", vreg_info->name);
|
||||
|
||||
ret = regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to set voltage %s\n", vreg_info->name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_snoc_vreg_on(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct ath10k_wcn3990_vreg_info *vreg_info;
|
||||
struct ath10k_vreg_info *vreg_info;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
@ -1324,62 +1418,30 @@ static int ath10k_wcn3990_vreg_on(struct ath10k *ar)
|
||||
if (!vreg_info->reg)
|
||||
continue;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
|
||||
vreg_info->max_v);
|
||||
if (ret) {
|
||||
ath10k_err(ar,
|
||||
"failed to set regulator %s voltage-min: %d voltage-max: %d\n",
|
||||
vreg_info->name, vreg_info->min_v, vreg_info->max_v);
|
||||
ret = __ath10k_snoc_vreg_on(ar, vreg_info);
|
||||
if (ret)
|
||||
goto err_reg_config;
|
||||
}
|
||||
|
||||
if (vreg_info->load_ua) {
|
||||
ret = regulator_set_load(vreg_info->reg,
|
||||
vreg_info->load_ua);
|
||||
if (ret < 0) {
|
||||
ath10k_err(ar,
|
||||
"failed to set regulator %s load: %d\n",
|
||||
vreg_info->name,
|
||||
vreg_info->load_ua);
|
||||
goto err_reg_config;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regulator_enable(vreg_info->reg);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to enable regulator %s\n",
|
||||
vreg_info->name);
|
||||
goto err_reg_config;
|
||||
}
|
||||
|
||||
if (vreg_info->settle_delay)
|
||||
udelay(vreg_info->settle_delay);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_config:
|
||||
for (; i >= 0; i--) {
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
vreg_info = &ar_snoc->vreg[i];
|
||||
|
||||
if (!vreg_info->reg)
|
||||
continue;
|
||||
|
||||
regulator_disable(vreg_info->reg);
|
||||
regulator_set_load(vreg_info->reg, 0);
|
||||
regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
|
||||
__ath10k_snoc_vreg_off(ar, vreg_info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_wcn3990_vreg_off(struct ath10k *ar)
|
||||
static int ath10k_snoc_vreg_off(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct ath10k_wcn3990_vreg_info *vreg_info;
|
||||
struct ath10k_vreg_info *vreg_info;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
@ -1389,33 +1451,16 @@ static int ath10k_wcn3990_vreg_off(struct ath10k *ar)
|
||||
if (!vreg_info->reg)
|
||||
continue;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being disabled\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_disable(vreg_info->reg);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to disable regulator %s\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_set_load(vreg_info->reg, 0);
|
||||
if (ret < 0)
|
||||
ath10k_err(ar, "failed to set load %s\n",
|
||||
vreg_info->name);
|
||||
|
||||
ret = regulator_set_voltage(vreg_info->reg, 0,
|
||||
vreg_info->max_v);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to set voltage %s\n",
|
||||
vreg_info->name);
|
||||
ret = __ath10k_snoc_vreg_off(ar, vreg_info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_wcn3990_clk_init(struct ath10k *ar)
|
||||
static int ath10k_snoc_clk_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct ath10k_wcn3990_clk_info *clk_info;
|
||||
struct ath10k_clk_info *clk_info;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
@ -1449,7 +1494,7 @@ static int ath10k_wcn3990_clk_init(struct ath10k *ar)
|
||||
return 0;
|
||||
|
||||
err_clock_config:
|
||||
for (; i >= 0; i--) {
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
clk_info = &ar_snoc->clk[i];
|
||||
|
||||
if (!clk_info->handle)
|
||||
@ -1461,10 +1506,10 @@ err_clock_config:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_wcn3990_clk_deinit(struct ath10k *ar)
|
||||
static int ath10k_snoc_clk_deinit(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct ath10k_wcn3990_clk_info *clk_info;
|
||||
struct ath10k_clk_info *clk_info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) {
|
||||
@ -1488,18 +1533,18 @@ static int ath10k_hw_power_on(struct ath10k *ar)
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");
|
||||
|
||||
ret = ath10k_wcn3990_vreg_on(ar);
|
||||
ret = ath10k_snoc_vreg_on(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ath10k_wcn3990_clk_init(ar);
|
||||
ret = ath10k_snoc_clk_init(ar);
|
||||
if (ret)
|
||||
goto vreg_off;
|
||||
|
||||
return ret;
|
||||
|
||||
vreg_off:
|
||||
ath10k_wcn3990_vreg_off(ar);
|
||||
ath10k_snoc_vreg_off(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1509,9 +1554,9 @@ static int ath10k_hw_power_off(struct ath10k *ar)
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");
|
||||
|
||||
ath10k_wcn3990_clk_deinit(ar);
|
||||
ath10k_snoc_clk_deinit(ar);
|
||||
|
||||
ret = ath10k_wcn3990_vreg_off(ar);
|
||||
ret = ath10k_snoc_vreg_off(ar);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1628,8 +1673,17 @@ err_core_destroy:
|
||||
static int ath10k_snoc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ath10k *ar = platform_get_drvdata(pdev);
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");
|
||||
|
||||
reinit_completion(&ar->driver_recovery);
|
||||
|
||||
if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
|
||||
wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);
|
||||
|
||||
set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);
|
||||
|
||||
ath10k_core_unregister(ar);
|
||||
ath10k_hw_power_off(ar);
|
||||
ath10k_snoc_free_irq(ar);
|
||||
@ -1641,12 +1695,12 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static struct platform_driver ath10k_snoc_driver = {
|
||||
.probe = ath10k_snoc_probe,
|
||||
.remove = ath10k_snoc_remove,
|
||||
.driver = {
|
||||
.name = "ath10k_snoc",
|
||||
.of_match_table = ath10k_snoc_dt_match,
|
||||
},
|
||||
.probe = ath10k_snoc_probe,
|
||||
.remove = ath10k_snoc_remove,
|
||||
.driver = {
|
||||
.name = "ath10k_snoc",
|
||||
.of_match_table = ath10k_snoc_dt_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ath10k_snoc_driver);
|
||||
|
||||
|
@ -53,7 +53,7 @@ struct ath10k_snoc_ce_irq {
|
||||
u32 irq_line;
|
||||
};
|
||||
|
||||
struct ath10k_wcn3990_vreg_info {
|
||||
struct ath10k_vreg_info {
|
||||
struct regulator *reg;
|
||||
const char *name;
|
||||
u32 min_v;
|
||||
@ -63,13 +63,19 @@ struct ath10k_wcn3990_vreg_info {
|
||||
bool required;
|
||||
};
|
||||
|
||||
struct ath10k_wcn3990_clk_info {
|
||||
struct ath10k_clk_info {
|
||||
struct clk *handle;
|
||||
const char *name;
|
||||
u32 freq;
|
||||
bool required;
|
||||
};
|
||||
|
||||
enum ath10k_snoc_flags {
|
||||
ATH10K_SNOC_FLAG_REGISTERED,
|
||||
ATH10K_SNOC_FLAG_UNREGISTERING,
|
||||
ATH10K_SNOC_FLAG_RECOVERY,
|
||||
};
|
||||
|
||||
struct ath10k_snoc {
|
||||
struct platform_device *dev;
|
||||
struct ath10k *ar;
|
||||
@ -81,9 +87,10 @@ struct ath10k_snoc {
|
||||
struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX];
|
||||
struct ath10k_ce ce;
|
||||
struct timer_list rx_post_retry;
|
||||
struct ath10k_wcn3990_vreg_info *vreg;
|
||||
struct ath10k_wcn3990_clk_info *clk;
|
||||
struct ath10k_vreg_info *vreg;
|
||||
struct ath10k_clk_info *clk;
|
||||
struct ath10k_qmi *qmi;
|
||||
unsigned long int flags;
|
||||
};
|
||||
|
||||
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
|
||||
@ -91,8 +98,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
|
||||
return (struct ath10k_snoc *)ar->drv_priv;
|
||||
}
|
||||
|
||||
void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value);
|
||||
u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset);
|
||||
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type);
|
||||
|
||||
#endif /* _SNOC_H_ */
|
||||
|
@ -762,6 +762,9 @@ static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar,
|
||||
arg->noise_floor = ev->noise_floor;
|
||||
arg->rx_clear_count = ev->rx_clear_count;
|
||||
arg->cycle_count = ev->cycle_count;
|
||||
if (test_bit(ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
arg->mac_clk_mhz = ev->mac_clk_mhz;
|
||||
|
||||
kfree(tb);
|
||||
return 0;
|
||||
@ -3452,7 +3455,6 @@ ath10k_wmi_tlv_op_gen_config_pno_start(struct ath10k *ar,
|
||||
struct wmi_tlv *tlv;
|
||||
struct sk_buff *skb;
|
||||
__le32 *channel_list;
|
||||
u16 tlv_len;
|
||||
size_t len;
|
||||
void *ptr;
|
||||
u32 i;
|
||||
@ -3510,8 +3512,6 @@ ath10k_wmi_tlv_op_gen_config_pno_start(struct ath10k *ar,
|
||||
/* nlo_configured_parameters(nlo_list) */
|
||||
cmd->no_of_ssids = __cpu_to_le32(min_t(u8, pno->uc_networks_count,
|
||||
WMI_NLO_MAX_SSIDS));
|
||||
tlv_len = __le32_to_cpu(cmd->no_of_ssids) *
|
||||
sizeof(struct nlo_configured_parameters);
|
||||
|
||||
tlv = ptr;
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
|
||||
|
@ -1579,6 +1579,16 @@ struct ath10k_mgmt_tx_pkt_addr {
|
||||
dma_addr_t paddr;
|
||||
};
|
||||
|
||||
struct chan_info_params {
|
||||
u32 err_code;
|
||||
u32 freq;
|
||||
u32 cmd_flags;
|
||||
u32 noise_floor;
|
||||
u32 rx_clear_count;
|
||||
u32 cycle_count;
|
||||
u32 mac_clk_mhz;
|
||||
};
|
||||
|
||||
struct wmi_tlv_mgmt_tx_compl_ev {
|
||||
__le32 desc_id;
|
||||
__le32 status;
|
||||
|
@ -2554,12 +2554,89 @@ static int ath10k_wmi_10_4_op_pull_ch_info_ev(struct ath10k *ar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the channel info event for firmware which only sends one
|
||||
* chan_info event per scanned channel.
|
||||
*/
|
||||
static void ath10k_wmi_event_chan_info_unpaired(struct ath10k *ar,
|
||||
struct chan_info_params *params)
|
||||
{
|
||||
struct survey_info *survey;
|
||||
int idx;
|
||||
|
||||
if (params->cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "chan info report completed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
idx = freq_to_idx(ar, params->freq);
|
||||
if (idx >= ARRAY_SIZE(ar->survey)) {
|
||||
ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
|
||||
params->freq, idx);
|
||||
return;
|
||||
}
|
||||
|
||||
survey = &ar->survey[idx];
|
||||
|
||||
if (!params->mac_clk_mhz || !survey)
|
||||
return;
|
||||
|
||||
memset(survey, 0, sizeof(*survey));
|
||||
|
||||
survey->noise = params->noise_floor;
|
||||
survey->time = (params->cycle_count / params->mac_clk_mhz) / 1000;
|
||||
survey->time_busy = (params->rx_clear_count / params->mac_clk_mhz) / 1000;
|
||||
survey->filled |= SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the channel info event for firmware which sends chan_info
|
||||
* event in pairs(start and stop events) for every scanned channel.
|
||||
*/
|
||||
static void ath10k_wmi_event_chan_info_paired(struct ath10k *ar,
|
||||
struct chan_info_params *params)
|
||||
{
|
||||
struct survey_info *survey;
|
||||
int idx;
|
||||
|
||||
idx = freq_to_idx(ar, params->freq);
|
||||
if (idx >= ARRAY_SIZE(ar->survey)) {
|
||||
ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
|
||||
params->freq, idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (params->cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
|
||||
if (ar->ch_info_can_report_survey) {
|
||||
survey = &ar->survey[idx];
|
||||
survey->noise = params->noise_floor;
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
||||
|
||||
ath10k_hw_fill_survey_time(ar,
|
||||
survey,
|
||||
params->cycle_count,
|
||||
params->rx_clear_count,
|
||||
ar->survey_last_cycle_count,
|
||||
ar->survey_last_rx_clear_count);
|
||||
}
|
||||
|
||||
ar->ch_info_can_report_survey = false;
|
||||
} else {
|
||||
ar->ch_info_can_report_survey = true;
|
||||
}
|
||||
|
||||
if (!(params->cmd_flags & WMI_CHAN_INFO_FLAG_PRE_COMPLETE)) {
|
||||
ar->survey_last_rx_clear_count = params->rx_clear_count;
|
||||
ar->survey_last_cycle_count = params->cycle_count;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct chan_info_params ch_info_param;
|
||||
struct wmi_ch_info_ev_arg arg = {};
|
||||
struct survey_info *survey;
|
||||
u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
|
||||
int idx, ret;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_wmi_pull_ch_info(ar, skb, &arg);
|
||||
if (ret) {
|
||||
@ -2567,17 +2644,19 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
|
||||
return;
|
||||
}
|
||||
|
||||
err_code = __le32_to_cpu(arg.err_code);
|
||||
freq = __le32_to_cpu(arg.freq);
|
||||
cmd_flags = __le32_to_cpu(arg.cmd_flags);
|
||||
noise_floor = __le32_to_cpu(arg.noise_floor);
|
||||
rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
|
||||
cycle_count = __le32_to_cpu(arg.cycle_count);
|
||||
ch_info_param.err_code = __le32_to_cpu(arg.err_code);
|
||||
ch_info_param.freq = __le32_to_cpu(arg.freq);
|
||||
ch_info_param.cmd_flags = __le32_to_cpu(arg.cmd_flags);
|
||||
ch_info_param.noise_floor = __le32_to_cpu(arg.noise_floor);
|
||||
ch_info_param.rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
|
||||
ch_info_param.cycle_count = __le32_to_cpu(arg.cycle_count);
|
||||
ch_info_param.mac_clk_mhz = __le32_to_cpu(arg.mac_clk_mhz);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
|
||||
err_code, freq, cmd_flags, noise_floor, rx_clear_count,
|
||||
cycle_count);
|
||||
ch_info_param.err_code, ch_info_param.freq, ch_info_param.cmd_flags,
|
||||
ch_info_param.noise_floor, ch_info_param.rx_clear_count,
|
||||
ch_info_param.cycle_count);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
@ -2591,36 +2670,11 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
|
||||
break;
|
||||
}
|
||||
|
||||
idx = freq_to_idx(ar, freq);
|
||||
if (idx >= ARRAY_SIZE(ar->survey)) {
|
||||
ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
|
||||
freq, idx);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
|
||||
if (ar->ch_info_can_report_survey) {
|
||||
survey = &ar->survey[idx];
|
||||
survey->noise = noise_floor;
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
||||
|
||||
ath10k_hw_fill_survey_time(ar,
|
||||
survey,
|
||||
cycle_count,
|
||||
rx_clear_count,
|
||||
ar->survey_last_cycle_count,
|
||||
ar->survey_last_rx_clear_count);
|
||||
}
|
||||
|
||||
ar->ch_info_can_report_survey = false;
|
||||
} else {
|
||||
ar->ch_info_can_report_survey = true;
|
||||
}
|
||||
|
||||
if (!(cmd_flags & WMI_CHAN_INFO_FLAG_PRE_COMPLETE)) {
|
||||
ar->survey_last_rx_clear_count = rx_clear_count;
|
||||
ar->survey_last_cycle_count = cycle_count;
|
||||
}
|
||||
if (test_bit(ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
ath10k_wmi_event_chan_info_unpaired(ar, &ch_info_param);
|
||||
else
|
||||
ath10k_wmi_event_chan_info_paired(ar, &ch_info_param);
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
@ -4991,6 +4991,7 @@ enum wmi_rate_preamble {
|
||||
#define ATH10K_LEGACY_NUM 12
|
||||
#define ATH10K_GI_NUM 2
|
||||
#define ATH10K_HT_MCS_NUM 32
|
||||
#define ATH10K_RATE_TABLE_NUM 320
|
||||
|
||||
/* Value to disable fixed rate setting */
|
||||
#define WMI_FIXED_RATE_NONE (0xff)
|
||||
@ -6441,6 +6442,14 @@ struct wmi_chan_info_event {
|
||||
__le32 noise_floor;
|
||||
__le32 rx_clear_count;
|
||||
__le32 cycle_count;
|
||||
__le32 chan_tx_pwr_range;
|
||||
__le32 chan_tx_pwr_tp;
|
||||
__le32 rx_frame_count;
|
||||
__le32 my_bss_rx_cycle_count;
|
||||
__le32 rx_11b_mode_data_duration;
|
||||
__le32 tx_frame_cnt;
|
||||
__le32 mac_clk_mhz;
|
||||
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_4_chan_info_event {
|
||||
@ -6669,6 +6678,10 @@ struct wmi_ch_info_ev_arg {
|
||||
__le32 chan_tx_pwr_range;
|
||||
__le32 chan_tx_pwr_tp;
|
||||
__le32 rx_frame_count;
|
||||
__le32 my_bss_rx_cycle_count;
|
||||
__le32 rx_11b_mode_data_duration;
|
||||
__le32 tx_frame_cnt;
|
||||
__le32 mac_clk_mhz;
|
||||
};
|
||||
|
||||
/* From 10.4 firmware, not sure all have the same values. */
|
||||
|
@ -135,7 +135,7 @@ static void ath10k_wow_convert_8023_to_80211
|
||||
&old_hdr_mask->h_proto,
|
||||
sizeof(old_hdr_mask->h_proto));
|
||||
|
||||
/* Caculate new pkt_offset */
|
||||
/* Calculate new pkt_offset */
|
||||
if (old->pkt_offset < ETH_ALEN)
|
||||
new->pkt_offset = old->pkt_offset +
|
||||
offsetof(struct ieee80211_hdr_3addr, addr1);
|
||||
@ -146,7 +146,7 @@ static void ath10k_wow_convert_8023_to_80211
|
||||
else
|
||||
new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN;
|
||||
|
||||
/* Caculate new hdr end offset */
|
||||
/* Calculate new hdr end offset */
|
||||
if (total_len > ETH_HLEN)
|
||||
hdr_80211_end_offset = hdr_len + rfc_len;
|
||||
else if (total_len > offsetof(struct ethhdr, h_proto))
|
||||
|
@ -389,6 +389,7 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
|
||||
if (!ik->valid || ik->key_type != WAPI_CRYPT)
|
||||
break;
|
||||
/* for WAPI, we need to set the delayed group key, continue: */
|
||||
/* fall through */
|
||||
case WPA_PSK_AUTH:
|
||||
case WPA2_PSK_AUTH:
|
||||
case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
|
||||
|
@ -116,7 +116,7 @@ config ATH9K_DFS_CERTIFIED
|
||||
except increase code size.
|
||||
|
||||
config ATH9K_DYNACK
|
||||
bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)"
|
||||
bool "Atheros ath9k ACK timeout estimation algorithm"
|
||||
depends on ATH9K
|
||||
default n
|
||||
---help---
|
||||
|
@ -586,7 +586,7 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
|
||||
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
|
||||
break;
|
||||
}
|
||||
/* else: fall through */
|
||||
/* fall through */
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x7:
|
||||
|
@ -119,7 +119,7 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
aModeRefSel = 2;
|
||||
if (aModeRefSel)
|
||||
break;
|
||||
/* else: fall through */
|
||||
/* fall through */
|
||||
case 1:
|
||||
default:
|
||||
aModeRefSel = 0;
|
||||
|
@ -1055,17 +1055,15 @@ void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
|
||||
static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
|
||||
{
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
u32 new_flags, to_set, to_clear;
|
||||
u32 to_set, to_clear;
|
||||
|
||||
if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))
|
||||
return;
|
||||
|
||||
if (mci->is_2g) {
|
||||
new_flags = MCI_2G_FLAGS;
|
||||
to_clear = MCI_2G_FLAGS_CLEAR_MASK;
|
||||
to_set = MCI_2G_FLAGS_SET_MASK;
|
||||
} else {
|
||||
new_flags = MCI_5G_FLAGS;
|
||||
to_clear = MCI_5G_FLAGS_CLEAR_MASK;
|
||||
to_set = MCI_5G_FLAGS_SET_MASK;
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ struct ath_node {
|
||||
#endif
|
||||
u8 key_idx[4];
|
||||
|
||||
u32 ackto;
|
||||
int ackto;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -29,9 +29,13 @@
|
||||
* ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
|
||||
*
|
||||
*/
|
||||
static inline u32 ath_dynack_ewma(u32 old, u32 new)
|
||||
static inline int ath_dynack_ewma(int old, int new)
|
||||
{
|
||||
return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV;
|
||||
if (old > 0)
|
||||
return (new * (EWMA_DIV - EWMA_LEVEL) +
|
||||
old * EWMA_LEVEL) / EWMA_DIV;
|
||||
else
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,10 +86,10 @@ static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac)
|
||||
*/
|
||||
static void ath_dynack_compute_ackto(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_node *an;
|
||||
u32 to = 0;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
struct ath_node *an;
|
||||
int to = 0;
|
||||
|
||||
list_for_each_entry(an, &da->nodes, list)
|
||||
if (an->ackto > to)
|
||||
@ -144,7 +148,8 @@ static void ath_dynack_compute_to(struct ath_hw *ah)
|
||||
an->ackto = ath_dynack_ewma(an->ackto,
|
||||
ackto);
|
||||
ath_dbg(ath9k_hw_common(ah), DYNACK,
|
||||
"%pM to %u\n", dst, an->ackto);
|
||||
"%pM to %d [%u]\n", dst,
|
||||
an->ackto, ackto);
|
||||
if (time_is_before_jiffies(da->lto)) {
|
||||
ath_dynack_compute_ackto(ah);
|
||||
da->lto = jiffies + COMPUTE_TO;
|
||||
@ -166,18 +171,21 @@ static void ath_dynack_compute_to(struct ath_hw *ah)
|
||||
* @ah: ath hw
|
||||
* @skb: socket buffer
|
||||
* @ts: tx status info
|
||||
* @sta: station pointer
|
||||
*
|
||||
*/
|
||||
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
|
||||
struct ath_tx_status *ts)
|
||||
struct ath_tx_status *ts,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
u8 ridx;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
u32 dur = ts->duration;
|
||||
u8 ridx;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
|
||||
if (!da->enabled || (info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&da->qlock);
|
||||
@ -187,11 +195,19 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
|
||||
/* late ACK */
|
||||
if (ts->ts_status & ATH9K_TXERR_XRETRY) {
|
||||
if (ieee80211_is_assoc_req(hdr->frame_control) ||
|
||||
ieee80211_is_assoc_resp(hdr->frame_control)) {
|
||||
ieee80211_is_assoc_resp(hdr->frame_control) ||
|
||||
ieee80211_is_auth(hdr->frame_control)) {
|
||||
ath_dbg(common, DYNACK, "late ack\n");
|
||||
|
||||
ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
|
||||
ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
|
||||
ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
|
||||
if (sta) {
|
||||
struct ath_node *an;
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
an->ackto = -1;
|
||||
}
|
||||
da->lto = jiffies + LATEACK_DELAY;
|
||||
}
|
||||
|
||||
@ -202,14 +218,13 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
|
||||
ridx = ts->ts_rateindex;
|
||||
|
||||
da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp;
|
||||
da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration;
|
||||
ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1);
|
||||
ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2);
|
||||
|
||||
if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) {
|
||||
u32 phy, sifs;
|
||||
const struct ieee80211_rate *rate;
|
||||
struct ieee80211_tx_rate *rates = info->status.rates;
|
||||
u32 phy;
|
||||
|
||||
rate = &common->sbands[info->band].bitrates[rates[ridx].idx];
|
||||
if (info->band == NL80211_BAND_2GHZ &&
|
||||
@ -218,19 +233,18 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
|
||||
else
|
||||
phy = WLAN_RC_PHY_OFDM;
|
||||
|
||||
sifs = ath_dynack_get_sifs(ah, phy);
|
||||
da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs;
|
||||
dur -= ath_dynack_get_sifs(ah, phy);
|
||||
}
|
||||
|
||||
ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
|
||||
hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp,
|
||||
da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb,
|
||||
(da->st_rbf.t_rb + 1) % ATH_DYN_BUF);
|
||||
da->st_rbf.ts[da->st_rbf.t_rb].dur = dur;
|
||||
|
||||
INCR(da->st_rbf.t_rb, ATH_DYN_BUF);
|
||||
if (da->st_rbf.t_rb == da->st_rbf.h_rb)
|
||||
INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
|
||||
|
||||
ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
|
||||
hdr->addr1, ts->ts_tstamp, dur, da->st_rbf.h_rb,
|
||||
da->st_rbf.t_rb);
|
||||
|
||||
ath_dynack_compute_to(ah);
|
||||
|
||||
spin_unlock_bh(&da->qlock);
|
||||
@ -251,20 +265,19 @@ void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb,
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled)
|
||||
if (!da->enabled || !ath_dynack_bssidmask(ah, hdr->addr1))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&da->qlock);
|
||||
da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts;
|
||||
|
||||
ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
|
||||
da->ack_rbf.tstamp[da->ack_rbf.t_rb],
|
||||
da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF);
|
||||
|
||||
INCR(da->ack_rbf.t_rb, ATH_DYN_BUF);
|
||||
if (da->ack_rbf.t_rb == da->ack_rbf.h_rb)
|
||||
INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
|
||||
|
||||
ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
|
||||
ts, da->ack_rbf.h_rb, da->ack_rbf.t_rb);
|
||||
|
||||
ath_dynack_compute_to(ah);
|
||||
|
||||
spin_unlock_bh(&da->qlock);
|
||||
|
@ -86,7 +86,8 @@ void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an);
|
||||
void ath_dynack_init(struct ath_hw *ah);
|
||||
void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts);
|
||||
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
|
||||
struct ath_tx_status *ts);
|
||||
struct ath_tx_status *ts,
|
||||
struct ieee80211_sta *sta);
|
||||
#else
|
||||
static inline void ath_dynack_init(struct ath_hw *ah) {}
|
||||
static inline void ath_dynack_node_init(struct ath_hw *ah,
|
||||
@ -97,7 +98,8 @@ static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah,
|
||||
struct sk_buff *skb, u32 ts) {}
|
||||
static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah,
|
||||
struct sk_buff *skb,
|
||||
struct ath_tx_status *ts) {}
|
||||
struct ath_tx_status *ts,
|
||||
struct ieee80211_sta *sta) {}
|
||||
#endif
|
||||
|
||||
#endif /* DYNACK_H */
|
||||
|
@ -2279,6 +2279,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
REG_SET_BIT(ah, AR_TXCFG,
|
||||
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_AP:
|
||||
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
|
||||
|
@ -629,7 +629,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
if (bf == bf->bf_lastbf)
|
||||
ath_dynack_sample_tx_ts(sc->sc_ah,
|
||||
bf->bf_mpdu,
|
||||
ts);
|
||||
ts, sta);
|
||||
}
|
||||
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts,
|
||||
@ -773,7 +773,8 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
|
||||
memcpy(info->control.rates, bf->rates,
|
||||
sizeof(info->control.rates));
|
||||
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
|
||||
ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
|
||||
ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts,
|
||||
sta);
|
||||
}
|
||||
ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok);
|
||||
} else
|
||||
|
@ -766,6 +766,7 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)
|
||||
|
||||
goto drop;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case AR9170_RX_STATUS_MPDU_MIDDLE:
|
||||
/* These are just data + mac status */
|
||||
|
@ -830,10 +830,12 @@ static bool carl9170_tx_rts_check(struct ar9170 *ar,
|
||||
case CARL9170_ERP_AUTO:
|
||||
if (ampdu)
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
case CARL9170_ERP_MAC80211:
|
||||
if (!(rate->flags & IEEE80211_TX_RC_USE_RTS_CTS))
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
case CARL9170_ERP_RTS:
|
||||
if (likely(!multi))
|
||||
@ -854,6 +856,7 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar,
|
||||
case CARL9170_ERP_MAC80211:
|
||||
if (!(rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
case CARL9170_ERP_CTS:
|
||||
return true;
|
||||
|
@ -51,6 +51,19 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
|
||||
CHAN60G(4, 0),
|
||||
};
|
||||
|
||||
static void
|
||||
wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len)
|
||||
{
|
||||
kfree(*pdst);
|
||||
*pdst = NULL;
|
||||
*pdst_len = 0;
|
||||
if (src_len > 0) {
|
||||
*pdst = kmemdup(src, src_len, GFP_KERNEL);
|
||||
if (*pdst)
|
||||
*pdst_len = src_len;
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_num_supported_channels(struct wil6210_priv *wil)
|
||||
{
|
||||
int num_channels = ARRAY_SIZE(wil_60ghz_channels);
|
||||
@ -1441,11 +1454,19 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
|
||||
rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
|
||||
params->key, key_usage);
|
||||
if (!rc && !IS_ERR(cs))
|
||||
if (!rc && !IS_ERR(cs)) {
|
||||
/* update local storage used for AP recovery */
|
||||
if (key_usage == WMI_KEY_USE_TX_GROUP && params->key &&
|
||||
params->key_len <= WMI_MAX_KEY_LEN) {
|
||||
vif->gtk_index = key_index;
|
||||
memcpy(vif->gtk, params->key, params->key_len);
|
||||
vif->gtk_len = params->key_len;
|
||||
}
|
||||
/* in FT set crypto will take place upon receiving
|
||||
* WMI_RING_EN_EVENTID event
|
||||
*/
|
||||
wil_set_crypto_rx(key_index, key_usage, cs, params);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1634,6 +1655,14 @@ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
|
||||
u16 len = 0, proberesp_len = 0;
|
||||
u8 *ies = NULL, *proberesp;
|
||||
|
||||
/* update local storage used for AP recovery */
|
||||
wil_memdup_ie(&vif->proberesp, &vif->proberesp_len, bcon->probe_resp,
|
||||
bcon->probe_resp_len);
|
||||
wil_memdup_ie(&vif->proberesp_ies, &vif->proberesp_ies_len,
|
||||
bcon->proberesp_ies, bcon->proberesp_ies_len);
|
||||
wil_memdup_ie(&vif->assocresp_ies, &vif->assocresp_ies_len,
|
||||
bcon->assocresp_ies, bcon->assocresp_ies_len);
|
||||
|
||||
proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
|
||||
bcon->probe_resp_len,
|
||||
&proberesp_len);
|
||||
@ -1735,6 +1764,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
vif->channel = chan;
|
||||
vif->hidden_ssid = hidden_ssid;
|
||||
vif->pbss = pbss;
|
||||
vif->bi = bi;
|
||||
memcpy(vif->ssid, ssid, ssid_len);
|
||||
vif->ssid_len = ssid_len;
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
|
||||
@ -1761,11 +1793,64 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc, i;
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
struct wil6210_vif *vif = wil->vifs[i];
|
||||
struct net_device *ndev;
|
||||
struct cfg80211_beacon_data bcon = {};
|
||||
struct key_params key_params = {};
|
||||
|
||||
if (!vif || vif->ssid_len == 0)
|
||||
continue;
|
||||
|
||||
ndev = vif_to_ndev(vif);
|
||||
bcon.proberesp_ies = vif->proberesp_ies;
|
||||
bcon.assocresp_ies = vif->assocresp_ies;
|
||||
bcon.probe_resp = vif->proberesp;
|
||||
bcon.proberesp_ies_len = vif->proberesp_ies_len;
|
||||
bcon.assocresp_ies_len = vif->assocresp_ies_len;
|
||||
bcon.probe_resp_len = vif->proberesp_len;
|
||||
|
||||
wil_info(wil,
|
||||
"AP (vif %d) recovery: privacy %d, bi %d, channel %d, hidden %d, pbss %d\n",
|
||||
i, vif->privacy, vif->bi, vif->channel,
|
||||
vif->hidden_ssid, vif->pbss);
|
||||
wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
vif->ssid, vif->ssid_len, true);
|
||||
rc = _wil_cfg80211_start_ap(wiphy, ndev,
|
||||
vif->ssid, vif->ssid_len,
|
||||
vif->privacy, vif->bi,
|
||||
vif->channel, &bcon,
|
||||
vif->hidden_ssid, vif->pbss);
|
||||
if (rc) {
|
||||
wil_err(wil, "vif %d recovery failed (%d)\n", i, rc);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!vif->privacy || vif->gtk_len == 0)
|
||||
continue;
|
||||
|
||||
key_params.key = vif->gtk;
|
||||
key_params.key_len = vif->gtk_len;
|
||||
key_params.seq_len = IEEE80211_GCMP_PN_LEN;
|
||||
rc = wil_cfg80211_add_key(wiphy, ndev, vif->gtk_index, false,
|
||||
NULL, &key_params);
|
||||
if (rc)
|
||||
wil_err(wil, "vif %d recovery add key failed (%d)\n",
|
||||
i, rc);
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_beacon_data *bcon)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
int rc;
|
||||
u32 privacy = 0;
|
||||
@ -1778,15 +1863,16 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
bcon->tail_len))
|
||||
privacy = 1;
|
||||
|
||||
memcpy(vif->ssid, wdev->ssid, wdev->ssid_len);
|
||||
vif->ssid_len = wdev->ssid_len;
|
||||
|
||||
/* in case privacy has changed, need to restart the AP */
|
||||
if (vif->privacy != privacy) {
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
|
||||
wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n",
|
||||
vif->privacy, privacy);
|
||||
|
||||
rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid,
|
||||
wdev->ssid_len, privacy,
|
||||
rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid,
|
||||
vif->ssid_len, privacy,
|
||||
wdev->beacon_interval,
|
||||
vif->channel, bcon,
|
||||
vif->hidden_ssid,
|
||||
@ -1876,6 +1962,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
||||
|
||||
wmi_pcp_stop(vif);
|
||||
clear_bit(wil_vif_ft_roam, vif->status);
|
||||
vif->ssid_len = 0;
|
||||
wil_memdup_ie(&vif->proberesp, &vif->proberesp_len, NULL, 0);
|
||||
wil_memdup_ie(&vif->proberesp_ies, &vif->proberesp_ies_len, NULL, 0);
|
||||
wil_memdup_ie(&vif->assocresp_ies, &vif->assocresp_ies_len, NULL, 0);
|
||||
memset(vif->gtk, 0, WMI_MAX_KEY_LEN);
|
||||
vif->gtk_len = 0;
|
||||
|
||||
if (last)
|
||||
__wil_down(wil);
|
||||
@ -1923,7 +2015,7 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
|
||||
params->mac, params->reason_code, vif->mid);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(vif, params->mac, params->reason_code, false);
|
||||
wil6210_disconnect(vif, params->mac, params->reason_code);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
return 0;
|
||||
|
@ -664,10 +664,10 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
||||
enum { max_count = 4096 };
|
||||
struct wil_blob_wrapper *wil_blob = file->private_data;
|
||||
struct wil6210_priv *wil = wil_blob->wil;
|
||||
loff_t pos = *ppos;
|
||||
loff_t aligned_pos, pos = *ppos;
|
||||
size_t available = wil_blob->blob.size;
|
||||
void *buf;
|
||||
size_t ret;
|
||||
size_t unaligned_bytes, aligned_count, ret;
|
||||
int rc;
|
||||
|
||||
if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
|
||||
@ -685,7 +685,12 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
||||
if (count > max_count)
|
||||
count = max_count;
|
||||
|
||||
buf = kmalloc(count, GFP_KERNEL);
|
||||
/* set pos to 4 bytes aligned */
|
||||
unaligned_bytes = pos % 4;
|
||||
aligned_pos = pos - unaligned_bytes;
|
||||
aligned_count = count + unaligned_bytes;
|
||||
|
||||
buf = kmalloc(aligned_count, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -696,9 +701,9 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
||||
}
|
||||
|
||||
wil_memcpy_fromio_32(buf, (const void __iomem *)
|
||||
wil_blob->blob.data + pos, count);
|
||||
wil_blob->blob.data + aligned_pos, aligned_count);
|
||||
|
||||
ret = copy_to_user(user_buf, buf, count);
|
||||
ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
@ -962,6 +967,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
||||
int rc;
|
||||
void *frame;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
if (!len)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
@ -80,7 +81,7 @@ static const struct kernel_param_ops mtu_max_ops = {
|
||||
module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
|
||||
MODULE_PARM_DESC(mtu_max, " Max MTU value.");
|
||||
|
||||
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
|
||||
static uint rx_ring_order;
|
||||
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
|
||||
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
|
||||
|
||||
@ -214,8 +215,21 @@ static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
|
||||
wil->txrx_ops.ring_fini_tx(wil, ring);
|
||||
}
|
||||
|
||||
static void wil_disconnect_cid(struct wil6210_vif *vif, int cid,
|
||||
u16 reason_code, bool from_event)
|
||||
static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WIL6210_MAX_CID; i++) {
|
||||
if (wil->sta[i].mid == mid &&
|
||||
wil->sta[i].status == wil_sta_connected)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wil_disconnect_cid_complete(struct wil6210_vif *vif, int cid,
|
||||
u16 reason_code)
|
||||
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
{
|
||||
uint i;
|
||||
@ -226,24 +240,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
int min_ring_id = wil_get_min_tx_ring_id(wil);
|
||||
|
||||
might_sleep();
|
||||
wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
|
||||
wil_dbg_misc(wil,
|
||||
"disconnect_cid_complete: CID %d, MID %d, status %d\n",
|
||||
cid, sta->mid, sta->status);
|
||||
/* inform upper/lower layers */
|
||||
/* inform upper layers */
|
||||
if (sta->status != wil_sta_unused) {
|
||||
if (vif->mid != sta->mid) {
|
||||
wil_err(wil, "STA MID mismatch with VIF MID(%d)\n",
|
||||
vif->mid);
|
||||
/* let FW override sta->mid but be more strict with
|
||||
* user space requests
|
||||
*/
|
||||
if (!from_event)
|
||||
return;
|
||||
}
|
||||
if (!from_event) {
|
||||
bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
|
||||
disable_ap_sme : false;
|
||||
wmi_disconnect_sta(vif, sta->addr, reason_code,
|
||||
true, del_sta);
|
||||
}
|
||||
|
||||
switch (wdev->iftype) {
|
||||
@ -283,36 +287,20 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
sta->stats.tx_latency_min_us = U32_MAX;
|
||||
}
|
||||
|
||||
static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if (wil->sta[i].mid == mid &&
|
||||
wil->sta[i].status == wil_sta_connected)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code, bool from_event)
|
||||
static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
|
||||
const u8 *bssid, u16 reason_code)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int cid = -ENOENT;
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
if (unlikely(!vif))
|
||||
return;
|
||||
|
||||
ndev = vif_to_ndev(vif);
|
||||
wdev = vif_to_wdev(vif);
|
||||
|
||||
might_sleep();
|
||||
wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
|
||||
reason_code, from_event ? "+" : "-");
|
||||
wil_info(wil, "disconnect_complete: bssid=%pM, reason=%d\n",
|
||||
bssid, reason_code);
|
||||
|
||||
/* Cases are:
|
||||
* - disconnect single STA, still connected
|
||||
@ -327,14 +315,15 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
if (bssid && !is_broadcast_ether_addr(bssid) &&
|
||||
!ether_addr_equal_unaligned(ndev->dev_addr, bssid)) {
|
||||
cid = wil_find_cid(wil, vif->mid, bssid);
|
||||
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
|
||||
wil_dbg_misc(wil,
|
||||
"Disconnect complete %pM, CID=%d, reason=%d\n",
|
||||
bssid, cid, reason_code);
|
||||
if (cid >= 0) /* disconnect 1 peer */
|
||||
wil_disconnect_cid(vif, cid, reason_code, from_event);
|
||||
wil_disconnect_cid_complete(vif, cid, reason_code);
|
||||
} else { /* all */
|
||||
wil_dbg_misc(wil, "Disconnect all\n");
|
||||
wil_dbg_misc(wil, "Disconnect complete all\n");
|
||||
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
|
||||
wil_disconnect_cid(vif, cid, reason_code, from_event);
|
||||
wil_disconnect_cid_complete(vif, cid, reason_code);
|
||||
}
|
||||
|
||||
/* link state */
|
||||
@ -380,6 +369,84 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_disconnect_cid(struct wil6210_vif *vif, int cid,
|
||||
u16 reason_code)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
bool del_sta = false;
|
||||
|
||||
might_sleep();
|
||||
wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
|
||||
cid, sta->mid, sta->status);
|
||||
|
||||
if (sta->status == wil_sta_unused)
|
||||
return 0;
|
||||
|
||||
if (vif->mid != sta->mid) {
|
||||
wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", vif->mid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* inform lower layers */
|
||||
if (wdev->iftype == NL80211_IFTYPE_AP && disable_ap_sme)
|
||||
del_sta = true;
|
||||
|
||||
/* disconnect by sending command disconnect/del_sta and wait
|
||||
* synchronously for WMI_DISCONNECT_EVENTID event.
|
||||
*/
|
||||
return wmi_disconnect_sta(vif, sta->addr, reason_code, del_sta);
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code)
|
||||
{
|
||||
struct wil6210_priv *wil;
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
int cid = -ENOENT;
|
||||
|
||||
if (unlikely(!vif))
|
||||
return;
|
||||
|
||||
wil = vif_to_wil(vif);
|
||||
ndev = vif_to_ndev(vif);
|
||||
wdev = vif_to_wdev(vif);
|
||||
|
||||
might_sleep();
|
||||
wil_info(wil, "disconnect bssid=%pM, reason=%d\n", bssid, reason_code);
|
||||
|
||||
/* Cases are:
|
||||
* - disconnect single STA, still connected
|
||||
* - disconnect single STA, already disconnected
|
||||
* - disconnect all
|
||||
*
|
||||
* 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 && !is_broadcast_ether_addr(bssid) &&
|
||||
!ether_addr_equal_unaligned(ndev->dev_addr, bssid)) {
|
||||
cid = wil_find_cid(wil, vif->mid, bssid);
|
||||
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
|
||||
bssid, cid, reason_code);
|
||||
if (cid >= 0) /* disconnect 1 peer */
|
||||
wil_disconnect_cid(vif, cid, reason_code);
|
||||
} else { /* all */
|
||||
wil_dbg_misc(wil, "Disconnect all\n");
|
||||
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
|
||||
wil_disconnect_cid(vif, cid, reason_code);
|
||||
}
|
||||
|
||||
/* call event handler manually after processing wmi_call,
|
||||
* to avoid deadlock - disconnect event handler acquires
|
||||
* wil->mutex while it is already held here
|
||||
*/
|
||||
_wil6210_disconnect_complete(vif, bssid, reason_code);
|
||||
}
|
||||
|
||||
void wil_disconnect_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_vif *vif = container_of(work,
|
||||
@ -485,10 +552,11 @@ static void wil_fw_error_worker(struct work_struct *work)
|
||||
if (wil_wait_for_recovery(wil) != 0)
|
||||
return;
|
||||
|
||||
rtnl_lock();
|
||||
mutex_lock(&wil->mutex);
|
||||
/* Needs adaptation for multiple VIFs
|
||||
* need to go over all VIFs and consider the appropriate
|
||||
* recovery.
|
||||
* recovery because each one can have different iftype.
|
||||
*/
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@ -500,15 +568,24 @@ static void wil_fw_error_worker(struct work_struct *work)
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
wil_info(wil, "No recovery for AP-like interface\n");
|
||||
/* recovery in these modes is done by upper layers */
|
||||
if (no_fw_recovery) /* upper layers do recovery */
|
||||
break;
|
||||
/* silent recovery, upper layers will see disconnect */
|
||||
__wil_down(wil);
|
||||
__wil_up(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
wil_cfg80211_ap_recovery(wil);
|
||||
mutex_lock(&wil->mutex);
|
||||
wil_info(wil, "... completed\n");
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "No recovery - unknown interface type %d\n",
|
||||
wdev->iftype);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static int wil_find_free_ring(struct wil6210_priv *wil)
|
||||
@ -694,20 +771,41 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
|
||||
* @vif: virtual interface context
|
||||
* @bssid: peer to disconnect, NULL to disconnect all
|
||||
* @reason_code: Reason code for the Disassociation frame
|
||||
* @from_event: whether is invoked from FW event handler
|
||||
*
|
||||
* Disconnect and release associated resources. If invoked not from the
|
||||
* FW event handler, issue WMI command(s) to trigger MAC disconnect.
|
||||
* Disconnect and release associated resources. Issue WMI
|
||||
* command(s) to trigger MAC disconnect. When command was issued
|
||||
* successfully, call the wil6210_disconnect_complete function
|
||||
* to handle the event synchronously
|
||||
*/
|
||||
void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code, bool from_event)
|
||||
u16 reason_code)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
|
||||
wil_dbg_misc(wil, "disconnect\n");
|
||||
wil_dbg_misc(wil, "disconnecting\n");
|
||||
|
||||
del_timer_sync(&vif->connect_timer);
|
||||
_wil6210_disconnect(vif, bssid, reason_code, from_event);
|
||||
_wil6210_disconnect(vif, bssid, reason_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* wil6210_disconnect_complete - handle disconnect event
|
||||
* @vif: virtual interface context
|
||||
* @bssid: peer to disconnect, NULL to disconnect all
|
||||
* @reason_code: Reason code for the Disassociation frame
|
||||
*
|
||||
* Release associated resources and indicate upper layers the
|
||||
* connection is terminated.
|
||||
*/
|
||||
void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
|
||||
wil_dbg_misc(wil, "got disconnect\n");
|
||||
|
||||
del_timer_sync(&vif->connect_timer);
|
||||
_wil6210_disconnect_complete(vif, bssid, reason_code);
|
||||
}
|
||||
|
||||
void wil_priv_deinit(struct wil6210_priv *wil)
|
||||
@ -998,10 +1096,13 @@ static int wil_target_reset(struct wil6210_priv *wil, int no_flash)
|
||||
|
||||
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
|
||||
|
||||
/* Clear MAC link up */
|
||||
wil_s(wil, RGF_HP_CTRL, BIT(15));
|
||||
wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
|
||||
wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
|
||||
if (wil->hw_version < HW_VER_TALYN) {
|
||||
/* Clear MAC link up */
|
||||
wil_s(wil, RGF_HP_CTRL, BIT(15));
|
||||
wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0,
|
||||
BIT_HPAL_PERST_FROM_PAD);
|
||||
wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
|
||||
}
|
||||
|
||||
wil_halt_cpu(wil);
|
||||
|
||||
@ -1398,8 +1499,15 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
|
||||
wil6210_clear_irq(wil);
|
||||
/* CAF_ICR - clear and mask */
|
||||
/* it is W1C, clear by writing back same value */
|
||||
wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
|
||||
wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
|
||||
if (wil->hw_version < HW_VER_TALYN_MB) {
|
||||
wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
|
||||
wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
|
||||
} else {
|
||||
wil_s(wil,
|
||||
RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0);
|
||||
wil_w(wil, RGF_CAF_ICR_TALYN_MB +
|
||||
offsetof(struct RGF_ICR, IMV), ~0);
|
||||
}
|
||||
/* clear PAL_UNIT_ICR (potential D0->D3 leftover)
|
||||
* In Talyn-MB host cannot access this register due to
|
||||
* access control, hence PAL_UNIT_ICR is cleared by the FW
|
||||
@ -1511,7 +1619,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
if (vif) {
|
||||
cancel_work_sync(&vif->disconnect_worker);
|
||||
wil6210_disconnect(vif, NULL,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
WLAN_REASON_DEAUTH_LEAVING);
|
||||
}
|
||||
}
|
||||
wil_bcast_fini_all(wil);
|
||||
@ -1681,7 +1789,12 @@ int __wil_up(struct wil6210_priv *wil)
|
||||
return rc;
|
||||
|
||||
/* Rx RING. After MAC and beacon */
|
||||
rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order);
|
||||
if (rx_ring_order == 0)
|
||||
rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ?
|
||||
WIL_RX_RING_SIZE_ORDER_DEFAULT :
|
||||
WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT;
|
||||
|
||||
rc = wil->txrx_ops.rx_init(wil, rx_ring_order);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -345,8 +345,7 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name,
|
||||
ndev->ieee80211_ptr = wdev;
|
||||
ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
|
||||
NETIF_F_SG | NETIF_F_GRO |
|
||||
NETIF_F_TSO | NETIF_F_TSO6 |
|
||||
NETIF_F_RXHASH;
|
||||
NETIF_F_TSO | NETIF_F_TSO6;
|
||||
|
||||
ndev->features |= ndev->hw_features;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
||||
@ -513,7 +512,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
|
||||
}
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
ndev = vif_to_ndev(vif);
|
||||
|
@ -743,14 +743,6 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
if (ndev->features & NETIF_F_RXHASH)
|
||||
/* fake L4 to ensure it won't be re-calculated later
|
||||
* set hash to any non-zero value to activate rps
|
||||
* mechanism, core will be chosen according
|
||||
* to user-level rps configuration.
|
||||
*/
|
||||
skb_set_hash(skb, 1, PKT_HASH_TYPE_L4);
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) {
|
||||
@ -880,7 +872,7 @@ static void wil_rx_buf_len_init(struct wil6210_priv *wil)
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_rx_init(struct wil6210_priv *wil, u16 size)
|
||||
static int wil_rx_init(struct wil6210_priv *wil, uint order)
|
||||
{
|
||||
struct wil_ring *vring = &wil->ring_rx;
|
||||
int rc;
|
||||
@ -894,7 +886,7 @@ static int wil_rx_init(struct wil6210_priv *wil, u16 size)
|
||||
|
||||
wil_rx_buf_len_init(wil);
|
||||
|
||||
vring->size = size;
|
||||
vring->size = 1 << order;
|
||||
vring->is_rx = true;
|
||||
rc = wil_vring_alloc(wil, vring);
|
||||
if (rc)
|
||||
@ -1403,6 +1395,8 @@ found:
|
||||
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
|
||||
wil_set_da_for_vring(wil, skb2, i);
|
||||
wil_tx_ring(wil, vif, v2, skb2);
|
||||
/* successful call to wil_tx_ring takes skb2 ref */
|
||||
dev_kfree_skb_any(skb2);
|
||||
} else {
|
||||
wil_err(wil, "skb_copy failed\n");
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
|
||||
struct wil_ring *ring, u32 i)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
unsigned int sz = ALIGN(wil->rx_buf_len, 4);
|
||||
unsigned int sz = wil->rx_buf_len;
|
||||
dma_addr_t pa;
|
||||
u16 buff_id;
|
||||
struct list_head *active = &wil->rx_buff_mgmt.active;
|
||||
@ -234,9 +234,10 @@ static int wil_rx_refill_edma(struct wil6210_priv *wil)
|
||||
struct wil_ring *ring = &wil->ring_rx;
|
||||
u32 next_head;
|
||||
int rc = 0;
|
||||
u32 swtail = *ring->edma_rx_swtail.va;
|
||||
ring->swtail = *ring->edma_rx_swtail.va;
|
||||
|
||||
for (; next_head = wil_ring_next_head(ring), (next_head != swtail);
|
||||
for (; next_head = wil_ring_next_head(ring),
|
||||
(next_head != ring->swtail);
|
||||
ring->swhead = next_head) {
|
||||
rc = wil_ring_alloc_skb_edma(wil, ring, ring->swhead);
|
||||
if (unlikely(rc)) {
|
||||
@ -264,43 +265,26 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
|
||||
struct wil_ring *ring)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
u32 next_tail;
|
||||
u32 swhead = (ring->swhead + 1) % ring->size;
|
||||
struct list_head *active = &wil->rx_buff_mgmt.active;
|
||||
dma_addr_t pa;
|
||||
u16 dmalen;
|
||||
|
||||
for (; next_tail = wil_ring_next_tail(ring), (next_tail != swhead);
|
||||
ring->swtail = next_tail) {
|
||||
struct wil_rx_enhanced_desc dd, *d = ⅆ
|
||||
struct wil_rx_enhanced_desc *_d =
|
||||
(struct wil_rx_enhanced_desc *)
|
||||
&ring->va[ring->swtail].rx.enhanced;
|
||||
struct sk_buff *skb;
|
||||
u16 buff_id;
|
||||
while (!list_empty(active)) {
|
||||
struct wil_rx_buff *rx_buff =
|
||||
list_first_entry(active, struct wil_rx_buff, list);
|
||||
struct sk_buff *skb = rx_buff->skb;
|
||||
|
||||
*d = *_d;
|
||||
|
||||
/* Extract the SKB from the rx_buff management array */
|
||||
buff_id = __le16_to_cpu(d->mac.buff_id);
|
||||
if (buff_id >= wil->rx_buff_mgmt.size) {
|
||||
wil_err(wil, "invalid buff_id %d\n", buff_id);
|
||||
continue;
|
||||
}
|
||||
skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
|
||||
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
|
||||
if (unlikely(!skb)) {
|
||||
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
|
||||
wil_err(wil, "No Rx skb at buff_id %d\n", rx_buff->id);
|
||||
} else {
|
||||
pa = wil_rx_desc_get_addr_edma(&d->dma);
|
||||
dmalen = le16_to_cpu(d->dma.length);
|
||||
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
|
||||
|
||||
rx_buff->skb = NULL;
|
||||
memcpy(&pa, skb->cb, sizeof(pa));
|
||||
dma_unmap_single(dev, pa, wil->rx_buf_len,
|
||||
DMA_FROM_DEVICE);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* Move the buffer from the active to the free list */
|
||||
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
|
||||
&wil->rx_buff_mgmt.free);
|
||||
list_move(&rx_buff->list, &wil->rx_buff_mgmt.free);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,8 +341,8 @@ static int wil_init_rx_sring(struct wil6210_priv *wil,
|
||||
struct wil_status_ring *sring = &wil->srings[ring_id];
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", sring->size,
|
||||
ring_id);
|
||||
wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n",
|
||||
status_ring_size, ring_id);
|
||||
|
||||
memset(&sring->rx_data, 0, sizeof(sring->rx_data));
|
||||
|
||||
@ -602,20 +586,20 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil)
|
||||
|
||||
static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil)
|
||||
{
|
||||
/* RX buffer size must be aligned to 4 bytes */
|
||||
wil->rx_buf_len = rx_large_buf ?
|
||||
WIL_MAX_ETH_MTU : WIL_EDMA_RX_BUF_LEN_DEFAULT;
|
||||
}
|
||||
|
||||
static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
|
||||
static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
|
||||
{
|
||||
u16 status_ring_size;
|
||||
u16 status_ring_size, desc_ring_size = 1 << desc_ring_order;
|
||||
struct wil_ring *ring = &wil->ring_rx;
|
||||
int rc;
|
||||
size_t elem_size = wil->use_compressed_rx_status ?
|
||||
sizeof(struct wil_rx_status_compressed) :
|
||||
sizeof(struct wil_rx_status_extended);
|
||||
int i;
|
||||
u16 max_rx_pl_per_desc;
|
||||
|
||||
/* In SW reorder one must use extended status messages */
|
||||
if (wil->use_compressed_rx_status && !wil->use_rx_hw_reordering) {
|
||||
@ -623,7 +607,12 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
|
||||
"compressed RX status cannot be used with SW reorder\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wil->rx_status_ring_order <= desc_ring_order)
|
||||
/* make sure sring is larger than desc ring */
|
||||
wil->rx_status_ring_order = desc_ring_order + 1;
|
||||
if (wil->rx_buff_id_count <= desc_ring_size)
|
||||
/* make sure we will not run out of buff_ids */
|
||||
wil->rx_buff_id_count = desc_ring_size + 512;
|
||||
if (wil->rx_status_ring_order < WIL_SRING_SIZE_ORDER_MIN ||
|
||||
wil->rx_status_ring_order > WIL_SRING_SIZE_ORDER_MAX)
|
||||
wil->rx_status_ring_order = WIL_RX_SRING_SIZE_ORDER_DEFAULT;
|
||||
@ -636,8 +625,6 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
|
||||
|
||||
wil_rx_buf_len_init_edma(wil);
|
||||
|
||||
max_rx_pl_per_desc = ALIGN(wil->rx_buf_len, 4);
|
||||
|
||||
/* Use debugfs dbg_num_rx_srings if set, reserve one sring for TX */
|
||||
if (wil->num_rx_status_rings > WIL6210_MAX_STATUS_RINGS - 1)
|
||||
wil->num_rx_status_rings = WIL6210_MAX_STATUS_RINGS - 1;
|
||||
@ -645,7 +632,7 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
|
||||
wil_dbg_misc(wil, "rx_init: allocate %d status rings\n",
|
||||
wil->num_rx_status_rings);
|
||||
|
||||
rc = wil_wmi_cfg_def_rx_offload(wil, max_rx_pl_per_desc);
|
||||
rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -834,23 +821,24 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
|
||||
wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n",
|
||||
l2_rx_status);
|
||||
/* Due to HW issue, KEY error will trigger a MIC error */
|
||||
if (l2_rx_status & WIL_RX_EDMA_ERROR_MIC) {
|
||||
wil_dbg_txrx(wil,
|
||||
"L2 MIC/KEY error, dropping packet\n");
|
||||
if (l2_rx_status == WIL_RX_EDMA_ERROR_MIC) {
|
||||
wil_err_ratelimited(wil,
|
||||
"L2 MIC/KEY error, dropping packet\n");
|
||||
stats->rx_mic_error++;
|
||||
}
|
||||
if (l2_rx_status & WIL_RX_EDMA_ERROR_KEY) {
|
||||
wil_dbg_txrx(wil, "L2 KEY error, dropping packet\n");
|
||||
if (l2_rx_status == WIL_RX_EDMA_ERROR_KEY) {
|
||||
wil_err_ratelimited(wil,
|
||||
"L2 KEY error, dropping packet\n");
|
||||
stats->rx_key_error++;
|
||||
}
|
||||
if (l2_rx_status & WIL_RX_EDMA_ERROR_REPLAY) {
|
||||
wil_dbg_txrx(wil,
|
||||
"L2 REPLAY error, dropping packet\n");
|
||||
if (l2_rx_status == WIL_RX_EDMA_ERROR_REPLAY) {
|
||||
wil_err_ratelimited(wil,
|
||||
"L2 REPLAY error, dropping packet\n");
|
||||
stats->rx_replay++;
|
||||
}
|
||||
if (l2_rx_status & WIL_RX_EDMA_ERROR_AMSDU) {
|
||||
wil_dbg_txrx(wil,
|
||||
"L2 AMSDU error, dropping packet\n");
|
||||
if (l2_rx_status == WIL_RX_EDMA_ERROR_AMSDU) {
|
||||
wil_err_ratelimited(wil,
|
||||
"L2 AMSDU error, dropping packet\n");
|
||||
stats->rx_amsdu_error++;
|
||||
}
|
||||
return -EFAULT;
|
||||
@ -881,7 +869,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t pa;
|
||||
struct wil_ring_rx_data *rxdata = &sring->rx_data;
|
||||
unsigned int sz = ALIGN(wil->rx_buf_len, 4);
|
||||
unsigned int sz = wil->rx_buf_len;
|
||||
struct wil_net_stats *stats = NULL;
|
||||
u16 dmalen;
|
||||
int cid;
|
||||
|
@ -23,9 +23,9 @@
|
||||
#define WIL_SRING_SIZE_ORDER_MIN (WIL_RING_SIZE_ORDER_MIN)
|
||||
#define WIL_SRING_SIZE_ORDER_MAX (WIL_RING_SIZE_ORDER_MAX)
|
||||
/* RX sring order should be bigger than RX ring order */
|
||||
#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (11)
|
||||
#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (12)
|
||||
#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (12)
|
||||
#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (1536)
|
||||
#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600)
|
||||
|
||||
#define WIL_DEFAULT_RX_STATUS_RING_ID 0
|
||||
#define WIL_RX_DESC_RING_ID 0
|
||||
|
@ -81,6 +81,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
|
||||
|
||||
#define WIL_TX_Q_LEN_DEFAULT (4000)
|
||||
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
|
||||
#define WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT (11)
|
||||
#define WIL_TX_RING_SIZE_ORDER_DEFAULT (12)
|
||||
#define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7)
|
||||
#define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */
|
||||
@ -319,6 +320,7 @@ struct RGF_ICR {
|
||||
/* MAC timer, usec, for packet lifetime */
|
||||
#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
|
||||
|
||||
#define RGF_CAF_ICR_TALYN_MB (0x8893d4) /* struct RGF_ICR */
|
||||
#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */
|
||||
#define RGF_CAF_OSC_CONTROL (0x88afa4)
|
||||
#define BIT_CAF_OSC_XTAL_EN BIT(0)
|
||||
@ -613,7 +615,7 @@ struct wil_txrx_ops {
|
||||
int cid, int tid);
|
||||
irqreturn_t (*irq_tx)(int irq, void *cookie);
|
||||
/* RX ops */
|
||||
int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
|
||||
int (*rx_init)(struct wil6210_priv *wil, uint ring_order);
|
||||
void (*rx_fini)(struct wil6210_priv *wil);
|
||||
int (*wmi_addba_rx_resp)(struct wil6210_priv *wil, u8 mid, u8 cid,
|
||||
u8 tid, u8 token, u16 status, bool amsdu,
|
||||
@ -848,6 +850,14 @@ struct wil6210_vif {
|
||||
u8 hidden_ssid; /* relevant in AP mode */
|
||||
u32 ap_isolate; /* no intra-BSS communication */
|
||||
bool pbss;
|
||||
int bi;
|
||||
u8 *proberesp, *proberesp_ies, *assocresp_ies;
|
||||
size_t proberesp_len, proberesp_ies_len, assocresp_ies_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t ssid_len;
|
||||
u8 gtk_index;
|
||||
u8 gtk[WMI_MAX_KEY_LEN];
|
||||
size_t gtk_len;
|
||||
int bcast_ring;
|
||||
struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
|
||||
int locally_generated_disc; /* relevant in STA mode */
|
||||
@ -1220,8 +1230,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring);
|
||||
int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie);
|
||||
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
||||
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
||||
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
|
||||
u16 reason, bool full_disconnect, bool del_sta);
|
||||
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason,
|
||||
bool del_sta);
|
||||
int wmi_addba(struct wil6210_priv *wil, u8 mid,
|
||||
u8 ringid, u8 size, u16 timeout);
|
||||
int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason);
|
||||
@ -1276,6 +1286,7 @@ int wmi_stop_discovery(struct wil6210_vif *vif);
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie);
|
||||
void wil_cfg80211_ap_recovery(struct wil6210_priv *wil);
|
||||
int wil_cfg80211_iface_combinations_from_fw(
|
||||
struct wil6210_priv *wil,
|
||||
const struct wil_fw_record_concurrency *conc);
|
||||
@ -1306,7 +1317,9 @@ void wil_abort_scan(struct wil6210_vif *vif, bool sync);
|
||||
void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync);
|
||||
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps);
|
||||
void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code, bool from_event);
|
||||
u16 reason_code);
|
||||
void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code);
|
||||
void wil_probe_client_flush(struct wil6210_vif *vif);
|
||||
void wil_probe_client_worker(struct work_struct *work);
|
||||
void wil_disconnect_worker(struct work_struct *work);
|
||||
|
@ -1018,7 +1018,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
|
||||
evt->cid, rc);
|
||||
wmi_disconnect_sta(vif, wil->sta[evt->cid].addr,
|
||||
WLAN_REASON_UNSPECIFIED, false, false);
|
||||
WLAN_REASON_UNSPECIFIED, false);
|
||||
} else {
|
||||
wil_info(wil, "successful connection to CID %d\n", evt->cid);
|
||||
}
|
||||
@ -1112,7 +1112,24 @@ static void wmi_evt_disconnect(struct wil6210_vif *vif, int id,
|
||||
}
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(vif, evt->bssid, reason_code, true);
|
||||
wil6210_disconnect_complete(vif, evt->bssid, reason_code);
|
||||
if (disable_ap_sme) {
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
|
||||
/* disconnect event in disable_ap_sme mode means link loss */
|
||||
switch (wdev->iftype) {
|
||||
/* AP-like interface */
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
/* notify hostapd about link loss */
|
||||
cfg80211_cqm_pktloss_notify(ndev, evt->bssid, 0,
|
||||
GFP_KERNEL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&wil->mutex);
|
||||
}
|
||||
|
||||
@ -1637,7 +1654,7 @@ wmi_evt_auth_status(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
return;
|
||||
|
||||
fail:
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1766,7 +1783,7 @@ wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
return;
|
||||
|
||||
fail:
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1949,16 +1966,17 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
|
||||
{
|
||||
int rc;
|
||||
unsigned long remain;
|
||||
ulong flags;
|
||||
|
||||
mutex_lock(&wil->wmi_mutex);
|
||||
|
||||
spin_lock(&wil->wmi_ev_lock);
|
||||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||
wil->reply_id = reply_id;
|
||||
wil->reply_mid = mid;
|
||||
wil->reply_buf = reply;
|
||||
wil->reply_size = reply_size;
|
||||
reinit_completion(&wil->wmi_call);
|
||||
spin_unlock(&wil->wmi_ev_lock);
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
|
||||
rc = __wmi_send(wil, cmdid, mid, buf, len);
|
||||
if (rc)
|
||||
@ -1978,12 +1996,12 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
|
||||
}
|
||||
|
||||
out:
|
||||
spin_lock(&wil->wmi_ev_lock);
|
||||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||
wil->reply_id = 0;
|
||||
wil->reply_mid = U8_MAX;
|
||||
wil->reply_buf = NULL;
|
||||
wil->reply_size = 0;
|
||||
spin_unlock(&wil->wmi_ev_lock);
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
|
||||
mutex_unlock(&wil->wmi_mutex);
|
||||
|
||||
@ -2560,12 +2578,11 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
|
||||
u16 reason, bool full_disconnect, bool del_sta)
|
||||
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason,
|
||||
bool del_sta)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
u16 reason_code;
|
||||
struct wmi_disconnect_sta_cmd disc_sta_cmd = {
|
||||
.disconnect_reason = cpu_to_le16(reason),
|
||||
};
|
||||
@ -2598,21 +2615,8 @@ int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
|
||||
wil_fw_error_recovery(wil);
|
||||
return rc;
|
||||
}
|
||||
wil->sinfo_gen++;
|
||||
|
||||
if (full_disconnect) {
|
||||
/* call event handler manually after processing wmi_call,
|
||||
* to avoid deadlock - disconnect event handler acquires
|
||||
* wil->mutex while it is already held here
|
||||
*/
|
||||
reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
|
||||
|
||||
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
|
||||
reply.evt.bssid, reason_code,
|
||||
reply.evt.disconnect_reason);
|
||||
|
||||
wil->sinfo_gen++;
|
||||
wil6210_disconnect(vif, reply.evt.bssid, reason_code, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3145,7 +3149,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
|
||||
|
||||
if (mid == MID_BROADCAST)
|
||||
mid = 0;
|
||||
if (mid >= wil->max_vifs) {
|
||||
if (mid >= ARRAY_SIZE(wil->vifs) || mid >= wil->max_vifs) {
|
||||
wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
|
||||
mid);
|
||||
return;
|
||||
|
Loading…
x
Reference in New Issue
Block a user