mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for v5.6. Major changes: ath11k * a new driver for Qualcomm Wi-Fi 6 (IEEE 802.11ax) devices ath10k * significant improvements on receive throughput and firmware download with SDIO bus * report signal strength for each chain also on SDIO * set max mtu to 1500 on SDIO devices
This commit is contained in:
273
Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
Normal file
273
Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
Normal file
@@ -0,0 +1,273 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/wireless/qcom,ath11k.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies ath11k wireless devices Generic Binding
|
||||
|
||||
maintainers:
|
||||
- Kalle Valo <kvalo@codeaurora.org>
|
||||
|
||||
description: |
|
||||
These are dt entries for Qualcomm Technologies, Inc. IEEE 802.11ax
|
||||
devices, for example like AHB based IPQ8074.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,ipq8074-wifi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: misc-pulse1 interrupt events
|
||||
- description: misc-latch interrupt events
|
||||
- description: sw exception interrupt events
|
||||
- description: watchdog interrupt events
|
||||
- description: interrupt event for ring CE0
|
||||
- description: interrupt event for ring CE1
|
||||
- description: interrupt event for ring CE2
|
||||
- description: interrupt event for ring CE3
|
||||
- description: interrupt event for ring CE4
|
||||
- description: interrupt event for ring CE5
|
||||
- description: interrupt event for ring CE6
|
||||
- description: interrupt event for ring CE7
|
||||
- description: interrupt event for ring CE8
|
||||
- description: interrupt event for ring CE9
|
||||
- description: interrupt event for ring CE10
|
||||
- description: interrupt event for ring CE11
|
||||
- description: interrupt event for ring host2wbm-desc-feed
|
||||
- description: interrupt event for ring host2reo-re-injection
|
||||
- description: interrupt event for ring host2reo-command
|
||||
- description: interrupt event for ring host2rxdma-monitor-ring3
|
||||
- description: interrupt event for ring host2rxdma-monitor-ring2
|
||||
- description: interrupt event for ring host2rxdma-monitor-ring1
|
||||
- description: interrupt event for ring reo2ost-exception
|
||||
- description: interrupt event for ring wbm2host-rx-release
|
||||
- description: interrupt event for ring reo2host-status
|
||||
- description: interrupt event for ring reo2host-destination-ring4
|
||||
- description: interrupt event for ring reo2host-destination-ring3
|
||||
- description: interrupt event for ring reo2host-destination-ring2
|
||||
- description: interrupt event for ring reo2host-destination-ring1
|
||||
- description: interrupt event for ring rxdma2host-monitor-destination-mac3
|
||||
- description: interrupt event for ring rxdma2host-monitor-destination-mac2
|
||||
- description: interrupt event for ring rxdma2host-monitor-destination-mac1
|
||||
- description: interrupt event for ring ppdu-end-interrupts-mac3
|
||||
- description: interrupt event for ring ppdu-end-interrupts-mac2
|
||||
- description: interrupt event for ring ppdu-end-interrupts-mac1
|
||||
- description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
|
||||
- description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
|
||||
- description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
|
||||
- description: interrupt event for ring host2rxdma-host-buf-ring-mac3
|
||||
- description: interrupt event for ring host2rxdma-host-buf-ring-mac2
|
||||
- description: interrupt event for ring host2rxdma-host-buf-ring-mac1
|
||||
- description: interrupt event for ring rxdma2host-destination-ring-mac3
|
||||
- description: interrupt event for ring rxdma2host-destination-ring-mac2
|
||||
- description: interrupt event for ring rxdma2host-destination-ring-mac1
|
||||
- description: interrupt event for ring host2tcl-input-ring4
|
||||
- description: interrupt event for ring host2tcl-input-ring3
|
||||
- description: interrupt event for ring host2tcl-input-ring2
|
||||
- description: interrupt event for ring host2tcl-input-ring1
|
||||
- description: interrupt event for ring wbm2host-tx-completions-ring3
|
||||
- description: interrupt event for ring wbm2host-tx-completions-ring2
|
||||
- description: interrupt event for ring wbm2host-tx-completions-ring1
|
||||
- description: interrupt event for ring tcl2host-status-ring
|
||||
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: misc-pulse1
|
||||
- const: misc-latch
|
||||
- const: sw-exception
|
||||
- const: watchdog
|
||||
- const: ce0
|
||||
- const: ce1
|
||||
- const: ce2
|
||||
- const: ce3
|
||||
- const: ce4
|
||||
- const: ce5
|
||||
- const: ce6
|
||||
- const: ce7
|
||||
- const: ce8
|
||||
- const: ce9
|
||||
- const: ce10
|
||||
- const: ce11
|
||||
- const: host2wbm-desc-feed
|
||||
- const: host2reo-re-injection
|
||||
- const: host2reo-command
|
||||
- const: host2rxdma-monitor-ring3
|
||||
- const: host2rxdma-monitor-ring2
|
||||
- const: host2rxdma-monitor-ring1
|
||||
- const: reo2ost-exception
|
||||
- const: wbm2host-rx-release
|
||||
- const: reo2host-status
|
||||
- const: reo2host-destination-ring4
|
||||
- const: reo2host-destination-ring3
|
||||
- const: reo2host-destination-ring2
|
||||
- const: reo2host-destination-ring1
|
||||
- const: rxdma2host-monitor-destination-mac3
|
||||
- const: rxdma2host-monitor-destination-mac2
|
||||
- const: rxdma2host-monitor-destination-mac1
|
||||
- const: ppdu-end-interrupts-mac3
|
||||
- const: ppdu-end-interrupts-mac2
|
||||
- const: ppdu-end-interrupts-mac1
|
||||
- const: rxdma2host-monitor-status-ring-mac3
|
||||
- const: rxdma2host-monitor-status-ring-mac2
|
||||
- const: rxdma2host-monitor-status-ring-mac1
|
||||
- const: host2rxdma-host-buf-ring-mac3
|
||||
- const: host2rxdma-host-buf-ring-mac2
|
||||
- const: host2rxdma-host-buf-ring-mac1
|
||||
- const: rxdma2host-destination-ring-mac3
|
||||
- const: rxdma2host-destination-ring-mac2
|
||||
- const: rxdma2host-destination-ring-mac1
|
||||
- const: host2tcl-input-ring4
|
||||
- const: host2tcl-input-ring3
|
||||
- const: host2tcl-input-ring2
|
||||
- const: host2tcl-input-ring1
|
||||
- const: wbm2host-tx-completions-ring3
|
||||
- const: wbm2host-tx-completions-ring2
|
||||
- const: wbm2host-tx-completions-ring1
|
||||
- const: tcl2host-status-ring
|
||||
|
||||
qcom,rproc:
|
||||
$ref: /schemas/types.yaml#definitions/phandle
|
||||
description:
|
||||
DT entry of q6v5-wcss remoteproc driver.
|
||||
Phandle to a node that can contain the following properties
|
||||
* compatible
|
||||
* reg
|
||||
* reg-names
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- qcom,rproc
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
q6v5_wcss: q6v5_wcss@CD00000 {
|
||||
compatible = "qcom,ipq8074-wcss-pil";
|
||||
reg = <0xCD00000 0x4040>,
|
||||
<0x4AB000 0x20>;
|
||||
reg-names = "qdsp6",
|
||||
"rmb";
|
||||
};
|
||||
|
||||
wifi0: wifi@c000000 {
|
||||
compatible = "qcom,ipq8074-wifi";
|
||||
reg = <0xc000000 0x2000000>;
|
||||
interrupts = <0 320 1>,
|
||||
<0 319 1>,
|
||||
<0 318 1>,
|
||||
<0 317 1>,
|
||||
<0 316 1>,
|
||||
<0 315 1>,
|
||||
<0 314 1>,
|
||||
<0 311 1>,
|
||||
<0 310 1>,
|
||||
<0 411 1>,
|
||||
<0 410 1>,
|
||||
<0 40 1>,
|
||||
<0 39 1>,
|
||||
<0 302 1>,
|
||||
<0 301 1>,
|
||||
<0 37 1>,
|
||||
<0 36 1>,
|
||||
<0 296 1>,
|
||||
<0 295 1>,
|
||||
<0 294 1>,
|
||||
<0 293 1>,
|
||||
<0 292 1>,
|
||||
<0 291 1>,
|
||||
<0 290 1>,
|
||||
<0 289 1>,
|
||||
<0 288 1>,
|
||||
<0 239 1>,
|
||||
<0 236 1>,
|
||||
<0 235 1>,
|
||||
<0 234 1>,
|
||||
<0 233 1>,
|
||||
<0 232 1>,
|
||||
<0 231 1>,
|
||||
<0 230 1>,
|
||||
<0 229 1>,
|
||||
<0 228 1>,
|
||||
<0 224 1>,
|
||||
<0 223 1>,
|
||||
<0 203 1>,
|
||||
<0 183 1>,
|
||||
<0 180 1>,
|
||||
<0 179 1>,
|
||||
<0 178 1>,
|
||||
<0 177 1>,
|
||||
<0 176 1>,
|
||||
<0 163 1>,
|
||||
<0 162 1>,
|
||||
<0 160 1>,
|
||||
<0 159 1>,
|
||||
<0 158 1>,
|
||||
<0 157 1>,
|
||||
<0 156 1>;
|
||||
interrupt-names = "misc-pulse1",
|
||||
"misc-latch",
|
||||
"sw-exception",
|
||||
"watchdog",
|
||||
"ce0",
|
||||
"ce1",
|
||||
"ce2",
|
||||
"ce3",
|
||||
"ce4",
|
||||
"ce5",
|
||||
"ce6",
|
||||
"ce7",
|
||||
"ce8",
|
||||
"ce9",
|
||||
"ce10",
|
||||
"ce11",
|
||||
"host2wbm-desc-feed",
|
||||
"host2reo-re-injection",
|
||||
"host2reo-command",
|
||||
"host2rxdma-monitor-ring3",
|
||||
"host2rxdma-monitor-ring2",
|
||||
"host2rxdma-monitor-ring1",
|
||||
"reo2ost-exception",
|
||||
"wbm2host-rx-release",
|
||||
"reo2host-status",
|
||||
"reo2host-destination-ring4",
|
||||
"reo2host-destination-ring3",
|
||||
"reo2host-destination-ring2",
|
||||
"reo2host-destination-ring1",
|
||||
"rxdma2host-monitor-destination-mac3",
|
||||
"rxdma2host-monitor-destination-mac2",
|
||||
"rxdma2host-monitor-destination-mac1",
|
||||
"ppdu-end-interrupts-mac3",
|
||||
"ppdu-end-interrupts-mac2",
|
||||
"ppdu-end-interrupts-mac1",
|
||||
"rxdma2host-monitor-status-ring-mac3",
|
||||
"rxdma2host-monitor-status-ring-mac2",
|
||||
"rxdma2host-monitor-status-ring-mac1",
|
||||
"host2rxdma-host-buf-ring-mac3",
|
||||
"host2rxdma-host-buf-ring-mac2",
|
||||
"host2rxdma-host-buf-ring-mac1",
|
||||
"rxdma2host-destination-ring-mac3",
|
||||
"rxdma2host-destination-ring-mac2",
|
||||
"rxdma2host-destination-ring-mac1",
|
||||
"host2tcl-input-ring4",
|
||||
"host2tcl-input-ring3",
|
||||
"host2tcl-input-ring2",
|
||||
"host2tcl-input-ring1",
|
||||
"wbm2host-tx-completions-ring3",
|
||||
"wbm2host-tx-completions-ring2",
|
||||
"wbm2host-tx-completions-ring1",
|
||||
"tcl2host-status-ring";
|
||||
qcom,rproc = <&q6v5_wcss>;
|
||||
};
|
||||
@@ -13644,6 +13644,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
|
||||
S: Supported
|
||||
F: drivers/net/wireless/ath/ath10k/
|
||||
|
||||
QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
|
||||
M: Kalle Valo <kvalo@codeaurora.org>
|
||||
L: ath11k@lists.infradead.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
|
||||
S: Supported
|
||||
F: drivers/net/wireless/ath/ath11k/
|
||||
|
||||
QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
|
||||
M: QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
||||
@@ -62,5 +62,6 @@ source "drivers/net/wireless/ath/ar5523/Kconfig"
|
||||
source "drivers/net/wireless/ath/wil6210/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath10k/Kconfig"
|
||||
source "drivers/net/wireless/ath/wcn36xx/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath11k/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
@@ -7,6 +7,7 @@ obj-$(CONFIG_AR5523) += ar5523/
|
||||
obj-$(CONFIG_WIL6210) += wil6210/
|
||||
obj-$(CONFIG_ATH10K) += ath10k/
|
||||
obj-$(CONFIG_WCN36XX) += wcn36xx/
|
||||
obj-$(CONFIG_ATH11K) += ath11k/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
|
||||
|
||||
@@ -346,6 +346,52 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 length)
|
||||
{
|
||||
struct bmi_cmd *cmd;
|
||||
u32 hdrlen = sizeof(cmd->id) + sizeof(cmd->lz_data);
|
||||
u32 txlen;
|
||||
int ret;
|
||||
size_t buf_len;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "large bmi lz data buffer 0x%pK length %d\n",
|
||||
buffer, length);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
buf_len = sizeof(*cmd) + BMI_MAX_LARGE_DATA_SIZE - BMI_MAX_DATA_SIZE;
|
||||
cmd = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
while (length) {
|
||||
txlen = min(length, BMI_MAX_LARGE_DATA_SIZE - hdrlen);
|
||||
|
||||
WARN_ON_ONCE(txlen & 3);
|
||||
|
||||
cmd->id = __cpu_to_le32(BMI_LZ_DATA);
|
||||
cmd->lz_data.len = __cpu_to_le32(txlen);
|
||||
memcpy(cmd->lz_data.payload, buffer, txlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, cmd, hdrlen + txlen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to write to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
buffer += txlen;
|
||||
length -= txlen;
|
||||
}
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
@@ -430,7 +476,11 @@ int ath10k_bmi_fast_download(struct ath10k *ar,
|
||||
if (trailer_len > 0)
|
||||
memcpy(trailer, buffer + head_len, trailer_len);
|
||||
|
||||
ret = ath10k_bmi_lz_data(ar, buffer, head_len);
|
||||
if (ar->hw_params.bmi_large_size_download)
|
||||
ret = ath10k_bmi_lz_data_large(ar, buffer, head_len);
|
||||
else
|
||||
ret = ath10k_bmi_lz_data(ar, buffer, head_len);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -45,6 +45,15 @@
|
||||
sizeof(u32) + \
|
||||
sizeof(u32))
|
||||
|
||||
/* Maximum data size used for large BMI transfers */
|
||||
#define BMI_MAX_LARGE_DATA_SIZE 2048
|
||||
|
||||
/* len = cmd + addr + length */
|
||||
#define BMI_MAX_LARGE_CMDBUF_SIZE (BMI_MAX_LARGE_DATA_SIZE + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32))
|
||||
|
||||
/* BMI Commands */
|
||||
|
||||
enum bmi_cmd_id {
|
||||
@@ -258,6 +267,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result);
|
||||
int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address);
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length);
|
||||
|
||||
int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
|
||||
const void *buffer, u32 length);
|
||||
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val);
|
||||
|
||||
@@ -189,6 +189,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.num_wds_entries = 0x20,
|
||||
.uart_pin_workaround = true,
|
||||
.tx_stats_over_pktlog = false,
|
||||
.bmi_large_size_download = true,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_2_1_VERSION,
|
||||
@@ -714,18 +715,6 @@ static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Explicitly set fwlog prints to zero as target may turn it on
|
||||
* based on scratch registers.
|
||||
*/
|
||||
ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
param |= HI_OPTION_DISABLE_DBGLOG;
|
||||
ret = ath10k_bmi_write32(ar, hi_option_flag, param);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3231,6 +3220,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
init_waitqueue_head(&ar->htt.empty_tx_wq);
|
||||
init_waitqueue_head(&ar->wmi.tx_credits_wq);
|
||||
|
||||
skb_queue_head_init(&ar->htt.rx_indication_head);
|
||||
|
||||
init_completion(&ar->offchan_tx_completed);
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
@@ -124,6 +124,7 @@ struct ath10k_skb_cb {
|
||||
struct ath10k_skb_rxcb {
|
||||
dma_addr_t paddr;
|
||||
struct hlist_node hlist;
|
||||
u8 eid;
|
||||
};
|
||||
|
||||
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
|
||||
@@ -1180,6 +1181,7 @@ struct ath10k {
|
||||
|
||||
struct {
|
||||
/* protected by data_lock */
|
||||
u32 rx_crc_err_drop;
|
||||
u32 fw_crash_counter;
|
||||
u32 fw_warm_reset_counter;
|
||||
u32 fw_cold_reset_counter;
|
||||
|
||||
@@ -1094,6 +1094,7 @@ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
|
||||
"d_rts_good",
|
||||
"d_tx_power", /* in .5 dbM I think */
|
||||
"d_rx_crc_err", /* fcs_bad */
|
||||
"d_rx_crc_err_drop", /* frame with FCS error, dropped late in kernel */
|
||||
"d_no_beacon",
|
||||
"d_tx_mpdus_queued",
|
||||
"d_tx_msdu_queued",
|
||||
@@ -1193,6 +1194,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
|
||||
data[i++] = pdev_stats->rts_good;
|
||||
data[i++] = pdev_stats->chan_tx_power;
|
||||
data[i++] = pdev_stats->fcs_bad;
|
||||
data[i++] = ar->stats.rx_crc_err_drop;
|
||||
data[i++] = pdev_stats->no_beacons;
|
||||
data[i++] = pdev_stats->mpdu_enqued;
|
||||
data[i++] = pdev_stats->msdu_enqued;
|
||||
|
||||
@@ -270,7 +270,7 @@ ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc,
|
||||
struct ath10k *ar = htc->ar;
|
||||
int bundle_cnt = len / sizeof(*report);
|
||||
|
||||
if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_RX_BUNDLE)) {
|
||||
if (!bundle_cnt || (bundle_cnt > htc->max_msgs_per_htc_bundle)) {
|
||||
ath10k_warn(ar, "Invalid lookahead bundle count: %d\n",
|
||||
bundle_cnt);
|
||||
return -EINVAL;
|
||||
@@ -800,8 +800,8 @@ setup:
|
||||
&ep->ul_pipe_id,
|
||||
&ep->dl_pipe_id);
|
||||
if (status) {
|
||||
ath10k_warn(ar, "unsupported HTC service id: %d\n",
|
||||
ep->service_id);
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "unsupported HTC service id: %d\n",
|
||||
ep->service_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -878,8 +878,8 @@ static bool ath10k_htc_pktlog_svc_supported(struct ath10k *ar)
|
||||
&ul_pipe_id,
|
||||
&dl_pipe_id);
|
||||
if (status) {
|
||||
ath10k_warn(ar, "unsupported HTC service id: %d\n",
|
||||
ATH10K_HTC_SVC_ID_HTT_LOG_MSG);
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "unsupported HTC pktlog service id: %d\n",
|
||||
ATH10K_HTC_SVC_ID_HTT_LOG_MSG);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
struct ath10k;
|
||||
|
||||
@@ -39,7 +40,7 @@ struct ath10k;
|
||||
* 4-byte aligned.
|
||||
*/
|
||||
|
||||
#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 8
|
||||
#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
|
||||
|
||||
enum ath10k_htc_tx_flags {
|
||||
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
|
||||
@@ -49,9 +50,27 @@ enum ath10k_htc_tx_flags {
|
||||
enum ath10k_htc_rx_flags {
|
||||
ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK = 0x01,
|
||||
ATH10K_HTC_FLAG_TRAILER_PRESENT = 0x02,
|
||||
ATH10K_HTC_FLAG_BUNDLE_MASK = 0xF0
|
||||
};
|
||||
|
||||
#define ATH10K_HTC_FLAG_BUNDLE_MASK GENMASK(7, 4)
|
||||
|
||||
/* bits 2-3 are for extra bundle count bits 4-5 */
|
||||
#define ATH10K_HTC_BUNDLE_EXTRA_MASK GENMASK(3, 2)
|
||||
#define ATH10K_HTC_BUNDLE_EXTRA_SHIFT 4
|
||||
|
||||
static inline unsigned int ath10k_htc_get_bundle_count(u8 max_msgs, u8 flags)
|
||||
{
|
||||
unsigned int count, extra_count = 0;
|
||||
|
||||
count = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, flags);
|
||||
|
||||
if (max_msgs > 16)
|
||||
extra_count = FIELD_GET(ATH10K_HTC_BUNDLE_EXTRA_MASK, flags) <<
|
||||
ATH10K_HTC_BUNDLE_EXTRA_SHIFT;
|
||||
|
||||
return count + extra_count;
|
||||
}
|
||||
|
||||
struct ath10k_htc_hdr {
|
||||
u8 eid; /* @enum ath10k_htc_ep_id */
|
||||
u8 flags; /* @enum ath10k_htc_tx_flags, ath10k_htc_rx_flags */
|
||||
|
||||
@@ -1869,6 +1869,8 @@ struct ath10k_htt {
|
||||
struct ath10k *ar;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
|
||||
struct sk_buff_head rx_indication_head;
|
||||
|
||||
u8 target_version_major;
|
||||
u8 target_version_minor;
|
||||
struct completion target_version_received;
|
||||
@@ -2283,6 +2285,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, 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);
|
||||
int ath10k_htt_rx_hl_indication(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
|
||||
|
||||
@@ -1285,6 +1285,13 @@ static void ath10k_process_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
if (!(ar->filter_flags & FIF_FCSFAIL) &&
|
||||
status->flag & RX_FLAG_FAILED_FCS_CRC) {
|
||||
ar->stats.rx_crc_err_drop++;
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_DATA,
|
||||
"rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
skb,
|
||||
@@ -2196,8 +2203,8 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
||||
HTT_RX_IND_MPDU_STATUS_OK &&
|
||||
mpdu_ranges->mpdu_range_status !=
|
||||
HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR) {
|
||||
ath10k_warn(ar, "MPDU range status: %d\n",
|
||||
mpdu_ranges->mpdu_range_status);
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt mpdu_range_status %d\n",
|
||||
mpdu_ranges->mpdu_range_status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -2235,8 +2242,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
qos = ieee80211_is_data_qos(hdr->frame_control);
|
||||
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
rx_status->chains |= BIT(0);
|
||||
memset(rx_status, 0, sizeof(*rx_status));
|
||||
|
||||
if (rx->ppdu.combined_rssi == 0) {
|
||||
/* SDIO firmware does not provide signal */
|
||||
rx_status->signal = 0;
|
||||
@@ -2350,7 +2359,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
||||
memcpy(skb->data + offset, &qos_ctrl, IEEE80211_QOS_CTL_LEN);
|
||||
}
|
||||
|
||||
ieee80211_rx_ni(ar->hw, skb);
|
||||
if (ar->napi.dev)
|
||||
ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi);
|
||||
else
|
||||
ieee80211_rx_ni(ar->hw, skb);
|
||||
|
||||
/* We have delivered the skb to the upper layers (mac80211) so we
|
||||
* must not free it.
|
||||
@@ -3751,14 +3763,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_RX_IND:
|
||||
if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL)
|
||||
return ath10k_htt_rx_proc_rx_ind_hl(htt,
|
||||
&resp->rx_ind_hl,
|
||||
skb,
|
||||
HTT_RX_PN_CHECK,
|
||||
HTT_RX_NON_TKIP_MIC);
|
||||
else
|
||||
if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) {
|
||||
ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
|
||||
} else {
|
||||
skb_queue_tail(&htt->rx_indication_head, skb);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_PEER_MAP: {
|
||||
struct htt_peer_map_event ev = {
|
||||
@@ -3948,6 +3958,37 @@ static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
|
||||
return quota;
|
||||
}
|
||||
|
||||
int ath10k_htt_rx_hl_indication(struct ath10k *ar, int budget)
|
||||
{
|
||||
struct htt_resp *resp;
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
struct sk_buff *skb;
|
||||
bool release;
|
||||
int quota;
|
||||
|
||||
for (quota = 0; quota < budget; quota++) {
|
||||
skb = skb_dequeue(&htt->rx_indication_head);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
resp = (struct htt_resp *)skb->data;
|
||||
|
||||
release = ath10k_htt_rx_proc_rx_ind_hl(htt,
|
||||
&resp->rx_ind_hl,
|
||||
skb,
|
||||
HTT_RX_PN_CHECK,
|
||||
HTT_RX_NON_TKIP_MIC);
|
||||
|
||||
if (release)
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "rx indication poll pending count:%d\n",
|
||||
skb_queue_len(&htt->rx_indication_head));
|
||||
}
|
||||
return quota;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htt_rx_hl_indication);
|
||||
|
||||
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
|
||||
@@ -613,6 +613,9 @@ struct ath10k_hw_params {
|
||||
/* target supporting fw download via diag ce */
|
||||
bool fw_diag_ce_download;
|
||||
|
||||
/* target supporting fw download via large size BMI */
|
||||
bool bmi_large_size_download;
|
||||
|
||||
/* need to set uart pin if disable uart print, workaround for a
|
||||
* firmware bug
|
||||
*/
|
||||
|
||||
@@ -6329,6 +6329,9 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
if (sta && sta->tdls)
|
||||
ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
|
||||
ar->wmi.peer_param->authorize, 1);
|
||||
else if (sta && cmd == SET_KEY && (key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
|
||||
ath10k_wmi_peer_set_param(ar, arvif->vdev_id, peer_addr,
|
||||
ar->wmi.peer_param->authorize, 1);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
@@ -8908,6 +8911,7 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
WMI_PNO_MAX_SCHED_SCAN_PLAN_INT;
|
||||
ar->hw->wiphy->max_sched_scan_plan_iterations =
|
||||
WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS;
|
||||
ar->hw->wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
|
||||
}
|
||||
|
||||
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
|
||||
|
||||
@@ -279,7 +279,15 @@ static int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
/* end = 1 triggers a CRC check on the BDF. If this fails, we
|
||||
* get a QMI_ERR_MALFORMED_MSG_V01 error, but the FW is still
|
||||
* willing to use the BDF. For some platforms, all the valid
|
||||
* released BDFs fail this CRC check, so attempt to detect this
|
||||
* scenario and treat it as non-fatal.
|
||||
*/
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01 &&
|
||||
!(req->end == 1 &&
|
||||
resp.resp.result == QMI_ERR_MALFORMED_MSG_V01)) {
|
||||
ath10k_err(ar, "failed to download board data file: %d\n",
|
||||
resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
@@ -635,7 +643,9 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
/* older FW didn't support this request, which is not fatal */
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01 &&
|
||||
resp.resp.error != QMI_ERR_NOT_SUPPORTED_V01) {
|
||||
ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "trace.h"
|
||||
#include "sdio.h"
|
||||
|
||||
#define ATH10K_SDIO_VSG_BUF_SIZE (64 * 1024)
|
||||
|
||||
/* inlined helper functions */
|
||||
|
||||
static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
|
||||
@@ -417,6 +419,7 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
|
||||
struct ath10k_htc *htc = &ar->htc;
|
||||
struct ath10k_sdio_rx_data *pkt;
|
||||
struct ath10k_htc_ep *ep;
|
||||
struct ath10k_skb_rxcb *cb;
|
||||
enum ath10k_htc_ep_id id;
|
||||
int ret, i, *n_lookahead_local;
|
||||
u32 *lookaheads_local;
|
||||
@@ -462,10 +465,16 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!pkt->trailer_only)
|
||||
ep->ep_ops.ep_rx_complete(ar_sdio->ar, pkt->skb);
|
||||
else
|
||||
if (!pkt->trailer_only) {
|
||||
cb = ATH10K_SKB_RXCB(pkt->skb);
|
||||
cb->eid = id;
|
||||
|
||||
skb_queue_tail(&ar_sdio->rx_head, pkt->skb);
|
||||
queue_work(ar->workqueue_aux,
|
||||
&ar_sdio->async_work_rx);
|
||||
} else {
|
||||
kfree_skb(pkt->skb);
|
||||
}
|
||||
|
||||
/* The RX complete handler now owns the skb...*/
|
||||
pkt->skb = NULL;
|
||||
@@ -484,21 +493,22 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar,
|
||||
struct ath10k_sdio_rx_data *rx_pkts,
|
||||
struct ath10k_htc_hdr *htc_hdr,
|
||||
size_t full_len, size_t act_len,
|
||||
size_t *bndl_cnt)
|
||||
static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
|
||||
struct ath10k_sdio_rx_data *rx_pkts,
|
||||
struct ath10k_htc_hdr *htc_hdr,
|
||||
size_t full_len, size_t act_len,
|
||||
size_t *bndl_cnt)
|
||||
{
|
||||
int ret, i;
|
||||
u8 max_msgs = ar->htc.max_msgs_per_htc_bundle;
|
||||
|
||||
*bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags);
|
||||
*bndl_cnt = ath10k_htc_get_bundle_count(max_msgs, htc_hdr->flags);
|
||||
|
||||
if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_RX_BUNDLE) {
|
||||
if (*bndl_cnt > max_msgs) {
|
||||
ath10k_warn(ar,
|
||||
"HTC bundle length %u exceeds maximum %u\n",
|
||||
le16_to_cpu(htc_hdr->len),
|
||||
HTC_HOST_MAX_MSG_PER_RX_BUNDLE);
|
||||
max_msgs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -529,12 +539,11 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
|
||||
size_t full_len, act_len;
|
||||
bool last_in_bundle;
|
||||
int ret, i;
|
||||
int pkt_cnt = 0;
|
||||
|
||||
if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) {
|
||||
ath10k_warn(ar,
|
||||
"the total number of pkgs to be fetched (%u) exceeds maximum %u\n",
|
||||
n_lookaheads,
|
||||
ATH10K_SDIO_MAX_RX_MSGS);
|
||||
ath10k_warn(ar, "the total number of pkgs to be fetched (%u) exceeds maximum %u\n",
|
||||
n_lookaheads, ATH10K_SDIO_MAX_RX_MSGS);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
@@ -543,10 +552,8 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
|
||||
htc_hdr = (struct ath10k_htc_hdr *)&lookaheads[i];
|
||||
last_in_bundle = false;
|
||||
|
||||
if (le16_to_cpu(htc_hdr->len) >
|
||||
ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH) {
|
||||
ath10k_warn(ar,
|
||||
"payload length %d exceeds max htc length: %zu\n",
|
||||
if (le16_to_cpu(htc_hdr->len) > ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH) {
|
||||
ath10k_warn(ar, "payload length %d exceeds max htc length: %zu\n",
|
||||
le16_to_cpu(htc_hdr->len),
|
||||
ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH);
|
||||
ret = -ENOMEM;
|
||||
@@ -557,36 +564,37 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
|
||||
full_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio, act_len);
|
||||
|
||||
if (full_len > ATH10K_SDIO_MAX_BUFFER_SIZE) {
|
||||
ath10k_warn(ar,
|
||||
"rx buffer requested with invalid htc_hdr length (%d, 0x%x): %d\n",
|
||||
ath10k_warn(ar, "rx buffer requested with invalid htc_hdr length (%d, 0x%x): %d\n",
|
||||
htc_hdr->eid, htc_hdr->flags,
|
||||
le16_to_cpu(htc_hdr->len));
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (htc_hdr->flags & ATH10K_HTC_FLAG_BUNDLE_MASK) {
|
||||
if (ath10k_htc_get_bundle_count(
|
||||
ar->htc.max_msgs_per_htc_bundle, htc_hdr->flags)) {
|
||||
/* HTC header indicates that every packet to follow
|
||||
* has the same padded length so that it can be
|
||||
* optimally fetched as a full bundle.
|
||||
*/
|
||||
size_t bndl_cnt;
|
||||
|
||||
ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar,
|
||||
&ar_sdio->rx_pkts[i],
|
||||
htc_hdr,
|
||||
full_len,
|
||||
act_len,
|
||||
&bndl_cnt);
|
||||
ret = ath10k_sdio_mbox_alloc_bundle(ar,
|
||||
&ar_sdio->rx_pkts[pkt_cnt],
|
||||
htc_hdr,
|
||||
full_len,
|
||||
act_len,
|
||||
&bndl_cnt);
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "alloc_bundle error %d\n", ret);
|
||||
ath10k_warn(ar, "failed to allocate a bundle: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
n_lookaheads += bndl_cnt;
|
||||
i += bndl_cnt;
|
||||
/*Next buffer will be the last in the bundle */
|
||||
pkt_cnt += bndl_cnt;
|
||||
|
||||
/* next buffer will be the last in the bundle */
|
||||
last_in_bundle = true;
|
||||
}
|
||||
|
||||
@@ -597,7 +605,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
|
||||
if (htc_hdr->flags & ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK)
|
||||
full_len += ATH10K_HIF_MBOX_BLOCK_SIZE;
|
||||
|
||||
ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[i],
|
||||
ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[pkt_cnt],
|
||||
act_len,
|
||||
full_len,
|
||||
last_in_bundle,
|
||||
@@ -606,9 +614,11 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
|
||||
ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pkt_cnt++;
|
||||
}
|
||||
|
||||
ar_sdio->n_rx_pkts = i;
|
||||
ar_sdio->n_rx_pkts = pkt_cnt;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -622,59 +632,74 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
|
||||
struct ath10k_sdio_rx_data *pkt)
|
||||
static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
struct ath10k_htc_hdr *htc_hdr;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
|
||||
skb->data, pkt->alloc_len);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Update actual length. The original length may be incorrect,
|
||||
* as the FW will bundle multiple packets as long as their sizes
|
||||
* fit within the same aligned length (pkt->alloc_len).
|
||||
*/
|
||||
htc_hdr = (struct ath10k_htc_hdr *)skb->data;
|
||||
pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
|
||||
if (pkt->act_len > pkt->alloc_len) {
|
||||
ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
|
||||
pkt->act_len, pkt->alloc_len);
|
||||
ret = -EMSGSIZE;
|
||||
goto out;
|
||||
if (ret) {
|
||||
ar_sdio->n_rx_pkts = 0;
|
||||
ath10k_sdio_mbox_free_rx_pkt(pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
htc_hdr = (struct ath10k_htc_hdr *)skb->data;
|
||||
pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
|
||||
skb_put(skb, pkt->act_len);
|
||||
|
||||
out:
|
||||
pkt->status = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
|
||||
static int ath10k_sdio_mbox_rx_fetch_bundle(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
struct ath10k_sdio_rx_data *pkt;
|
||||
struct ath10k_htc_hdr *htc_hdr;
|
||||
int ret, i;
|
||||
u32 pkt_offset, virt_pkt_len;
|
||||
|
||||
virt_pkt_len = 0;
|
||||
for (i = 0; i < ar_sdio->n_rx_pkts; i++)
|
||||
virt_pkt_len += ar_sdio->rx_pkts[i].alloc_len;
|
||||
|
||||
if (virt_pkt_len > ATH10K_SDIO_VSG_BUF_SIZE) {
|
||||
ath10k_warn(ar, "sdio vsg buffer size limit: %d\n", virt_pkt_len);
|
||||
ret = -E2BIG;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
|
||||
ar_sdio->vsg_buffer, virt_pkt_len);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read bundle packets: %d", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pkt_offset = 0;
|
||||
for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
|
||||
ret = ath10k_sdio_mbox_rx_packet(ar,
|
||||
&ar_sdio->rx_pkts[i]);
|
||||
if (ret)
|
||||
goto err;
|
||||
pkt = &ar_sdio->rx_pkts[i];
|
||||
htc_hdr = (struct ath10k_htc_hdr *)(ar_sdio->vsg_buffer + pkt_offset);
|
||||
pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
|
||||
|
||||
skb_put_data(pkt->skb, htc_hdr, pkt->act_len);
|
||||
pkt_offset += pkt->alloc_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/* Free all packets that was not successfully fetched. */
|
||||
for (; i < ar_sdio->n_rx_pkts; i++)
|
||||
for (i = 0; i < ar_sdio->n_rx_pkts; i++)
|
||||
ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]);
|
||||
|
||||
ar_sdio->n_rx_pkts = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -717,7 +742,10 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar,
|
||||
*/
|
||||
*done = false;
|
||||
|
||||
ret = ath10k_sdio_mbox_rx_fetch(ar);
|
||||
if (ar_sdio->n_rx_pkts > 1)
|
||||
ret = ath10k_sdio_mbox_rx_fetch_bundle(ar);
|
||||
else
|
||||
ret = ath10k_sdio_mbox_rx_fetch(ar);
|
||||
|
||||
/* Process fetched packets. This will potentially update
|
||||
* n_lookaheads depending on if the packets contain lookahead
|
||||
@@ -1293,6 +1321,31 @@ static void __ath10k_sdio_write_async(struct ath10k *ar,
|
||||
ath10k_sdio_free_bus_req(ar, req);
|
||||
}
|
||||
|
||||
/* To improve throughput use workqueue to deliver packets to HTC layer,
|
||||
* this way SDIO bus is utilised much better.
|
||||
*/
|
||||
static void ath10k_rx_indication_async_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
|
||||
async_work_rx);
|
||||
struct ath10k *ar = ar_sdio->ar;
|
||||
struct ath10k_htc_ep *ep;
|
||||
struct ath10k_skb_rxcb *cb;
|
||||
struct sk_buff *skb;
|
||||
|
||||
while (true) {
|
||||
skb = skb_dequeue(&ar_sdio->rx_head);
|
||||
if (!skb)
|
||||
break;
|
||||
cb = ATH10K_SKB_RXCB(skb);
|
||||
ep = &ar->htc.endpoint[cb->eid];
|
||||
ep->ep_ops.ep_rx_complete(ar, skb);
|
||||
}
|
||||
|
||||
if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
|
||||
napi_schedule(&ar->napi);
|
||||
}
|
||||
|
||||
static void ath10k_sdio_write_async_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
|
||||
@@ -1681,6 +1734,8 @@ static int ath10k_sdio_hif_start(struct ath10k *ar)
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
int ret;
|
||||
|
||||
napi_enable(&ar->napi);
|
||||
|
||||
/* Sleep 20 ms before HIF interrupts are disabled.
|
||||
* This will give target plenty of time to process the BMI done
|
||||
* request before interrupts are disabled.
|
||||
@@ -1805,13 +1860,16 @@ static void ath10k_sdio_hif_stop(struct ath10k *ar)
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar_sdio->wr_async_lock);
|
||||
|
||||
napi_synchronize(&ar->napi);
|
||||
napi_disable(&ar->napi);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int ath10k_sdio_hif_suspend(struct ath10k *ar)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_hif_resume(struct ath10k *ar)
|
||||
@@ -1961,7 +2019,26 @@ static const struct ath10k_hif_ops ath10k_sdio_hif_ops = {
|
||||
*/
|
||||
static int ath10k_sdio_pm_suspend(struct device *device)
|
||||
{
|
||||
return 0;
|
||||
struct sdio_func *func = dev_to_sdio_func(device);
|
||||
struct ath10k_sdio *ar_sdio = sdio_get_drvdata(func);
|
||||
struct ath10k *ar = ar_sdio->ar;
|
||||
mmc_pm_flag_t pm_flag, pm_caps;
|
||||
int ret;
|
||||
|
||||
if (!device_may_wakeup(ar->dev))
|
||||
return 0;
|
||||
|
||||
pm_flag = MMC_PM_KEEP_POWER;
|
||||
|
||||
ret = sdio_set_host_pm_flags(func, pm_flag);
|
||||
if (ret) {
|
||||
pm_caps = sdio_get_host_pm_caps(func);
|
||||
ath10k_warn(ar, "failed to set sdio host pm flags (0x%x, 0x%x): %d\n",
|
||||
pm_flag, pm_caps, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_pm_resume(struct device *device)
|
||||
@@ -1980,6 +2057,20 @@ static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend,
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static int ath10k_sdio_napi_poll(struct napi_struct *ctx, int budget)
|
||||
{
|
||||
struct ath10k *ar = container_of(ctx, struct ath10k, napi);
|
||||
int done;
|
||||
|
||||
done = ath10k_htt_rx_hl_indication(ar, budget);
|
||||
ath10k_dbg(ar, ATH10K_DBG_SDIO, "napi poll: done: %d, budget:%d\n", done, budget);
|
||||
|
||||
if (done < budget)
|
||||
napi_complete_done(ctx, done);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
@@ -2005,6 +2096,9 @@ static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll,
|
||||
ATH10K_NAPI_BUDGET);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
|
||||
func->num, func->vendor, func->device,
|
||||
@@ -2020,6 +2114,12 @@ static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
goto err_core_destroy;
|
||||
}
|
||||
|
||||
ar_sdio->vsg_buffer = devm_kmalloc(ar->dev, ATH10K_SDIO_VSG_BUF_SIZE, GFP_KERNEL);
|
||||
if (!ar_sdio->vsg_buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto err_core_destroy;
|
||||
}
|
||||
|
||||
ar_sdio->irq_data.irq_en_reg =
|
||||
devm_kzalloc(ar->dev, sizeof(struct ath10k_sdio_irq_enable_regs),
|
||||
GFP_KERNEL);
|
||||
@@ -2028,7 +2128,7 @@ static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
goto err_core_destroy;
|
||||
}
|
||||
|
||||
ar_sdio->bmi_buf = devm_kzalloc(ar->dev, BMI_MAX_CMDBUF_SIZE, GFP_KERNEL);
|
||||
ar_sdio->bmi_buf = devm_kzalloc(ar->dev, BMI_MAX_LARGE_CMDBUF_SIZE, GFP_KERNEL);
|
||||
if (!ar_sdio->bmi_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_core_destroy;
|
||||
@@ -2057,6 +2157,9 @@ static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++)
|
||||
ath10k_sdio_free_bus_req(ar, &ar_sdio->bus_req[i]);
|
||||
|
||||
skb_queue_head_init(&ar_sdio->rx_head);
|
||||
INIT_WORK(&ar_sdio->async_work_rx, ath10k_rx_indication_async_work);
|
||||
|
||||
dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, id->device);
|
||||
switch (dev_id_base) {
|
||||
case QCA_MANUFACTURER_ID_AR6005_BASE:
|
||||
@@ -2080,6 +2183,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
bus_params.chip_id = 0;
|
||||
bus_params.hl_msdu_ids = true;
|
||||
|
||||
ar->hw->max_mtu = ETH_DATA_LEN;
|
||||
|
||||
ret = ath10k_core_register(ar, &bus_params);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to register driver core: %d\n", ret);
|
||||
@@ -2106,6 +2211,9 @@ static void ath10k_sdio_remove(struct sdio_func *func)
|
||||
func->num, func->vendor, func->device);
|
||||
|
||||
ath10k_core_unregister(ar);
|
||||
|
||||
netif_napi_del(&ar->napi);
|
||||
|
||||
ath10k_core_destroy(ar);
|
||||
|
||||
flush_workqueue(ar_sdio->workqueue);
|
||||
|
||||
@@ -89,10 +89,10 @@
|
||||
* to the maximum value (HTC_HOST_MAX_MSG_PER_RX_BUNDLE).
|
||||
*
|
||||
* in this case the driver must allocate
|
||||
* (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE) skb's.
|
||||
* (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2) skb's.
|
||||
*/
|
||||
#define ATH10K_SDIO_MAX_RX_MSGS \
|
||||
(HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE)
|
||||
(HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2)
|
||||
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
|
||||
@@ -126,7 +126,6 @@ struct ath10k_sdio_rx_data {
|
||||
bool part_of_bundle;
|
||||
bool last_in_bundle;
|
||||
bool trailer_only;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_proc_regs {
|
||||
@@ -138,8 +137,8 @@ struct ath10k_sdio_irq_proc_regs {
|
||||
u8 rx_lookahead_valid;
|
||||
u8 host_int_status2;
|
||||
u8 gmbox_rx_avail;
|
||||
__le32 rx_lookahead[2];
|
||||
__le32 rx_gmbox_lookahead_alias[2];
|
||||
__le32 rx_lookahead[2 * ATH10K_HIF_MBOX_NUM_MAX];
|
||||
__le32 int_status_enable;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_enable_regs {
|
||||
@@ -187,6 +186,9 @@ struct ath10k_sdio {
|
||||
struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM];
|
||||
/* free list of bus requests */
|
||||
struct list_head bus_req_freeq;
|
||||
|
||||
struct sk_buff_head rx_head;
|
||||
|
||||
/* protects access to bus_req_freeq */
|
||||
spinlock_t lock;
|
||||
|
||||
@@ -196,6 +198,13 @@ struct ath10k_sdio {
|
||||
struct ath10k *ar;
|
||||
struct ath10k_sdio_irq_data irq_data;
|
||||
|
||||
/* temporary buffer for sdio read.
|
||||
* It is allocated when probe, and used for receive bundled packets,
|
||||
* the read for bundled packets is not parallel, so it does not need
|
||||
* protected.
|
||||
*/
|
||||
u8 *vsg_buffer;
|
||||
|
||||
/* temporary buffer for BMI requests */
|
||||
u8 *bmi_buf;
|
||||
|
||||
@@ -206,6 +215,8 @@ struct ath10k_sdio {
|
||||
struct list_head wr_asyncq;
|
||||
/* protects access to wr_asyncq */
|
||||
spinlock_t wr_async_lock;
|
||||
|
||||
struct work_struct async_work_rx;
|
||||
};
|
||||
|
||||
static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar)
|
||||
|
||||
@@ -1563,13 +1563,16 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
|
||||
ret = ath10k_qmi_init(ar, msa_size);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
|
||||
goto err_core_destroy;
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off:
|
||||
ath10k_hw_power_off(ar);
|
||||
|
||||
err_free_irq:
|
||||
ath10k_snoc_free_irq(ar);
|
||||
|
||||
|
||||
@@ -841,7 +841,7 @@ static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
|
||||
const struct wmi_tlv_mgmt_rx_ev *ev;
|
||||
const u8 *frame;
|
||||
u32 msdu_len;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
|
||||
if (IS_ERR(tb)) {
|
||||
@@ -865,6 +865,9 @@ static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
|
||||
arg->phy_mode = ev->phy_mode;
|
||||
arg->rate = ev->rate;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ev->rssi); i++)
|
||||
arg->rssi[i] = ev->rssi[i];
|
||||
|
||||
msdu_len = __le32_to_cpu(arg->buf_len);
|
||||
|
||||
if (skb->len < (frame - skb->data) + msdu_len) {
|
||||
@@ -3707,6 +3710,7 @@ 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;
|
||||
@@ -3764,10 +3768,12 @@ 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);
|
||||
tlv->len = __cpu_to_le16(len);
|
||||
tlv->len = __cpu_to_le16(tlv_len);
|
||||
|
||||
ptr += sizeof(*tlv);
|
||||
nlo_list = ptr;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user