Merge tag 'wireless-next-2025-03-20' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says: ==================== More features for 6.15, major changes: * cfg80211/mac80211: fix and enable link reconfiguration * rtw88: support RTL8814AE/RTL8814AU * mt7996: preparations for MLO * ath12k: continued work on MLO * iwlwifi: add new iwlmld sub-driver/op-mode for some current and future devices * wfx: wowlan support * tag 'wireless-next-2025-03-20' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (311 commits) wifi: mt76: mt7996: fix locking in mt7996_mac_sta_rc_work() wifi: mt76: mt76x2u: add TP-Link TL-WDN6200 ID to device table wifi: mt76: mt792x: re-register CHANCTX_STA_CSA only for the mt7921 series wifi: mt76: mt7996: Update mt7996_tx to MLO support wifi: mt76: mt7996: rework mt7996_ampdu_action to support MLO wifi: mt76: mt7996: rework set/get_tsf callabcks to support MLO wifi: mt76: mt7996: set vif default link_id adding/removing vif links wifi: mt76: mt7996: rework mt7996_mcu_beacon_inband_discov to support MLO wifi: mt76: mt7996: rework mt7996_mcu_add_obss_spr to support MLO wifi: mt76: mt7996: rework mt7996_net_fill_forward_path to support MLO wifi: mt76: mt7996: rework mt7996_update_mu_group to support MLO wifi: mt76: mt7996: rework mt7996_mac_sta_poll to support MLO wifi: mt76: mt7996: rework mt7996_mac_sta_rc_work to support MLO wifi: mt76: mt7996: remove mt7996_mac_enable_rtscts() wifi: mt76: mt7996: rework mt7996_sta_hw_queue_read to support MLO wifi: mt76: mt7996: rework mt7996_set_hw_key to support MLO wifi: mt76: mt7996: Add mt7996_sta_link to mt7996_mcu_add_bss_info signature wifi: mt76: mt7996: rework mt7996_sta_set_4addr and mt7996_sta_set_decap_offload to support MLO wifi: mt76: mt7996: rework mt7996_rx_get_wcid to support MLO wifi: mt76: mt7996: Rely on wcid_to_sta in mt7996_mac_add_txs_skb() ... ==================== Link: https://patch.msgid.link/20250320131106.33266-3-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -92,20 +92,41 @@ properties:
|
||||
|
||||
ieee80211-freq-limit: true
|
||||
|
||||
qcom,ath10k-calibration-data:
|
||||
qcom,calibration-data:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
description:
|
||||
Calibration data + board-specific data as a byte array. The length
|
||||
can vary between hardware versions.
|
||||
|
||||
qcom,ath10k-calibration-variant:
|
||||
qcom,ath10k-calibration-data:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
deprecated: true
|
||||
description:
|
||||
Calibration data + board-specific data as a byte array. The length
|
||||
can vary between hardware versions.
|
||||
|
||||
qcom,calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
Unique variant identifier of the calibration data in board-2.bin
|
||||
for designs with colliding bus and device specific ids
|
||||
|
||||
qcom,ath10k-calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
description:
|
||||
Unique variant identifier of the calibration data in board-2.bin
|
||||
for designs with colliding bus and device specific ids
|
||||
|
||||
qcom,pre-calibration-data:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
description:
|
||||
Pre-calibration data as a byte array. The length can vary between
|
||||
hardware versions.
|
||||
|
||||
qcom,ath10k-pre-calibration-data:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
deprecated: true
|
||||
description:
|
||||
Pre-calibration data as a byte array. The length can vary between
|
||||
hardware versions.
|
||||
|
||||
@@ -22,8 +22,15 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
qcom,calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: |
|
||||
string to uniquely identify variant of the calibration data for designs
|
||||
with colliding bus and device ids
|
||||
|
||||
qcom,ath11k-calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
description: |
|
||||
string to uniquely identify variant of the calibration data for designs
|
||||
with colliding bus and device ids
|
||||
@@ -127,7 +134,7 @@ examples:
|
||||
vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
|
||||
vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
|
||||
|
||||
qcom,ath11k-calibration-variant = "LE_X13S";
|
||||
qcom,calibration-variant = "LE_X13S";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -41,8 +41,15 @@ properties:
|
||||
* reg
|
||||
* reg-names
|
||||
|
||||
qcom,calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
string to uniquely identify variant of the calibration data in the
|
||||
board-2.bin for designs with colliding bus and device specific ids
|
||||
|
||||
qcom,ath11k-calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
description:
|
||||
string to uniquely identify variant of the calibration data in the
|
||||
board-2.bin for designs with colliding bus and device specific ids
|
||||
|
||||
@@ -52,8 +52,15 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
qcom,calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
String to uniquely identify variant of the calibration data for designs
|
||||
with colliding bus and device ids
|
||||
|
||||
qcom,ath12k-calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
description:
|
||||
String to uniquely identify variant of the calibration data for designs
|
||||
with colliding bus and device ids
|
||||
@@ -103,7 +110,7 @@ examples:
|
||||
compatible = "pci17cb,1109";
|
||||
reg = <0x0 0x0 0x0 0x0 0x0>;
|
||||
|
||||
qcom,ath12k-calibration-variant = "RDP433_1";
|
||||
qcom,calibration-variant = "RDP433_1";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
@@ -139,7 +146,7 @@ examples:
|
||||
compatible = "pci17cb,1109";
|
||||
reg = <0x0 0x0 0x0 0x0 0x0>;
|
||||
|
||||
qcom,ath12k-calibration-variant = "RDP433_2";
|
||||
qcom,calibration-variant = "RDP433_2";
|
||||
qcom,wsi-controller;
|
||||
|
||||
ports {
|
||||
@@ -176,7 +183,7 @@ examples:
|
||||
compatible = "pci17cb,1109";
|
||||
reg = <0x0 0x0 0x0 0x0 0x0>;
|
||||
|
||||
qcom,ath12k-calibration-variant = "RDP433_3";
|
||||
qcom,calibration-variant = "RDP433_3";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -1163,8 +1163,11 @@ int ath10k_core_check_dt(struct ath10k *ar)
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
of_property_read_string(node, "qcom,ath10k-calibration-variant",
|
||||
of_property_read_string(node, "qcom,calibration-variant",
|
||||
&variant);
|
||||
if (!variant)
|
||||
of_property_read_string(node, "qcom,ath10k-calibration-variant",
|
||||
&variant);
|
||||
if (!variant)
|
||||
return -ENODATA;
|
||||
|
||||
@@ -2259,7 +2262,9 @@ static int ath10k_core_pre_cal_download(struct ath10k *ar)
|
||||
"boot did not find a pre calibration file, try DT next: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,ath10k-pre-calibration-data");
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,pre-calibration-data");
|
||||
if (ret == -ENOENT)
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,ath10k-pre-calibration-data");
|
||||
if (ret) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"unable to load pre cal data from DT: %d\n", ret);
|
||||
@@ -2337,7 +2342,9 @@ static int ath10k_download_cal_data(struct ath10k *ar)
|
||||
"boot did not find a calibration file, try DT next: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,ath10k-calibration-data");
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,calibration-data");
|
||||
if (ret == -ENOENT)
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,ath10k-calibration-data");
|
||||
if (ret == 0) {
|
||||
ar->cal_mode = ATH10K_CAL_MODE_DT;
|
||||
goto done;
|
||||
|
||||
@@ -27,6 +27,7 @@ ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
|
||||
ath11k-$(CONFIG_THERMAL) += thermal.o
|
||||
ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o
|
||||
ath11k-$(CONFIG_PM) += wow.o
|
||||
ath11k-$(CONFIG_DEV_COREDUMP) += coredump.o
|
||||
|
||||
obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o
|
||||
ath11k_ahb-y += ahb.o
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -1290,6 +1290,7 @@ static void ath11k_ahb_remove(struct platform_device *pdev)
|
||||
ath11k_core_deinit(ab);
|
||||
|
||||
qmi_fail:
|
||||
ath11k_fw_destroy(ab);
|
||||
ath11k_ahb_free_resources(ab);
|
||||
}
|
||||
|
||||
@@ -1309,6 +1310,7 @@ static void ath11k_ahb_shutdown(struct platform_device *pdev)
|
||||
ath11k_core_deinit(ab);
|
||||
|
||||
free_resources:
|
||||
ath11k_fw_destroy(ab);
|
||||
ath11k_ahb_free_resources(ab);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -1175,8 +1175,11 @@ int ath11k_core_check_dt(struct ath11k_base *ab)
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
of_property_read_string(node, "qcom,ath11k-calibration-variant",
|
||||
of_property_read_string(node, "qcom,calibration-variant",
|
||||
&variant);
|
||||
if (!variant)
|
||||
of_property_read_string(node, "qcom,ath11k-calibration-variant",
|
||||
&variant);
|
||||
if (!variant)
|
||||
return -ENODATA;
|
||||
|
||||
@@ -2056,6 +2059,7 @@ void ath11k_core_halt(struct ath11k *ar)
|
||||
ath11k_mac_scan_finish(ar);
|
||||
ath11k_mac_peer_cleanup_all(ar);
|
||||
cancel_delayed_work_sync(&ar->scan.timeout);
|
||||
cancel_work_sync(&ar->channel_update_work);
|
||||
cancel_work_sync(&ar->regd_update_work);
|
||||
cancel_work_sync(&ab->update_11d_work);
|
||||
|
||||
@@ -2257,6 +2261,7 @@ static void ath11k_core_reset(struct work_struct *work)
|
||||
reinit_completion(&ab->recovery_start);
|
||||
atomic_set(&ab->recovery_start_count, 0);
|
||||
|
||||
ath11k_coredump_collect(ab);
|
||||
ath11k_core_pre_reconfigure_recovery(ab);
|
||||
|
||||
reinit_completion(&ab->reconfigure_complete);
|
||||
@@ -2346,7 +2351,6 @@ void ath11k_core_deinit(struct ath11k_base *ab)
|
||||
ath11k_hif_power_down(ab);
|
||||
ath11k_mac_destroy(ab);
|
||||
ath11k_core_soc_destroy(ab);
|
||||
ath11k_fw_destroy(ab);
|
||||
}
|
||||
EXPORT_SYMBOL(ath11k_core_deinit);
|
||||
|
||||
@@ -2393,6 +2397,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
|
||||
INIT_WORK(&ab->restart_work, ath11k_core_restart);
|
||||
INIT_WORK(&ab->update_11d_work, ath11k_update_11d);
|
||||
INIT_WORK(&ab->reset_work, ath11k_core_reset);
|
||||
INIT_WORK(&ab->dump_work, ath11k_coredump_upload);
|
||||
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
|
||||
init_completion(&ab->htc_suspend);
|
||||
init_completion(&ab->wow.wakeup_completed);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH11K_CORE_H
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "spectral.h"
|
||||
#include "wow.h"
|
||||
#include "fw.h"
|
||||
#include "coredump.h"
|
||||
|
||||
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
||||
|
||||
@@ -370,6 +371,7 @@ struct ath11k_vif {
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
struct wmi_wmm_params_all_arg wmm_params;
|
||||
struct wmi_wmm_params_all_arg muedca_params;
|
||||
struct list_head list;
|
||||
union {
|
||||
struct {
|
||||
@@ -685,7 +687,7 @@ struct ath11k {
|
||||
struct mutex conf_mutex;
|
||||
/* protects the radio specific data like debug stats, ppdu_stats_info stats,
|
||||
* vdev_stop_status info, scan data, ath11k_sta info, ath11k_vif info,
|
||||
* channel context data, survey info, test mode data.
|
||||
* channel context data, survey info, test mode data, channel_update_queue.
|
||||
*/
|
||||
spinlock_t data_lock;
|
||||
|
||||
@@ -743,6 +745,9 @@ struct ath11k {
|
||||
struct completion bss_survey_done;
|
||||
|
||||
struct work_struct regd_update_work;
|
||||
struct work_struct channel_update_work;
|
||||
/* protected with data_lock */
|
||||
struct list_head channel_update_queue;
|
||||
|
||||
struct work_struct wmi_mgmt_tx_work;
|
||||
struct sk_buff_head wmi_mgmt_tx_queue;
|
||||
@@ -900,6 +905,10 @@ struct ath11k_base {
|
||||
/* HW channel counters frequency value in hertz common to all MACs */
|
||||
u32 cc_freq_hz;
|
||||
|
||||
struct ath11k_dump_file_data *dump_data;
|
||||
size_t ath11k_coredump_len;
|
||||
struct work_struct dump_work;
|
||||
|
||||
struct ath11k_htc htc;
|
||||
|
||||
struct ath11k_dp dp;
|
||||
|
||||
52
drivers/net/wireless/ath/ath11k/coredump.c
Normal file
52
drivers/net/wireless/ath/ath11k/coredump.c
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/devcoredump.h>
|
||||
#include "hif.h"
|
||||
#include "coredump.h"
|
||||
#include "debug.h"
|
||||
|
||||
enum
|
||||
ath11k_fw_crash_dump_type ath11k_coredump_get_dump_type(int type)
|
||||
{
|
||||
enum ath11k_fw_crash_dump_type dump_type;
|
||||
|
||||
switch (type) {
|
||||
case HOST_DDR_REGION_TYPE:
|
||||
dump_type = FW_CRASH_DUMP_REMOTE_MEM_DATA;
|
||||
break;
|
||||
case M3_DUMP_REGION_TYPE:
|
||||
dump_type = FW_CRASH_DUMP_M3_DUMP;
|
||||
break;
|
||||
case PAGEABLE_MEM_REGION_TYPE:
|
||||
dump_type = FW_CRASH_DUMP_PAGEABLE_DATA;
|
||||
break;
|
||||
case BDF_MEM_REGION_TYPE:
|
||||
case CALDB_MEM_REGION_TYPE:
|
||||
dump_type = FW_CRASH_DUMP_NONE;
|
||||
break;
|
||||
default:
|
||||
dump_type = FW_CRASH_DUMP_TYPE_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
return dump_type;
|
||||
}
|
||||
EXPORT_SYMBOL(ath11k_coredump_get_dump_type);
|
||||
|
||||
void ath11k_coredump_upload(struct work_struct *work)
|
||||
{
|
||||
struct ath11k_base *ab = container_of(work, struct ath11k_base, dump_work);
|
||||
|
||||
ath11k_info(ab, "Uploading coredump\n");
|
||||
/* dev_coredumpv() takes ownership of the buffer */
|
||||
dev_coredumpv(ab->dev, ab->dump_data, ab->ath11k_coredump_len, GFP_KERNEL);
|
||||
ab->dump_data = NULL;
|
||||
}
|
||||
|
||||
void ath11k_coredump_collect(struct ath11k_base *ab)
|
||||
{
|
||||
ath11k_hif_coredump_download(ab);
|
||||
}
|
||||
79
drivers/net/wireless/ath/ath11k/coredump.h
Normal file
79
drivers/net/wireless/ath/ath11k/coredump.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef _ATH11K_COREDUMP_H_
|
||||
#define _ATH11K_COREDUMP_H_
|
||||
|
||||
#define ATH11K_FW_CRASH_DUMP_V2 2
|
||||
|
||||
enum ath11k_fw_crash_dump_type {
|
||||
FW_CRASH_DUMP_PAGING_DATA,
|
||||
FW_CRASH_DUMP_RDDM_DATA,
|
||||
FW_CRASH_DUMP_REMOTE_MEM_DATA,
|
||||
FW_CRASH_DUMP_PAGEABLE_DATA,
|
||||
FW_CRASH_DUMP_M3_DUMP,
|
||||
FW_CRASH_DUMP_NONE,
|
||||
|
||||
/* keep last */
|
||||
FW_CRASH_DUMP_TYPE_MAX,
|
||||
};
|
||||
|
||||
#define COREDUMP_TLV_HDR_SIZE 8
|
||||
|
||||
struct ath11k_tlv_dump_data {
|
||||
/* see ath11k_fw_crash_dump_type above */
|
||||
__le32 type;
|
||||
|
||||
/* in bytes */
|
||||
__le32 tlv_len;
|
||||
|
||||
/* pad to 32-bit boundaries as needed */
|
||||
u8 tlv_data[];
|
||||
} __packed;
|
||||
|
||||
struct ath11k_dump_file_data {
|
||||
/* "ATH11K-FW-DUMP" */
|
||||
char df_magic[16];
|
||||
/* total dump len in bytes */
|
||||
__le32 len;
|
||||
/* file dump version */
|
||||
__le32 version;
|
||||
/* pci device id */
|
||||
__le32 chip_id;
|
||||
/* qrtr instance id */
|
||||
__le32 qrtr_id;
|
||||
/* pci domain id */
|
||||
__le32 bus_id;
|
||||
guid_t guid;
|
||||
/* time-of-day stamp */
|
||||
__le64 tv_sec;
|
||||
/* time-of-day stamp, nano-seconds */
|
||||
__le64 tv_nsec;
|
||||
/* room for growth w/out changing binary format */
|
||||
u8 unused[128];
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
enum ath11k_fw_crash_dump_type ath11k_coredump_get_dump_type(int type);
|
||||
void ath11k_coredump_upload(struct work_struct *work);
|
||||
void ath11k_coredump_collect(struct ath11k_base *ab);
|
||||
#else
|
||||
static inline enum
|
||||
ath11k_fw_crash_dump_type ath11k_coredump_get_dump_type(int type)
|
||||
{
|
||||
return FW_CRASH_DUMP_TYPE_MAX;
|
||||
}
|
||||
|
||||
static inline void ath11k_coredump_upload(struct work_struct *work)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath11k_coredump_collect(struct ath11k_base *ab)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
@@ -104,14 +104,12 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring)
|
||||
if (!ring->vaddr_unaligned)
|
||||
return;
|
||||
|
||||
if (ring->cached) {
|
||||
dma_unmap_single(ab->dev, ring->paddr_unaligned, ring->size,
|
||||
DMA_FROM_DEVICE);
|
||||
kfree(ring->vaddr_unaligned);
|
||||
} else {
|
||||
if (ring->cached)
|
||||
dma_free_noncoherent(ab->dev, ring->size, ring->vaddr_unaligned,
|
||||
ring->paddr_unaligned, DMA_FROM_DEVICE);
|
||||
else
|
||||
dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned,
|
||||
ring->paddr_unaligned);
|
||||
}
|
||||
|
||||
ring->vaddr_unaligned = NULL;
|
||||
}
|
||||
@@ -249,25 +247,14 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
|
||||
default:
|
||||
cached = false;
|
||||
}
|
||||
|
||||
if (cached) {
|
||||
ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL);
|
||||
if (!ring->vaddr_unaligned)
|
||||
return -ENOMEM;
|
||||
|
||||
ring->paddr_unaligned = dma_map_single(ab->dev,
|
||||
ring->vaddr_unaligned,
|
||||
ring->size,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(ab->dev, ring->paddr_unaligned)) {
|
||||
kfree(ring->vaddr_unaligned);
|
||||
ring->vaddr_unaligned = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached)
|
||||
if (cached)
|
||||
ring->vaddr_unaligned = dma_alloc_noncoherent(ab->dev, ring->size,
|
||||
&ring->paddr_unaligned,
|
||||
DMA_FROM_DEVICE,
|
||||
GFP_KERNEL);
|
||||
else
|
||||
ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size,
|
||||
&ring->paddr_unaligned,
|
||||
GFP_KERNEL);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH11K_DP_H
|
||||
@@ -20,7 +20,6 @@ struct ath11k_ext_irq_grp;
|
||||
|
||||
struct dp_rx_tid {
|
||||
u8 tid;
|
||||
u32 *vaddr;
|
||||
dma_addr_t paddr;
|
||||
u32 size;
|
||||
u32 ba_win_sz;
|
||||
@@ -37,6 +36,9 @@ struct dp_rx_tid {
|
||||
/* Timer info related to fragments */
|
||||
struct timer_list frag_timer;
|
||||
struct ath11k_base *ab;
|
||||
u32 *vaddr_unaligned;
|
||||
dma_addr_t paddr_unaligned;
|
||||
u32 unaligned_size;
|
||||
};
|
||||
|
||||
#define DP_REO_DESC_FREE_THRESHOLD 64
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
@@ -675,11 +675,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
|
||||
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
||||
list_del(&cmd->list);
|
||||
rx_tid = &cmd->data;
|
||||
if (rx_tid->vaddr) {
|
||||
dma_unmap_single(ab->dev, rx_tid->paddr,
|
||||
rx_tid->size, DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
if (rx_tid->vaddr_unaligned) {
|
||||
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||
rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
}
|
||||
kfree(cmd);
|
||||
}
|
||||
@@ -689,11 +689,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
|
||||
list_del(&cmd_cache->list);
|
||||
dp->reo_cmd_cache_flush_count--;
|
||||
rx_tid = &cmd_cache->data;
|
||||
if (rx_tid->vaddr) {
|
||||
dma_unmap_single(ab->dev, rx_tid->paddr,
|
||||
rx_tid->size, DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
if (rx_tid->vaddr_unaligned) {
|
||||
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||
rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
}
|
||||
kfree(cmd_cache);
|
||||
}
|
||||
@@ -708,11 +708,11 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
|
||||
if (status != HAL_REO_CMD_SUCCESS)
|
||||
ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
|
||||
rx_tid->tid, status);
|
||||
if (rx_tid->vaddr) {
|
||||
dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
if (rx_tid->vaddr_unaligned) {
|
||||
dma_free_noncoherent(dp->ab->dev, rx_tid->unaligned_size,
|
||||
rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,10 +749,10 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
|
||||
if (ret) {
|
||||
ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
|
||||
rx_tid->tid, ret);
|
||||
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||
rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,10 +802,10 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
|
||||
|
||||
return;
|
||||
free_desc:
|
||||
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||
rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
}
|
||||
|
||||
void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
||||
@@ -831,14 +831,16 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
||||
if (ret != -ESHUTDOWN)
|
||||
ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
|
||||
tid, ret);
|
||||
dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
dma_free_noncoherent(ar->ab->dev, rx_tid->unaligned_size,
|
||||
rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
}
|
||||
|
||||
rx_tid->paddr = 0;
|
||||
rx_tid->paddr_unaligned = 0;
|
||||
rx_tid->size = 0;
|
||||
rx_tid->unaligned_size = 0;
|
||||
}
|
||||
|
||||
static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
|
||||
@@ -982,10 +984,9 @@ static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
|
||||
if (!rx_tid->active)
|
||||
goto unlock_exit;
|
||||
|
||||
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size, rx_tid->vaddr_unaligned,
|
||||
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||
rx_tid->vaddr_unaligned = NULL;
|
||||
|
||||
rx_tid->active = false;
|
||||
|
||||
@@ -1000,9 +1001,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ath11k_peer *peer;
|
||||
struct dp_rx_tid *rx_tid;
|
||||
u32 hw_desc_sz;
|
||||
u32 *addr_aligned;
|
||||
void *vaddr;
|
||||
u32 hw_desc_sz, *vaddr;
|
||||
void *vaddr_unaligned;
|
||||
dma_addr_t paddr;
|
||||
int ret;
|
||||
|
||||
@@ -1050,49 +1050,40 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
|
||||
else
|
||||
hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
|
||||
|
||||
vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
|
||||
if (!vaddr) {
|
||||
rx_tid->unaligned_size = hw_desc_sz + HAL_LINK_DESC_ALIGN - 1;
|
||||
vaddr_unaligned = dma_alloc_noncoherent(ab->dev, rx_tid->unaligned_size, &paddr,
|
||||
DMA_BIDIRECTIONAL, GFP_ATOMIC);
|
||||
if (!vaddr_unaligned) {
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
|
||||
|
||||
ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz,
|
||||
ssn, pn_type);
|
||||
|
||||
paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
ret = dma_mapping_error(ab->dev, paddr);
|
||||
if (ret) {
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
ath11k_warn(ab, "failed to setup dma map for peer %pM rx tid %d: %d\n",
|
||||
peer_mac, tid, ret);
|
||||
goto err_mem_free;
|
||||
}
|
||||
|
||||
rx_tid->vaddr = vaddr;
|
||||
rx_tid->paddr = paddr;
|
||||
rx_tid->vaddr_unaligned = vaddr_unaligned;
|
||||
vaddr = PTR_ALIGN(vaddr_unaligned, HAL_LINK_DESC_ALIGN);
|
||||
rx_tid->paddr_unaligned = paddr;
|
||||
rx_tid->paddr = rx_tid->paddr_unaligned + ((unsigned long)vaddr -
|
||||
(unsigned long)rx_tid->vaddr_unaligned);
|
||||
ath11k_hal_reo_qdesc_setup(vaddr, tid, ba_win_sz, ssn, pn_type);
|
||||
rx_tid->size = hw_desc_sz;
|
||||
rx_tid->active = true;
|
||||
|
||||
/* After dma_alloc_noncoherent, vaddr is being modified for reo qdesc setup.
|
||||
* Since these changes are not reflected in the device, driver now needs to
|
||||
* explicitly call dma_sync_single_for_device.
|
||||
*/
|
||||
dma_sync_single_for_device(ab->dev, rx_tid->paddr,
|
||||
rx_tid->size,
|
||||
DMA_TO_DEVICE);
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
|
||||
ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
|
||||
paddr, tid, 1, ba_win_sz);
|
||||
ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, rx_tid->paddr,
|
||||
tid, 1, ba_win_sz);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n",
|
||||
peer_mac, tid, ret);
|
||||
ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_mem_free:
|
||||
kfree(rx_tid->vaddr);
|
||||
rx_tid->vaddr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2831,8 +2822,6 @@ static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta,
|
||||
rx_stats->dcm_count += ppdu_info->dcm;
|
||||
rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu;
|
||||
|
||||
arsta->rssi_comb = ppdu_info->rssi_comb;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
|
||||
ARRAY_SIZE(ppdu_info->rssi_chain_pri20));
|
||||
|
||||
@@ -4783,7 +4772,7 @@ u32 ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id,
|
||||
if (!msdu) {
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
|
||||
"msdu_pop: invalid buf_id %d\n", buf_id);
|
||||
break;
|
||||
goto next_msdu;
|
||||
}
|
||||
rxcb = ATH11K_SKB_RXCB(msdu);
|
||||
if (!rxcb->unmapped) {
|
||||
@@ -5148,7 +5137,7 @@ static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id,
|
||||
struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
|
||||
const struct ath11k_hw_hal_params *hal_params;
|
||||
void *ring_entry;
|
||||
void *mon_dst_srng;
|
||||
struct hal_srng *mon_dst_srng;
|
||||
u32 ppdu_id;
|
||||
u32 rx_bufs_used;
|
||||
u32 ring_id;
|
||||
@@ -5165,6 +5154,7 @@ static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id,
|
||||
|
||||
spin_lock_bh(&pmon->mon_lock);
|
||||
|
||||
spin_lock_bh(&mon_dst_srng->lock);
|
||||
ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng);
|
||||
|
||||
ppdu_id = pmon->mon_ppdu_info.ppdu_id;
|
||||
@@ -5223,6 +5213,7 @@ static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id,
|
||||
mon_dst_srng);
|
||||
}
|
||||
ath11k_hal_srng_access_end(ar->ab, mon_dst_srng);
|
||||
spin_unlock_bh(&mon_dst_srng->lock);
|
||||
|
||||
spin_unlock_bh(&pmon->mon_lock);
|
||||
|
||||
@@ -5410,7 +5401,7 @@ ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar,
|
||||
"full mon msdu_pop: invalid buf_id %d\n",
|
||||
buf_id);
|
||||
spin_unlock_bh(&rx_ring->idr_lock);
|
||||
break;
|
||||
goto next_msdu;
|
||||
}
|
||||
idr_remove(&rx_ring->bufs_idr, buf_id);
|
||||
spin_unlock_bh(&rx_ring->idr_lock);
|
||||
@@ -5612,7 +5603,7 @@ static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id,
|
||||
struct hal_sw_mon_ring_entries *sw_mon_entries;
|
||||
struct ath11k_pdev_mon_stats *rx_mon_stats;
|
||||
struct sk_buff *head_msdu, *tail_msdu;
|
||||
void *mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id];
|
||||
struct hal_srng *mon_dst_srng;
|
||||
void *ring_entry;
|
||||
u32 rx_bufs_used = 0, mpdu_rx_bufs_used;
|
||||
int quota = 0, ret;
|
||||
@@ -5628,6 +5619,9 @@ static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id,
|
||||
goto reap_status_ring;
|
||||
}
|
||||
|
||||
mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id];
|
||||
spin_lock_bh(&mon_dst_srng->lock);
|
||||
|
||||
ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng);
|
||||
while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) {
|
||||
head_msdu = NULL;
|
||||
@@ -5671,6 +5665,7 @@ next_entry:
|
||||
}
|
||||
|
||||
ath11k_hal_srng_access_end(ar->ab, mon_dst_srng);
|
||||
spin_unlock_bh(&mon_dst_srng->lock);
|
||||
spin_unlock_bh(&pmon->mon_lock);
|
||||
|
||||
if (rx_bufs_used) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
@@ -166,3 +166,4 @@ void ath11k_fw_destroy(struct ath11k_base *ab)
|
||||
{
|
||||
release_firmware(ab->fw.fw);
|
||||
}
|
||||
EXPORT_SYMBOL(ath11k_fw_destroy);
|
||||
|
||||
@@ -31,6 +31,7 @@ struct ath11k_hif_ops {
|
||||
void (*ce_irq_enable)(struct ath11k_base *ab);
|
||||
void (*ce_irq_disable)(struct ath11k_base *ab);
|
||||
void (*get_ce_msi_idx)(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx);
|
||||
void (*coredump_download)(struct ath11k_base *ab);
|
||||
};
|
||||
|
||||
static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
|
||||
@@ -146,4 +147,10 @@ static inline void ath11k_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
|
||||
*msi_data_idx = ce_id;
|
||||
}
|
||||
|
||||
static inline void ath11k_hif_coredump_download(struct ath11k_base *ab)
|
||||
{
|
||||
if (ab->hif.ops->coredump_download)
|
||||
ab->hif.ops->coredump_download(ab);
|
||||
}
|
||||
|
||||
#endif /* _HIF_H_ */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <net/mac80211.h>
|
||||
@@ -1529,17 +1529,23 @@ static int ath11k_mac_set_vif_params(struct ath11k_vif *arvif,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
|
||||
static struct ath11k_vif *ath11k_mac_get_tx_arvif(struct ath11k_vif *arvif)
|
||||
{
|
||||
if (arvif->vif->mbssid_tx_vif)
|
||||
return ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif,
|
||||
struct ath11k_vif *tx_arvif)
|
||||
{
|
||||
struct ath11k_vif *tx_arvif;
|
||||
struct ieee80211_ema_beacons *beacons;
|
||||
int ret = 0;
|
||||
bool nontx_vif_params_set = false;
|
||||
u32 params = 0;
|
||||
u8 i = 0;
|
||||
|
||||
tx_arvif = ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
|
||||
|
||||
beacons = ieee80211_beacon_get_template_ema_list(tx_arvif->ar->hw,
|
||||
tx_arvif->vif, 0);
|
||||
if (!beacons || !beacons->cnt) {
|
||||
@@ -1585,25 +1591,22 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
|
||||
static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif,
|
||||
struct ath11k_vif *tx_arvif)
|
||||
{
|
||||
struct ath11k *ar = arvif->ar;
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ath11k_vif *tx_arvif = arvif;
|
||||
struct ieee80211_hw *hw = ar->hw;
|
||||
struct ieee80211_vif *vif = arvif->vif;
|
||||
struct ieee80211_mutable_offsets offs = {};
|
||||
struct sk_buff *bcn;
|
||||
int ret;
|
||||
|
||||
if (vif->mbssid_tx_vif) {
|
||||
tx_arvif = ath11k_vif_to_arvif(vif->mbssid_tx_vif);
|
||||
if (tx_arvif != arvif) {
|
||||
ar = tx_arvif->ar;
|
||||
ab = ar->ab;
|
||||
hw = ar->hw;
|
||||
vif = tx_arvif->vif;
|
||||
}
|
||||
if (tx_arvif != arvif) {
|
||||
ar = tx_arvif->ar;
|
||||
ab = ar->ab;
|
||||
hw = ar->hw;
|
||||
vif = tx_arvif->vif;
|
||||
}
|
||||
|
||||
bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0);
|
||||
@@ -1632,6 +1635,7 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
|
||||
static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = arvif->vif;
|
||||
struct ath11k_vif *tx_arvif;
|
||||
|
||||
if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
||||
return 0;
|
||||
@@ -1639,14 +1643,18 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
|
||||
/* Target does not expect beacon templates for the already up
|
||||
* non-transmitting interfaces, and results in a crash if sent.
|
||||
*/
|
||||
if (vif->mbssid_tx_vif &&
|
||||
arvif != ath11k_vif_to_arvif(vif->mbssid_tx_vif) && arvif->is_up)
|
||||
return 0;
|
||||
tx_arvif = ath11k_mac_get_tx_arvif(arvif);
|
||||
if (tx_arvif) {
|
||||
if (arvif != tx_arvif && arvif->is_up)
|
||||
return 0;
|
||||
|
||||
if (vif->bss_conf.ema_ap && vif->mbssid_tx_vif)
|
||||
return ath11k_mac_setup_bcn_tmpl_ema(arvif);
|
||||
if (vif->bss_conf.ema_ap)
|
||||
return ath11k_mac_setup_bcn_tmpl_ema(arvif, tx_arvif);
|
||||
} else {
|
||||
tx_arvif = arvif;
|
||||
}
|
||||
|
||||
return ath11k_mac_setup_bcn_tmpl_mbssid(arvif);
|
||||
return ath11k_mac_setup_bcn_tmpl_mbssid(arvif, tx_arvif);
|
||||
}
|
||||
|
||||
void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif)
|
||||
@@ -1674,7 +1682,7 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif,
|
||||
struct ieee80211_bss_conf *info)
|
||||
{
|
||||
struct ath11k *ar = arvif->ar;
|
||||
struct ath11k_vif *tx_arvif = NULL;
|
||||
struct ath11k_vif *tx_arvif;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&arvif->ar->conf_mutex);
|
||||
@@ -1701,9 +1709,7 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif,
|
||||
|
||||
ether_addr_copy(arvif->bssid, info->bssid);
|
||||
|
||||
if (arvif->vif->mbssid_tx_vif)
|
||||
tx_arvif = ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
|
||||
|
||||
tx_arvif = ath11k_mac_get_tx_arvif(arvif);
|
||||
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||
arvif->bssid,
|
||||
tx_arvif ? tx_arvif->bssid : NULL,
|
||||
@@ -5204,6 +5210,45 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_mac_op_conf_tx_mu_edca(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
unsigned int link_id, u16 ac,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
|
||||
struct ath11k *ar = hw->priv;
|
||||
struct wmi_wmm_params_arg *p;
|
||||
int ret;
|
||||
|
||||
switch (ac) {
|
||||
case IEEE80211_AC_VO:
|
||||
p = &arvif->muedca_params.ac_vo;
|
||||
break;
|
||||
case IEEE80211_AC_VI:
|
||||
p = &arvif->muedca_params.ac_vi;
|
||||
break;
|
||||
case IEEE80211_AC_BE:
|
||||
p = &arvif->muedca_params.ac_be;
|
||||
break;
|
||||
case IEEE80211_AC_BK:
|
||||
p = &arvif->muedca_params.ac_bk;
|
||||
break;
|
||||
default:
|
||||
ath11k_warn(ar->ab, "error ac: %d", ac);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p->cwmin = u8_get_bits(params->mu_edca_param_rec.ecw_min_max, GENMASK(3, 0));
|
||||
p->cwmax = u8_get_bits(params->mu_edca_param_rec.ecw_min_max, GENMASK(7, 4));
|
||||
p->aifs = u8_get_bits(params->mu_edca_param_rec.aifsn, GENMASK(3, 0));
|
||||
p->txop = params->mu_edca_param_rec.mu_edca_timer;
|
||||
|
||||
ret = ath11k_wmi_send_wmm_update_cmd_tlv(ar, arvif->vdev_id,
|
||||
&arvif->muedca_params,
|
||||
WMI_WMM_PARAM_TYPE_11AX_MU_EDCA);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
unsigned int link_id, u16 ac,
|
||||
@@ -5242,12 +5287,22 @@ static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
|
||||
p->txop = params->txop;
|
||||
|
||||
ret = ath11k_wmi_send_wmm_update_cmd_tlv(ar, arvif->vdev_id,
|
||||
&arvif->wmm_params);
|
||||
&arvif->wmm_params,
|
||||
WMI_WMM_PARAM_TYPE_LEGACY);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to set wmm params: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (params->mu_edca) {
|
||||
ret = ath11k_mac_op_conf_tx_mu_edca(hw, vif, link_id, ac,
|
||||
params);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to set mu_edca params: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath11k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
|
||||
|
||||
if (ret)
|
||||
@@ -5336,8 +5391,6 @@ static int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
|
||||
if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) {
|
||||
nsts = vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
||||
nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
||||
if (nsts > (ar->num_rx_chains - 1))
|
||||
nsts = ar->num_rx_chains - 1;
|
||||
value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
|
||||
}
|
||||
|
||||
@@ -5421,9 +5474,6 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
|
||||
|
||||
/* Enable Beamformee STS Field only if SU BF is enabled */
|
||||
if (subfee) {
|
||||
if (nsts > (ar->num_rx_chains - 1))
|
||||
nsts = ar->num_rx_chains - 1;
|
||||
|
||||
nsts <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
||||
nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
||||
*vht_cap |= nsts;
|
||||
@@ -6288,6 +6338,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
|
||||
{
|
||||
struct ath11k *ar = hw->priv;
|
||||
struct htt_ppdu_stats_info *ppdu_stats, *tmp;
|
||||
struct scan_chan_list_params *params;
|
||||
int ret;
|
||||
|
||||
ath11k_mac_drain_tx(ar);
|
||||
@@ -6303,6 +6354,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&ar->scan.timeout);
|
||||
cancel_work_sync(&ar->channel_update_work);
|
||||
cancel_work_sync(&ar->regd_update_work);
|
||||
cancel_work_sync(&ar->ab->update_11d_work);
|
||||
|
||||
@@ -6312,10 +6364,19 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
|
||||
list_del(&ppdu_stats->list);
|
||||
kfree(ppdu_stats);
|
||||
}
|
||||
|
||||
while ((params = list_first_entry_or_null(&ar->channel_update_queue,
|
||||
struct scan_chan_list_params,
|
||||
list))) {
|
||||
list_del(¶ms->list);
|
||||
kfree(params);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL);
|
||||
@@ -6330,23 +6391,20 @@ static int ath11k_mac_setup_vdev_params_mbssid(struct ath11k_vif *arvif,
|
||||
{
|
||||
struct ath11k *ar = arvif->ar;
|
||||
struct ath11k_vif *tx_arvif;
|
||||
struct ieee80211_vif *tx_vif;
|
||||
|
||||
*tx_vdev_id = 0;
|
||||
tx_vif = arvif->vif->mbssid_tx_vif;
|
||||
if (!tx_vif) {
|
||||
tx_arvif = ath11k_mac_get_tx_arvif(arvif);
|
||||
if (!tx_arvif) {
|
||||
*flags = WMI_HOST_VDEV_FLAGS_NON_MBSSID_AP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tx_arvif = ath11k_vif_to_arvif(tx_vif);
|
||||
|
||||
if (arvif->vif->bss_conf.nontransmitted) {
|
||||
if (ar->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy)
|
||||
if (ar->hw->wiphy != tx_arvif->ar->hw->wiphy)
|
||||
return -EINVAL;
|
||||
|
||||
*flags = WMI_HOST_VDEV_FLAGS_NON_TRANSMIT_AP;
|
||||
*tx_vdev_id = ath11k_vif_to_arvif(tx_vif)->vdev_id;
|
||||
*tx_vdev_id = tx_arvif->vdev_id;
|
||||
} else if (tx_arvif == arvif) {
|
||||
*flags = WMI_HOST_VDEV_FLAGS_TRANSMIT_AP;
|
||||
} else {
|
||||
@@ -7306,8 +7364,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
|
||||
int n_vifs)
|
||||
{
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ath11k_vif *arvif, *tx_arvif = NULL;
|
||||
struct ieee80211_vif *mbssid_tx_vif;
|
||||
struct ath11k_vif *arvif, *tx_arvif;
|
||||
int ret;
|
||||
int i;
|
||||
bool monitor_vif = false;
|
||||
@@ -7361,10 +7418,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
|
||||
ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
|
||||
ret);
|
||||
|
||||
mbssid_tx_vif = arvif->vif->mbssid_tx_vif;
|
||||
if (mbssid_tx_vif)
|
||||
tx_arvif = ath11k_vif_to_arvif(mbssid_tx_vif);
|
||||
|
||||
tx_arvif = ath11k_mac_get_tx_arvif(arvif);
|
||||
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||
arvif->bssid,
|
||||
tx_arvif ? tx_arvif->bssid : NULL,
|
||||
@@ -10019,6 +10073,7 @@ static const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = {
|
||||
|
||||
static void __ath11k_mac_unregister(struct ath11k *ar)
|
||||
{
|
||||
cancel_work_sync(&ar->channel_update_work);
|
||||
cancel_work_sync(&ar->regd_update_work);
|
||||
|
||||
ieee80211_unregister_hw(ar->hw);
|
||||
@@ -10418,6 +10473,8 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
|
||||
init_completion(&ar->thermal.wmi_sync);
|
||||
|
||||
INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work);
|
||||
INIT_WORK(&ar->channel_update_work, ath11k_regd_update_chan_list_work);
|
||||
INIT_LIST_HEAD(&ar->channel_update_queue);
|
||||
INIT_WORK(&ar->regd_update_work, ath11k_regd_update_work);
|
||||
|
||||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work);
|
||||
|
||||
@@ -491,3 +491,8 @@ int ath11k_mhi_resume(struct ath11k_pci *ab_pci)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath11k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic)
|
||||
{
|
||||
mhi_download_rddm_image(mhi_ctrl, in_panic);
|
||||
}
|
||||
|
||||
@@ -26,5 +26,6 @@ void ath11k_mhi_clear_vector(struct ath11k_base *ab);
|
||||
|
||||
int ath11k_mhi_suspend(struct ath11k_pci *ar_pci);
|
||||
int ath11k_mhi_resume(struct ath11k_pci *ar_pci);
|
||||
void ath11k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "pci.h"
|
||||
#include "core.h"
|
||||
@@ -610,6 +612,187 @@ static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
|
||||
PCI_EXP_LNKCTL_ASPMC);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
static int ath11k_pci_coredump_calculate_size(struct ath11k_base *ab, u32 *dump_seg_sz)
|
||||
{
|
||||
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||
struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
|
||||
struct image_info *rddm_img, *fw_img;
|
||||
struct ath11k_tlv_dump_data *dump_tlv;
|
||||
enum ath11k_fw_crash_dump_type mem_type;
|
||||
u32 len = 0, rddm_tlv_sz = 0, paging_tlv_sz = 0;
|
||||
struct ath11k_dump_file_data *file_data;
|
||||
int i;
|
||||
|
||||
rddm_img = mhi_ctrl->rddm_image;
|
||||
if (!rddm_img) {
|
||||
ath11k_err(ab, "No RDDM dump found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fw_img = mhi_ctrl->fbc_image;
|
||||
|
||||
for (i = 0; i < fw_img->entries ; i++) {
|
||||
if (!fw_img->mhi_buf[i].buf)
|
||||
continue;
|
||||
|
||||
paging_tlv_sz += fw_img->mhi_buf[i].len;
|
||||
}
|
||||
dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA] = paging_tlv_sz;
|
||||
|
||||
for (i = 0; i < rddm_img->entries; i++) {
|
||||
if (!rddm_img->mhi_buf[i].buf)
|
||||
continue;
|
||||
|
||||
rddm_tlv_sz += rddm_img->mhi_buf[i].len;
|
||||
}
|
||||
dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA] = rddm_tlv_sz;
|
||||
|
||||
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||
mem_type = ath11k_coredump_get_dump_type(ab->qmi.target_mem[i].type);
|
||||
|
||||
if (mem_type == FW_CRASH_DUMP_NONE)
|
||||
continue;
|
||||
|
||||
if (mem_type == FW_CRASH_DUMP_TYPE_MAX) {
|
||||
ath11k_dbg(ab, ATH11K_DBG_PCI,
|
||||
"target mem region type %d not supported",
|
||||
ab->qmi.target_mem[i].type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ab->qmi.target_mem[i].anyaddr)
|
||||
continue;
|
||||
|
||||
dump_seg_sz[mem_type] += ab->qmi.target_mem[i].size;
|
||||
}
|
||||
|
||||
for (i = 0; i < FW_CRASH_DUMP_TYPE_MAX; i++) {
|
||||
if (!dump_seg_sz[i])
|
||||
continue;
|
||||
|
||||
len += sizeof(*dump_tlv) + dump_seg_sz[i];
|
||||
}
|
||||
|
||||
if (len)
|
||||
len += sizeof(*file_data);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ath11k_pci_coredump_download(struct ath11k_base *ab)
|
||||
{
|
||||
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||
struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
|
||||
struct image_info *rddm_img, *fw_img;
|
||||
struct timespec64 timestamp;
|
||||
int i, len, mem_idx;
|
||||
enum ath11k_fw_crash_dump_type mem_type;
|
||||
struct ath11k_dump_file_data *file_data;
|
||||
struct ath11k_tlv_dump_data *dump_tlv;
|
||||
size_t hdr_len = sizeof(*file_data);
|
||||
void *buf;
|
||||
u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 };
|
||||
|
||||
ath11k_mhi_coredump(mhi_ctrl, false);
|
||||
|
||||
len = ath11k_pci_coredump_calculate_size(ab, dump_seg_sz);
|
||||
if (!len) {
|
||||
ath11k_warn(ab, "No crash dump data found for devcoredump");
|
||||
return;
|
||||
}
|
||||
|
||||
rddm_img = mhi_ctrl->rddm_image;
|
||||
fw_img = mhi_ctrl->fbc_image;
|
||||
|
||||
/* dev_coredumpv() requires vmalloc data */
|
||||
buf = vzalloc(len);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
ab->dump_data = buf;
|
||||
ab->ath11k_coredump_len = len;
|
||||
file_data = ab->dump_data;
|
||||
strscpy(file_data->df_magic, "ATH11K-FW-DUMP", sizeof(file_data->df_magic));
|
||||
file_data->len = cpu_to_le32(len);
|
||||
file_data->version = cpu_to_le32(ATH11K_FW_CRASH_DUMP_V2);
|
||||
file_data->chip_id = cpu_to_le32(ab_pci->dev_id);
|
||||
file_data->qrtr_id = cpu_to_le32(ab_pci->ab->qmi.service_ins_id);
|
||||
file_data->bus_id = cpu_to_le32(pci_domain_nr(ab_pci->pdev->bus));
|
||||
guid_gen(&file_data->guid);
|
||||
ktime_get_real_ts64(×tamp);
|
||||
file_data->tv_sec = cpu_to_le64(timestamp.tv_sec);
|
||||
file_data->tv_nsec = cpu_to_le64(timestamp.tv_nsec);
|
||||
buf += hdr_len;
|
||||
dump_tlv = buf;
|
||||
dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_PAGING_DATA);
|
||||
dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA]);
|
||||
buf += COREDUMP_TLV_HDR_SIZE;
|
||||
|
||||
/* append all segments together as they are all part of a single contiguous
|
||||
* block of memory
|
||||
*/
|
||||
for (i = 0; i < fw_img->entries ; i++) {
|
||||
if (!fw_img->mhi_buf[i].buf)
|
||||
continue;
|
||||
|
||||
memcpy_fromio(buf, (void const __iomem *)fw_img->mhi_buf[i].buf,
|
||||
fw_img->mhi_buf[i].len);
|
||||
buf += fw_img->mhi_buf[i].len;
|
||||
}
|
||||
|
||||
dump_tlv = buf;
|
||||
dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_RDDM_DATA);
|
||||
dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA]);
|
||||
buf += COREDUMP_TLV_HDR_SIZE;
|
||||
|
||||
/* append all segments together as they are all part of a single contiguous
|
||||
* block of memory
|
||||
*/
|
||||
for (i = 0; i < rddm_img->entries; i++) {
|
||||
if (!rddm_img->mhi_buf[i].buf)
|
||||
continue;
|
||||
|
||||
memcpy_fromio(buf, (void const __iomem *)rddm_img->mhi_buf[i].buf,
|
||||
rddm_img->mhi_buf[i].len);
|
||||
buf += rddm_img->mhi_buf[i].len;
|
||||
}
|
||||
|
||||
mem_idx = FW_CRASH_DUMP_REMOTE_MEM_DATA;
|
||||
for (; mem_idx < FW_CRASH_DUMP_TYPE_MAX; mem_idx++) {
|
||||
if (mem_idx == FW_CRASH_DUMP_NONE)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||
mem_type = ath11k_coredump_get_dump_type
|
||||
(ab->qmi.target_mem[i].type);
|
||||
|
||||
if (mem_type != mem_idx)
|
||||
continue;
|
||||
|
||||
if (!ab->qmi.target_mem[i].anyaddr) {
|
||||
ath11k_dbg(ab, ATH11K_DBG_PCI,
|
||||
"Skipping mem region type %d",
|
||||
ab->qmi.target_mem[i].type);
|
||||
continue;
|
||||
}
|
||||
|
||||
dump_tlv = buf;
|
||||
dump_tlv->type = cpu_to_le32(mem_idx);
|
||||
dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[mem_idx]);
|
||||
buf += COREDUMP_TLV_HDR_SIZE;
|
||||
|
||||
memcpy_fromio(buf, ab->qmi.target_mem[i].iaddr,
|
||||
ab->qmi.target_mem[i].size);
|
||||
|
||||
buf += ab->qmi.target_mem[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
queue_work(ab->workqueue, &ab->dump_work);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ath11k_pci_power_up(struct ath11k_base *ab)
|
||||
{
|
||||
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||
@@ -713,6 +896,9 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
|
||||
.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
|
||||
.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
|
||||
.get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx,
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
.coredump_download = ath11k_pci_coredump_download,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
|
||||
@@ -735,7 +921,7 @@ static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,
|
||||
if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab_pci->ab->dev_flags))
|
||||
return 0;
|
||||
|
||||
return irq_set_affinity_hint(ab_pci->pdev->irq, m);
|
||||
return irq_set_affinity_and_hint(ab_pci->pdev->irq, m);
|
||||
}
|
||||
|
||||
static int ath11k_pci_probe(struct pci_dev *pdev,
|
||||
@@ -939,6 +1125,8 @@ unsupported_wcn6855_soc:
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
/* __free_irq() expects the caller to have cleared the affinity hint */
|
||||
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
|
||||
ath11k_pcic_free_irq(ab);
|
||||
|
||||
err_ce_free:
|
||||
@@ -981,9 +1169,12 @@ static void ath11k_pci_remove(struct pci_dev *pdev)
|
||||
|
||||
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
|
||||
|
||||
cancel_work_sync(&ab->reset_work);
|
||||
cancel_work_sync(&ab->dump_work);
|
||||
ath11k_core_deinit(ab);
|
||||
|
||||
qmi_fail:
|
||||
ath11k_fw_destroy(ab);
|
||||
ath11k_mhi_unregister(ab_pci);
|
||||
|
||||
ath11k_pcic_free_irq(ab);
|
||||
|
||||
@@ -1957,14 +1957,16 @@ static void ath11k_qmi_free_target_mem_chunk(struct ath11k_base *ab)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||
if ((ab->hw_params.fixed_mem_region ||
|
||||
test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) &&
|
||||
ab->qmi.target_mem[i].iaddr)
|
||||
iounmap(ab->qmi.target_mem[i].iaddr);
|
||||
|
||||
if (!ab->qmi.target_mem[i].vaddr)
|
||||
if (!ab->qmi.target_mem[i].anyaddr)
|
||||
continue;
|
||||
|
||||
if (ab->hw_params.fixed_mem_region ||
|
||||
test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
|
||||
iounmap(ab->qmi.target_mem[i].iaddr);
|
||||
ab->qmi.target_mem[i].iaddr = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
dma_free_coherent(ab->dev,
|
||||
ab->qmi.target_mem[i].prev_size,
|
||||
ab->qmi.target_mem[i].vaddr,
|
||||
@@ -2070,7 +2072,7 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
||||
break;
|
||||
case BDF_MEM_REGION_TYPE:
|
||||
ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr;
|
||||
ab->qmi.target_mem[idx].vaddr = NULL;
|
||||
ab->qmi.target_mem[idx].iaddr = NULL;
|
||||
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||
idx++;
|
||||
@@ -2093,10 +2095,11 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
||||
} else {
|
||||
ab->qmi.target_mem[idx].paddr =
|
||||
ATH11K_QMI_CALDB_ADDRESS;
|
||||
ab->qmi.target_mem[idx].iaddr = NULL;
|
||||
}
|
||||
} else {
|
||||
ab->qmi.target_mem[idx].paddr = 0;
|
||||
ab->qmi.target_mem[idx].vaddr = NULL;
|
||||
ab->qmi.target_mem[idx].iaddr = NULL;
|
||||
}
|
||||
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH11K_QMI_H
|
||||
@@ -102,8 +102,11 @@ struct target_mem_chunk {
|
||||
u32 prev_size;
|
||||
u32 prev_type;
|
||||
dma_addr_t paddr;
|
||||
u32 *vaddr;
|
||||
void __iomem *iaddr;
|
||||
union {
|
||||
u32 *vaddr;
|
||||
void __iomem *iaddr;
|
||||
void *anyaddr;
|
||||
};
|
||||
};
|
||||
|
||||
struct target_info {
|
||||
@@ -154,6 +157,7 @@ struct ath11k_qmi {
|
||||
#define BDF_MEM_REGION_TYPE 0x2
|
||||
#define M3_DUMP_REGION_TYPE 0x3
|
||||
#define CALDB_MEM_REGION_TYPE 0x4
|
||||
#define PAGEABLE_MEM_REGION_TYPE 0x9
|
||||
|
||||
struct qmi_wlanfw_host_cap_req_msg_v01 {
|
||||
u8 num_clients_valid;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
@@ -55,6 +55,19 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"Regulatory Notification received for %s\n", wiphy_name(wiphy));
|
||||
|
||||
if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"driver initiated regd update\n");
|
||||
if (ar->state != ATH11K_STATE_ON)
|
||||
return;
|
||||
|
||||
ret = ath11k_reg_update_chan_list(ar, true);
|
||||
if (ret)
|
||||
ath11k_warn(ar->ab, "failed to update channel list: %d\n", ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Currently supporting only General User Hints. Cell base user
|
||||
* hints to be handled later.
|
||||
* Hints from other sources like Core, Beacons are not expected for
|
||||
@@ -111,32 +124,7 @@ int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait)
|
||||
struct channel_param *ch;
|
||||
enum nl80211_band band;
|
||||
int num_channels = 0;
|
||||
int i, ret, left;
|
||||
|
||||
if (wait && ar->state_11d != ATH11K_11D_IDLE) {
|
||||
left = wait_for_completion_timeout(&ar->completed_11d_scan,
|
||||
ATH11K_SCAN_TIMEOUT_HZ);
|
||||
if (!left) {
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"failed to receive 11d scan complete: timed out\n");
|
||||
ar->state_11d = ATH11K_11D_IDLE;
|
||||
}
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"11d scan wait left time %d\n", left);
|
||||
}
|
||||
|
||||
if (wait &&
|
||||
(ar->scan.state == ATH11K_SCAN_STARTING ||
|
||||
ar->scan.state == ATH11K_SCAN_RUNNING)) {
|
||||
left = wait_for_completion_timeout(&ar->scan.completed,
|
||||
ATH11K_SCAN_TIMEOUT_HZ);
|
||||
if (!left)
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"failed to receive hw scan complete: timed out\n");
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"hw scan wait left time %d\n", left);
|
||||
}
|
||||
int i, ret = 0;
|
||||
|
||||
if (ar->state == ATH11K_STATE_RESTARTING)
|
||||
return 0;
|
||||
@@ -218,6 +206,16 @@ int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait)
|
||||
}
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
list_add_tail(¶ms->list, &ar->channel_update_queue);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
queue_work(ar->ab->workqueue, &ar->channel_update_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params);
|
||||
kfree(params);
|
||||
|
||||
@@ -293,12 +291,6 @@ int ath11k_regd_update(struct ath11k *ar)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (ar->state == ATH11K_STATE_ON) {
|
||||
ret = ath11k_reg_update_chan_list(ar, true);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
ath11k_warn(ab, "failed to perform regd update : %d\n", ret);
|
||||
@@ -804,6 +796,54 @@ ret:
|
||||
return new_regd;
|
||||
}
|
||||
|
||||
void ath11k_regd_update_chan_list_work(struct work_struct *work)
|
||||
{
|
||||
struct ath11k *ar = container_of(work, struct ath11k,
|
||||
channel_update_work);
|
||||
struct scan_chan_list_params *params;
|
||||
struct list_head local_update_list;
|
||||
int left;
|
||||
|
||||
INIT_LIST_HEAD(&local_update_list);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
list_splice_tail_init(&ar->channel_update_queue, &local_update_list);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
while ((params = list_first_entry_or_null(&local_update_list,
|
||||
struct scan_chan_list_params,
|
||||
list))) {
|
||||
if (ar->state_11d != ATH11K_11D_IDLE) {
|
||||
left = wait_for_completion_timeout(&ar->completed_11d_scan,
|
||||
ATH11K_SCAN_TIMEOUT_HZ);
|
||||
if (!left) {
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"failed to receive 11d scan complete: timed out\n");
|
||||
ar->state_11d = ATH11K_11D_IDLE;
|
||||
}
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"reg 11d scan wait left time %d\n", left);
|
||||
}
|
||||
|
||||
if ((ar->scan.state == ATH11K_SCAN_STARTING ||
|
||||
ar->scan.state == ATH11K_SCAN_RUNNING)) {
|
||||
left = wait_for_completion_timeout(&ar->scan.completed,
|
||||
ATH11K_SCAN_TIMEOUT_HZ);
|
||||
if (!left)
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"failed to receive hw scan complete: timed out\n");
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_REG,
|
||||
"reg hw scan wait left time %d\n", left);
|
||||
}
|
||||
|
||||
ath11k_wmi_send_scan_chan_list_cmd(ar, params);
|
||||
list_del(¶ms->list);
|
||||
kfree(params);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ath11k_reg_is_world_alpha(char *alpha)
|
||||
{
|
||||
if (alpha[0] == '0' && alpha[1] == '0')
|
||||
@@ -977,6 +1017,7 @@ void ath11k_regd_update_work(struct work_struct *work)
|
||||
void ath11k_reg_init(struct ath11k *ar)
|
||||
{
|
||||
ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
|
||||
ar->hw->wiphy->flags |= WIPHY_FLAG_NOTIFY_REGDOM_BY_DRIVER;
|
||||
ar->hw->wiphy->reg_notifier = ath11k_reg_notifier;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH11K_REG_H
|
||||
@@ -33,6 +33,7 @@ void ath11k_reg_init(struct ath11k *ar);
|
||||
void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info);
|
||||
void ath11k_reg_free(struct ath11k_base *ab);
|
||||
void ath11k_regd_update_work(struct work_struct *work);
|
||||
void ath11k_regd_update_chan_list_work(struct work_struct *work);
|
||||
struct ieee80211_regdomain *
|
||||
ath11k_reg_build_regd(struct ath11k_base *ab,
|
||||
struct cur_regulatory_info *reg_info, bool intersect,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "testmode.h"
|
||||
@@ -10,18 +10,18 @@
|
||||
#include "wmi.h"
|
||||
#include "hw.h"
|
||||
#include "core.h"
|
||||
#include "testmode_i.h"
|
||||
#include "../testmode_i.h"
|
||||
|
||||
#define ATH11K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0)
|
||||
#define ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4)
|
||||
|
||||
static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = {
|
||||
[ATH11K_TM_ATTR_CMD] = { .type = NLA_U32 },
|
||||
[ATH11K_TM_ATTR_DATA] = { .type = NLA_BINARY,
|
||||
.len = ATH11K_TM_DATA_MAX_LEN },
|
||||
[ATH11K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
|
||||
[ATH11K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
|
||||
[ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
|
||||
static const struct nla_policy ath11k_tm_policy[ATH_TM_ATTR_MAX + 1] = {
|
||||
[ATH_TM_ATTR_CMD] = { .type = NLA_U32 },
|
||||
[ATH_TM_ATTR_DATA] = { .type = NLA_BINARY,
|
||||
.len = ATH_TM_DATA_MAX_LEN },
|
||||
[ATH_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
|
||||
[ATH_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
|
||||
[ATH_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static struct ath11k *ath11k_tm_get_ar(struct ath11k_base *ab)
|
||||
@@ -73,9 +73,9 @@ static void ath11k_tm_wmi_event_unsegmented(struct ath11k_base *ab, u32 cmd_id,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI) ||
|
||||
nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||
nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data)) {
|
||||
if (nla_put_u32(nl_skb, ATH_TM_ATTR_CMD, ATH_TM_CMD_WMI) ||
|
||||
nla_put_u32(nl_skb, ATH_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||
nla_put(nl_skb, ATH_TM_ATTR_DATA, skb->len, skb->data)) {
|
||||
ath11k_warn(ab, "failed to populate testmode unsegmented event\n");
|
||||
kfree_skb(nl_skb);
|
||||
goto out;
|
||||
@@ -140,7 +140,7 @@ static int ath11k_tm_process_event(struct ath11k_base *ab, u32 cmd_id,
|
||||
|
||||
data_pos = ab->testmode.data_pos;
|
||||
|
||||
if ((data_pos + datalen) > ATH11K_FTM_EVENT_MAX_BUF_LENGTH) {
|
||||
if ((data_pos + datalen) > ATH_FTM_EVENT_MAX_BUF_LENGTH) {
|
||||
ath11k_warn(ab, "Invalid ftm event length at %d: %d\n",
|
||||
data_pos, datalen);
|
||||
ret = -EINVAL;
|
||||
@@ -172,10 +172,10 @@ static int ath11k_tm_process_event(struct ath11k_base *ab, u32 cmd_id,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD,
|
||||
ATH11K_TM_CMD_WMI_FTM) ||
|
||||
nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||
nla_put(nl_skb, ATH11K_TM_ATTR_DATA, data_pos,
|
||||
if (nla_put_u32(nl_skb, ATH_TM_ATTR_CMD,
|
||||
ATH_TM_CMD_WMI_FTM) ||
|
||||
nla_put_u32(nl_skb, ATH_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||
nla_put(nl_skb, ATH_TM_ATTR_DATA, data_pos,
|
||||
&ab->testmode.eventdata[0])) {
|
||||
ath11k_warn(ab, "failed to populate segmented testmode event");
|
||||
kfree_skb(nl_skb);
|
||||
@@ -235,23 +235,23 @@ static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
||||
"cmd get version_major %d version_minor %d\n",
|
||||
ATH11K_TESTMODE_VERSION_MAJOR,
|
||||
ATH11K_TESTMODE_VERSION_MINOR);
|
||||
ATH_TESTMODE_VERSION_MAJOR,
|
||||
ATH_TESTMODE_VERSION_MINOR);
|
||||
|
||||
skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
|
||||
nla_total_size(sizeof(u32)));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nla_put_u32(skb, ATH11K_TM_ATTR_VERSION_MAJOR,
|
||||
ATH11K_TESTMODE_VERSION_MAJOR);
|
||||
ret = nla_put_u32(skb, ATH_TM_ATTR_VERSION_MAJOR,
|
||||
ATH_TESTMODE_VERSION_MAJOR);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nla_put_u32(skb, ATH11K_TM_ATTR_VERSION_MINOR,
|
||||
ATH11K_TESTMODE_VERSION_MINOR);
|
||||
ret = nla_put_u32(skb, ATH_TM_ATTR_VERSION_MINOR,
|
||||
ATH_TESTMODE_VERSION_MINOR);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
@@ -277,7 +277,7 @@ static int ath11k_tm_cmd_testmode_start(struct ath11k *ar, struct nlattr *tb[])
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->ab->testmode.eventdata = kzalloc(ATH11K_FTM_EVENT_MAX_BUF_LENGTH,
|
||||
ar->ab->testmode.eventdata = kzalloc(ATH_FTM_EVENT_MAX_BUF_LENGTH,
|
||||
GFP_KERNEL);
|
||||
if (!ar->ab->testmode.eventdata) {
|
||||
ret = -ENOMEM;
|
||||
@@ -310,25 +310,25 @@ static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[],
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (!tb[ATH11K_TM_ATTR_DATA]) {
|
||||
if (!tb[ATH_TM_ATTR_DATA]) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!tb[ATH11K_TM_ATTR_WMI_CMDID]) {
|
||||
if (!tb[ATH_TM_ATTR_WMI_CMDID]) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
|
||||
buf = nla_data(tb[ATH_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH_TM_ATTR_DATA]);
|
||||
if (!buf_len) {
|
||||
ath11k_warn(ar->ab, "No data present in testmode wmi command\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]);
|
||||
cmd_id = nla_get_u32(tb[ATH_TM_ATTR_WMI_CMDID]);
|
||||
|
||||
/* Make sure that the buffer length is long enough to
|
||||
* hold TLV and pdev/vdev id.
|
||||
@@ -409,13 +409,13 @@ static int ath11k_tm_cmd_wmi_ftm(struct ath11k *ar, struct nlattr *tb[])
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!tb[ATH11K_TM_ATTR_DATA]) {
|
||||
if (!tb[ATH_TM_ATTR_DATA]) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
|
||||
buf = nla_data(tb[ATH_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH_TM_ATTR_DATA]);
|
||||
cmd_id = WMI_PDEV_UTF_CMDID;
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
||||
@@ -476,25 +476,25 @@ int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
void *data, int len)
|
||||
{
|
||||
struct ath11k *ar = hw->priv;
|
||||
struct nlattr *tb[ATH11K_TM_ATTR_MAX + 1];
|
||||
struct nlattr *tb[ATH_TM_ATTR_MAX + 1];
|
||||
int ret;
|
||||
|
||||
ret = nla_parse(tb, ATH11K_TM_ATTR_MAX, data, len, ath11k_tm_policy,
|
||||
ret = nla_parse(tb, ATH_TM_ATTR_MAX, data, len, ath11k_tm_policy,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!tb[ATH11K_TM_ATTR_CMD])
|
||||
if (!tb[ATH_TM_ATTR_CMD])
|
||||
return -EINVAL;
|
||||
|
||||
switch (nla_get_u32(tb[ATH11K_TM_ATTR_CMD])) {
|
||||
case ATH11K_TM_CMD_GET_VERSION:
|
||||
switch (nla_get_u32(tb[ATH_TM_ATTR_CMD])) {
|
||||
case ATH_TM_CMD_GET_VERSION:
|
||||
return ath11k_tm_cmd_get_version(ar, tb);
|
||||
case ATH11K_TM_CMD_WMI:
|
||||
case ATH_TM_CMD_WMI:
|
||||
return ath11k_tm_cmd_wmi(ar, tb, vif);
|
||||
case ATH11K_TM_CMD_TESTMODE_START:
|
||||
case ATH_TM_CMD_TESTMODE_START:
|
||||
return ath11k_tm_cmd_testmode_start(ar, tb);
|
||||
case ATH11K_TM_CMD_WMI_FTM:
|
||||
case ATH_TM_CMD_WMI_FTM:
|
||||
return ath11k_tm_cmd_wmi_ftm(ar, tb);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ctype.h>
|
||||
@@ -2662,7 +2662,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
|
||||
}
|
||||
|
||||
int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
|
||||
struct wmi_wmm_params_all_arg *param)
|
||||
struct wmi_wmm_params_all_arg *param,
|
||||
enum wmi_wmm_params_type wmm_param_type)
|
||||
{
|
||||
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||
struct wmi_vdev_set_wmm_params_cmd *cmd;
|
||||
@@ -2681,7 +2682,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
|
||||
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||
|
||||
cmd->vdev_id = vdev_id;
|
||||
cmd->wmm_param_type = 0;
|
||||
cmd->wmm_param_type = wmm_param_type;
|
||||
|
||||
for (ac = 0; ac < WME_NUM_AC; ac++) {
|
||||
switch (ac) {
|
||||
@@ -2714,8 +2715,8 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
|
||||
wmm_param->no_ack = wmi_wmm_arg->no_ack;
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
||||
"wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n",
|
||||
ac, wmm_param->aifs, wmm_param->cwmin,
|
||||
"wmm set type %d ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n",
|
||||
wmm_param_type, ac, wmm_param->aifs, wmm_param->cwmin,
|
||||
wmm_param->cwmax, wmm_param->txoplimit,
|
||||
wmm_param->acm, wmm_param->no_ack);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH11K_WMI_H
|
||||
@@ -3817,6 +3817,7 @@ struct wmi_stop_scan_cmd {
|
||||
};
|
||||
|
||||
struct scan_chan_list_params {
|
||||
struct list_head list;
|
||||
u32 pdev_id;
|
||||
u16 nallchans;
|
||||
struct channel_param ch_param[];
|
||||
@@ -6346,6 +6347,11 @@ enum wmi_sta_keepalive_method {
|
||||
#define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30
|
||||
#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
|
||||
|
||||
enum wmi_wmm_params_type {
|
||||
WMI_WMM_PARAM_TYPE_LEGACY = 0,
|
||||
WMI_WMM_PARAM_TYPE_11AX_MU_EDCA = 1,
|
||||
};
|
||||
|
||||
const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,
|
||||
struct sk_buff *skb, gfp_t gfp);
|
||||
int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
|
||||
@@ -6402,7 +6408,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|
||||
int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar,
|
||||
struct scan_cancel_param *param);
|
||||
int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
|
||||
struct wmi_wmm_params_all_arg *param);
|
||||
struct wmi_wmm_params_all_arg *param,
|
||||
enum wmi_wmm_params_type wmm_param_type);
|
||||
int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt,
|
||||
u32 pdev_id);
|
||||
int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id);
|
||||
|
||||
@@ -23,11 +23,12 @@ ath12k-y += core.o \
|
||||
fw.o \
|
||||
p2p.o
|
||||
|
||||
ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o
|
||||
ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
|
||||
ath12k-$(CONFIG_ACPI) += acpi.o
|
||||
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
|
||||
ath12k-$(CONFIG_PM) += wow.o
|
||||
ath12k-$(CONFIG_ATH12K_COREDUMP) += coredump.o
|
||||
ath12k-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
@@ -12,7 +12,7 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
acpi_handle root_handle;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
root_handle = ACPI_HANDLE(ab->dev);
|
||||
if (!root_handle) {
|
||||
@@ -29,9 +29,48 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
|
||||
}
|
||||
|
||||
if (obj->type == ACPI_TYPE_INTEGER) {
|
||||
ab->acpi.func_bit = obj->integer.value;
|
||||
switch (func) {
|
||||
case ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS:
|
||||
ab->acpi.func_bit = obj->integer.value;
|
||||
break;
|
||||
case ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG:
|
||||
ab->acpi.bit_flag = obj->integer.value;
|
||||
break;
|
||||
}
|
||||
} else if (obj->type == ACPI_TYPE_STRING) {
|
||||
switch (func) {
|
||||
case ATH12K_ACPI_DSM_FUNC_BDF_EXT:
|
||||
if (obj->string.length <= ATH12K_ACPI_BDF_ANCHOR_STRING_LEN ||
|
||||
obj->string.length > ATH12K_ACPI_BDF_MAX_LEN ||
|
||||
memcmp(obj->string.pointer, ATH12K_ACPI_BDF_ANCHOR_STRING,
|
||||
ATH12K_ACPI_BDF_ANCHOR_STRING_LEN)) {
|
||||
ath12k_warn(ab, "invalid ACPI DSM BDF size: %d\n",
|
||||
obj->string.length);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(ab->acpi.bdf_string, obj->string.pointer,
|
||||
obj->buffer.length);
|
||||
|
||||
break;
|
||||
}
|
||||
} else if (obj->type == ACPI_TYPE_BUFFER) {
|
||||
switch (func) {
|
||||
case ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS:
|
||||
if (obj->buffer.length < ATH12K_ACPI_DSM_FUNC_MIN_BITMAP_SIZE ||
|
||||
obj->buffer.length > ATH12K_ACPI_DSM_FUNC_MAX_BITMAP_SIZE) {
|
||||
ath12k_warn(ab, "invalid ACPI DSM func size: %d\n",
|
||||
obj->buffer.length);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ab->acpi.func_bit = 0;
|
||||
for (i = 0; i < obj->buffer.length; i++)
|
||||
ab->acpi.func_bit += obj->buffer.pointer[i] << (i * 8);
|
||||
|
||||
break;
|
||||
case ATH12K_ACPI_DSM_FUNC_TAS_CFG:
|
||||
if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
|
||||
ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n",
|
||||
@@ -247,24 +286,118 @@ static int ath12k_acpi_set_tas_params(struct ath12k_base *ab)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ath12k_acpi_get_disable_rfkill(struct ath12k_base *ab)
|
||||
{
|
||||
return ab->acpi.acpi_disable_rfkill;
|
||||
}
|
||||
|
||||
bool ath12k_acpi_get_disable_11be(struct ath12k_base *ab)
|
||||
{
|
||||
return ab->acpi.acpi_disable_11be;
|
||||
}
|
||||
|
||||
void ath12k_acpi_set_dsm_func(struct ath12k_base *ab)
|
||||
{
|
||||
int ret;
|
||||
u8 *buf;
|
||||
|
||||
if (!ab->hw_params->acpi_guid)
|
||||
/* not supported with this hardware */
|
||||
return;
|
||||
|
||||
if (ab->acpi.acpi_tas_enable) {
|
||||
ret = ath12k_acpi_set_tas_params(ab);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to send ACPI TAS parameters: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ab->acpi.acpi_bios_sar_enable) {
|
||||
ret = ath12k_acpi_set_bios_sar_params(ab);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to send ACPI BIOS SAR: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ab->acpi.acpi_cca_enable) {
|
||||
buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
|
||||
ret = ath12k_wmi_set_bios_cmd(ab,
|
||||
WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,
|
||||
buf,
|
||||
ATH12K_ACPI_CCA_THR_OFFSET_LEN);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ab->acpi.acpi_band_edge_enable) {
|
||||
ret = ath12k_wmi_set_bios_cmd(ab,
|
||||
WMI_BIOS_PARAM_TYPE_BANDEDGE,
|
||||
ab->acpi.band_edge_power,
|
||||
sizeof(ab->acpi.band_edge_power));
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
"failed to set ACPI DSM band edge channel power: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ath12k_acpi_start(struct ath12k_base *ab)
|
||||
{
|
||||
acpi_status status;
|
||||
u8 *buf;
|
||||
int ret;
|
||||
|
||||
ab->acpi.acpi_tas_enable = false;
|
||||
ab->acpi.acpi_disable_11be = false;
|
||||
ab->acpi.acpi_disable_rfkill = false;
|
||||
ab->acpi.acpi_bios_sar_enable = false;
|
||||
ab->acpi.acpi_cca_enable = false;
|
||||
ab->acpi.acpi_band_edge_enable = false;
|
||||
ab->acpi.acpi_enable_bdf = false;
|
||||
ab->acpi.bdf_string[0] = '\0';
|
||||
|
||||
if (!ab->hw_params->acpi_guid)
|
||||
/* not supported with this hardware */
|
||||
return 0;
|
||||
|
||||
ab->acpi.acpi_tas_enable = false;
|
||||
|
||||
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS);
|
||||
if (ret) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_DISABLE_FLAG)) {
|
||||
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to get ACPI DISABLE FLAG: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ATH12K_ACPI_CHEK_BIT_VALID(ab->acpi,
|
||||
ATH12K_ACPI_DSM_DISABLE_11BE_BIT))
|
||||
ab->acpi.acpi_disable_11be = true;
|
||||
|
||||
if (!ATH12K_ACPI_CHEK_BIT_VALID(ab->acpi,
|
||||
ATH12K_ACPI_DSM_DISABLE_RFKILL_BIT))
|
||||
ab->acpi.acpi_disable_rfkill = true;
|
||||
}
|
||||
|
||||
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BDF_EXT)) {
|
||||
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BDF_EXT);
|
||||
if (ret || ab->acpi.bdf_string[0] == '\0') {
|
||||
ath12k_warn(ab, "failed to get ACPI BDF EXT: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ab->acpi.acpi_enable_bdf = true;
|
||||
}
|
||||
|
||||
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
|
||||
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG);
|
||||
if (ret) {
|
||||
@@ -308,20 +441,6 @@ int ath12k_acpi_start(struct ath12k_base *ab)
|
||||
ab->acpi.acpi_bios_sar_enable = true;
|
||||
}
|
||||
|
||||
if (ab->acpi.acpi_tas_enable) {
|
||||
ret = ath12k_acpi_set_tas_params(ab);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to send ACPI parameters: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ab->acpi.acpi_bios_sar_enable) {
|
||||
ret = ath12k_acpi_set_bios_sar_params(ab);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) {
|
||||
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
|
||||
if (ret) {
|
||||
@@ -332,18 +451,8 @@ int ath12k_acpi_start(struct ath12k_base *ab)
|
||||
|
||||
if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
|
||||
ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
|
||||
ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
|
||||
buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
|
||||
ret = ath12k_wmi_set_bios_cmd(ab,
|
||||
WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,
|
||||
buf,
|
||||
ATH12K_ACPI_CCA_THR_OFFSET_LEN);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ATH12K_ACPI_CCA_THR_ENABLE_FLAG)
|
||||
ab->acpi.acpi_cca_enable = true;
|
||||
}
|
||||
|
||||
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi,
|
||||
@@ -356,18 +465,8 @@ int ath12k_acpi_start(struct ath12k_base *ab)
|
||||
}
|
||||
|
||||
if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
|
||||
ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
|
||||
ret = ath12k_wmi_set_bios_cmd(ab,
|
||||
WMI_BIOS_PARAM_TYPE_BANDEDGE,
|
||||
ab->acpi.band_edge_power,
|
||||
sizeof(ab->acpi.band_edge_power));
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
"failed to set ACPI DSM band edge channel power: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG)
|
||||
ab->acpi.acpi_band_edge_enable = true;
|
||||
}
|
||||
|
||||
status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
|
||||
@@ -383,6 +482,21 @@ int ath12k_acpi_start(struct ath12k_base *ab)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath12k_acpi_check_bdf_variant_name(struct ath12k_base *ab)
|
||||
{
|
||||
size_t max_len = sizeof(ab->qmi.target.bdf_ext);
|
||||
|
||||
if (!ab->acpi.acpi_enable_bdf)
|
||||
return -ENODATA;
|
||||
|
||||
if (strscpy(ab->qmi.target.bdf_ext, ab->acpi.bdf_string + 4, max_len) < 0)
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT,
|
||||
"acpi bdf variant longer than the buffer (variant: %s)\n",
|
||||
ab->acpi.bdf_string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath12k_acpi_stop(struct ath12k_base *ab)
|
||||
{
|
||||
if (!ab->acpi.started)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef ATH12K_ACPI_H
|
||||
#define ATH12K_ACPI_H
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS 0
|
||||
#define ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG 2
|
||||
#define ATH12K_ACPI_DSM_FUNC_BDF_EXT 3
|
||||
#define ATH12K_ACPI_DSM_FUNC_BIOS_SAR 4
|
||||
#define ATH12K_ACPI_DSM_FUNC_GEO_OFFSET 5
|
||||
#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA 6
|
||||
@@ -16,6 +18,8 @@
|
||||
#define ATH12K_ACPI_DSM_FUNC_TAS_DATA 9
|
||||
#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE 10
|
||||
|
||||
#define ATH12K_ACPI_FUNC_BIT_DISABLE_FLAG BIT(1)
|
||||
#define ATH12K_ACPI_FUNC_BIT_BDF_EXT BIT(2)
|
||||
#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR BIT(3)
|
||||
#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET BIT(4)
|
||||
#define ATH12K_ACPI_FUNC_BIT_CCA BIT(5)
|
||||
@@ -25,6 +29,7 @@
|
||||
|
||||
#define ATH12K_ACPI_NOTIFY_EVENT 0x86
|
||||
#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func) (((_acdata).func_bit) & (_func))
|
||||
#define ATH12K_ACPI_CHEK_BIT_VALID(_acdata, _func) (((_acdata).bit_flag) & (_func))
|
||||
|
||||
#define ATH12K_ACPI_TAS_DATA_VERSION 0x1
|
||||
#define ATH12K_ACPI_TAS_DATA_ENABLE 0x1
|
||||
@@ -48,6 +53,16 @@
|
||||
#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE 100
|
||||
#define ATH12K_ACPI_DSM_TAS_CFG_SIZE 108
|
||||
|
||||
#define ATH12K_ACPI_DSM_FUNC_MIN_BITMAP_SIZE 1
|
||||
#define ATH12K_ACPI_DSM_FUNC_MAX_BITMAP_SIZE 4
|
||||
|
||||
#define ATH12K_ACPI_DSM_DISABLE_11BE_BIT BIT(0)
|
||||
#define ATH12K_ACPI_DSM_DISABLE_RFKILL_BIT BIT(2)
|
||||
|
||||
#define ATH12K_ACPI_BDF_ANCHOR_STRING_LEN 3
|
||||
#define ATH12K_ACPI_BDF_ANCHOR_STRING "BDF"
|
||||
#define ATH12K_ACPI_BDF_MAX_LEN 100
|
||||
|
||||
#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
|
||||
ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
|
||||
#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
|
||||
@@ -59,6 +74,10 @@
|
||||
|
||||
int ath12k_acpi_start(struct ath12k_base *ab);
|
||||
void ath12k_acpi_stop(struct ath12k_base *ab);
|
||||
bool ath12k_acpi_get_disable_rfkill(struct ath12k_base *ab);
|
||||
bool ath12k_acpi_get_disable_11be(struct ath12k_base *ab);
|
||||
void ath12k_acpi_set_dsm_func(struct ath12k_base *ab);
|
||||
int ath12k_acpi_check_bdf_variant_name(struct ath12k_base *ab);
|
||||
|
||||
#else
|
||||
|
||||
@@ -71,6 +90,25 @@ static inline void ath12k_acpi_stop(struct ath12k_base *ab)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool ath12k_acpi_get_disable_rfkill(struct ath12k_base *ab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool ath12k_acpi_get_disable_11be(struct ath12k_base *ab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ath12k_acpi_set_dsm_func(struct ath12k_base *ab)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath12k_acpi_check_bdf_variant_name(struct ath12k_base *ab)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
#endif /* ATH12K_ACPI_H */
|
||||
|
||||
@@ -23,6 +23,10 @@ unsigned int ath12k_debug_mask;
|
||||
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
|
||||
MODULE_PARM_DESC(debug_mask, "Debugging mask");
|
||||
|
||||
bool ath12k_ftm_mode;
|
||||
module_param_named(ftm_mode, ath12k_ftm_mode, bool, 0444);
|
||||
MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
|
||||
|
||||
/* protected with ath12k_hw_group_mutex */
|
||||
static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_list);
|
||||
|
||||
@@ -36,6 +40,9 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab)
|
||||
if (!(ab->target_caps.sys_cap_info & WMI_SYS_CAP_INFO_RFKILL))
|
||||
return 0;
|
||||
|
||||
if (ath12k_acpi_get_disable_rfkill(ab))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
ar = ab->pdevs[i].ar;
|
||||
|
||||
@@ -173,7 +180,7 @@ EXPORT_SYMBOL(ath12k_core_resume);
|
||||
|
||||
static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
|
||||
size_t name_len, bool with_variant,
|
||||
bool bus_type_mode)
|
||||
bool bus_type_mode, bool with_default)
|
||||
{
|
||||
/* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
|
||||
char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
|
||||
@@ -204,7 +211,9 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
|
||||
"bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
|
||||
ath12k_bus_str(ab->hif.bus),
|
||||
ab->qmi.target.chip_id,
|
||||
ab->qmi.target.board_id, variant);
|
||||
with_default ?
|
||||
ATH12K_BOARD_ID_DEFAULT : ab->qmi.target.board_id,
|
||||
variant);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -216,19 +225,19 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
|
||||
static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
return __ath12k_core_create_board_name(ab, name, name_len, true, false);
|
||||
return __ath12k_core_create_board_name(ab, name, name_len, true, false, false);
|
||||
}
|
||||
|
||||
static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
return __ath12k_core_create_board_name(ab, name, name_len, false, false);
|
||||
return __ath12k_core_create_board_name(ab, name, name_len, false, false, true);
|
||||
}
|
||||
|
||||
static int ath12k_core_create_bus_type_board_name(struct ath12k_base *ab, char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
return __ath12k_core_create_board_name(ab, name, name_len, false, true);
|
||||
return __ath12k_core_create_board_name(ab, name, name_len, false, true, true);
|
||||
}
|
||||
|
||||
const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
|
||||
@@ -693,6 +702,11 @@ static int ath12k_core_soc_create(struct ath12k_base *ab)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ath12k_ftm_mode) {
|
||||
ab->fw_mode = ATH12K_FIRMWARE_MODE_FTM;
|
||||
ath12k_info(ab, "Booting in ftm mode\n");
|
||||
}
|
||||
|
||||
ret = ath12k_qmi_init_service(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to initialize qmi :%d\n", ret);
|
||||
@@ -741,8 +755,7 @@ static void ath12k_core_pdev_destroy(struct ath12k_base *ab)
|
||||
ath12k_dp_pdev_free(ab);
|
||||
}
|
||||
|
||||
static int ath12k_core_start(struct ath12k_base *ab,
|
||||
enum ath12k_firmware_mode mode)
|
||||
static int ath12k_core_start(struct ath12k_base *ab)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -836,10 +849,7 @@ static int ath12k_core_start(struct ath12k_base *ab,
|
||||
goto err_reo_cleanup;
|
||||
}
|
||||
|
||||
ret = ath12k_acpi_start(ab);
|
||||
if (ret)
|
||||
/* ACPI is optional so continue in case of an error */
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi failed: %d\n", ret);
|
||||
ath12k_acpi_set_dsm_func(ab);
|
||||
|
||||
if (!test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags))
|
||||
/* Indicate the core start in the appropriate group */
|
||||
@@ -887,10 +897,41 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
|
||||
ath12k_mac_destroy(ag);
|
||||
}
|
||||
|
||||
u8 ath12k_get_num_partner_link(struct ath12k *ar)
|
||||
{
|
||||
struct ath12k_base *partner_ab, *ab = ar->ab;
|
||||
struct ath12k_hw_group *ag = ab->ag;
|
||||
struct ath12k_pdev *pdev;
|
||||
u8 num_link = 0;
|
||||
int i, j;
|
||||
|
||||
lockdep_assert_held(&ag->mutex);
|
||||
|
||||
for (i = 0; i < ag->num_devices; i++) {
|
||||
partner_ab = ag->ab[i];
|
||||
|
||||
for (j = 0; j < partner_ab->num_radios; j++) {
|
||||
pdev = &partner_ab->pdevs[j];
|
||||
|
||||
/* Avoid the self link */
|
||||
if (ar == pdev->ar)
|
||||
continue;
|
||||
|
||||
num_link++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_link;
|
||||
}
|
||||
|
||||
static int __ath12k_mac_mlo_ready(struct ath12k *ar)
|
||||
{
|
||||
u8 num_link = ath12k_get_num_partner_link(ar);
|
||||
int ret;
|
||||
|
||||
if (num_link == 0)
|
||||
return 0;
|
||||
|
||||
ret = ath12k_wmi_mlo_ready(ar);
|
||||
if (ret) {
|
||||
ath12k_err(ar->ab, "MLO ready failed for pdev %d: %d\n",
|
||||
@@ -920,19 +961,18 @@ int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag)
|
||||
ar = &ah->radio[j];
|
||||
ret = __ath12k_mac_mlo_ready(ar);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
if (!ag->mlo_capable || ag->num_devices == 1)
|
||||
if (!ag->mlo_capable)
|
||||
return 0;
|
||||
|
||||
ret = ath12k_mac_mlo_setup(ag);
|
||||
@@ -1068,7 +1108,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
|
||||
struct ath12k_hw_group *ag = ath12k_ab_to_ag(ab);
|
||||
int ret, i;
|
||||
|
||||
ret = ath12k_core_start_firmware(ab, ATH12K_FIRMWARE_MODE_NORMAL);
|
||||
ret = ath12k_core_start_firmware(ab, ab->fw_mode);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to start firmware: %d\n", ret);
|
||||
return ret;
|
||||
@@ -1089,7 +1129,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
|
||||
mutex_lock(&ag->mutex);
|
||||
mutex_lock(&ab->core_lock);
|
||||
|
||||
ret = ath12k_core_start(ab, ATH12K_FIRMWARE_MODE_NORMAL);
|
||||
ret = ath12k_core_start(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to start core: %d\n", ret);
|
||||
goto err_dp_free;
|
||||
@@ -1122,16 +1162,18 @@ err_core_stop:
|
||||
ath12k_core_stop(ab);
|
||||
mutex_unlock(&ab->core_lock);
|
||||
}
|
||||
mutex_unlock(&ag->mutex);
|
||||
goto exit;
|
||||
|
||||
err_dp_free:
|
||||
ath12k_dp_free(ab);
|
||||
mutex_unlock(&ab->core_lock);
|
||||
mutex_unlock(&ag->mutex);
|
||||
|
||||
err_firmware_stop:
|
||||
ath12k_qmi_firmware_stop(ab);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ag->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1239,7 +1281,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
|
||||
|
||||
for (i = 0; i < ag->num_hw; i++) {
|
||||
ah = ath12k_ag_to_ah(ag, i);
|
||||
if (!ah || ah->state == ATH12K_HW_STATE_OFF)
|
||||
if (!ah || ah->state == ATH12K_HW_STATE_OFF ||
|
||||
ah->state == ATH12K_HW_STATE_TM)
|
||||
continue;
|
||||
|
||||
ieee80211_stop_queues(ah->hw);
|
||||
@@ -1309,6 +1352,9 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
|
||||
ath12k_warn(ab,
|
||||
"device is wedged, will not restart hw %d\n", i);
|
||||
break;
|
||||
case ATH12K_HW_STATE_TM:
|
||||
ath12k_warn(ab, "fw mode reset done radio %d\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ah->hw_mutex);
|
||||
@@ -1602,6 +1648,9 @@ static struct ath12k_hw_group *ath12k_core_hw_group_assign(struct ath12k_base *a
|
||||
|
||||
lockdep_assert_held(&ath12k_hw_group_mutex);
|
||||
|
||||
if (ath12k_ftm_mode)
|
||||
goto invalid_group;
|
||||
|
||||
/* The grouping of multiple devices will be done based on device tree file.
|
||||
* The platforms that do not have any valid group information would have
|
||||
* each device to be part of its own invalid group.
|
||||
@@ -1789,19 +1838,19 @@ void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag)
|
||||
struct ath12k_base *ab;
|
||||
int i;
|
||||
|
||||
if (ath12k_ftm_mode)
|
||||
return;
|
||||
|
||||
lockdep_assert_held(&ag->mutex);
|
||||
|
||||
/* If more than one devices are grouped, then inter MLO
|
||||
* functionality can work still independent of whether internally
|
||||
* each device supports single_chip_mlo or not.
|
||||
* Only when there is one device, then it depends whether the
|
||||
* device can support intra chip MLO or not
|
||||
* Only when there is one device, then disable for WCN chipsets
|
||||
* till the required driver implementation is in place.
|
||||
*/
|
||||
if (ag->num_devices > 1) {
|
||||
ag->mlo_capable = true;
|
||||
} else {
|
||||
if (ag->num_devices == 1) {
|
||||
ab = ag->ab[0];
|
||||
ag->mlo_capable = ab->single_chip_mlo_supp;
|
||||
|
||||
/* WCN chipsets does not advertise in firmware features
|
||||
* hence skip checking
|
||||
@@ -1810,8 +1859,7 @@ void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ag->mlo_capable)
|
||||
return;
|
||||
ag->mlo_capable = true;
|
||||
|
||||
for (i = 0; i < ag->num_devices; i++) {
|
||||
ab = ag->ab[i];
|
||||
@@ -1927,7 +1975,6 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
|
||||
ab->dev = dev;
|
||||
ab->hif.bus = bus;
|
||||
ab->qmi.num_radios = U8_MAX;
|
||||
ab->single_chip_mlo_supp = false;
|
||||
|
||||
/* Device index used to identify the devices in a group.
|
||||
*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/panic_notifier.h>
|
||||
#include <linux/average.h>
|
||||
#include "qmi.h"
|
||||
#include "htc.h"
|
||||
#include "wmi.h"
|
||||
@@ -52,8 +53,6 @@
|
||||
|
||||
#define ATH12K_INVALID_HW_MAC_ID 0xFF
|
||||
#define ATH12K_CONNECTION_LOSS_HZ (3 * HZ)
|
||||
#define ATH12K_RX_RATE_TABLE_NUM 320
|
||||
#define ATH12K_RX_RATE_TABLE_11AX_NUM 576
|
||||
|
||||
#define ATH12K_MON_TIMER_INTERVAL 10
|
||||
#define ATH12K_RESET_TIMEOUT_HZ (20 * HZ)
|
||||
@@ -87,6 +86,7 @@ enum wme_ac {
|
||||
#define ATH12K_HT_MCS_MAX 7
|
||||
#define ATH12K_VHT_MCS_MAX 9
|
||||
#define ATH12K_HE_MCS_MAX 11
|
||||
#define ATH12K_EHT_MCS_MAX 15
|
||||
|
||||
enum ath12k_crypt_mode {
|
||||
/* Only use hardware crypto engine */
|
||||
@@ -141,6 +141,7 @@ struct ath12k_skb_rxcb {
|
||||
u8 is_frag;
|
||||
u8 tid;
|
||||
u16 peer_id;
|
||||
bool is_end_of_ppdu;
|
||||
};
|
||||
|
||||
enum ath12k_hw_rev {
|
||||
@@ -166,6 +167,7 @@ struct ath12k_ext_irq_grp {
|
||||
u32 num_irq;
|
||||
u32 grp_id;
|
||||
u64 timestamp;
|
||||
bool napi_enabled;
|
||||
struct napi_struct napi;
|
||||
struct net_device *napi_ndev;
|
||||
};
|
||||
@@ -235,6 +237,7 @@ enum ath12k_dev_flags {
|
||||
ATH12K_FLAG_CE_IRQ_ENABLED,
|
||||
ATH12K_FLAG_EXT_IRQ_ENABLED,
|
||||
ATH12K_FLAG_QMI_FW_READY_COMPLETE,
|
||||
ATH12K_FLAG_FTM_SEGMENTED,
|
||||
};
|
||||
|
||||
struct ath12k_tx_conf {
|
||||
@@ -298,6 +301,8 @@ struct ath12k_link_vif {
|
||||
u8 link_id;
|
||||
struct ath12k_vif *ahvif;
|
||||
struct ath12k_rekey_data rekey_data;
|
||||
|
||||
u8 current_cntdown_counter;
|
||||
};
|
||||
|
||||
struct ath12k_vif {
|
||||
@@ -327,6 +332,7 @@ struct ath12k_vif {
|
||||
u32 key_cipher;
|
||||
u8 tx_encap_type;
|
||||
bool ps;
|
||||
atomic_t mcbc_gsn;
|
||||
|
||||
struct ath12k_link_vif deflink;
|
||||
struct ath12k_link_vif __rcu *link[ATH12K_NUM_MAX_LINKS];
|
||||
@@ -354,20 +360,20 @@ struct ath12k_vif_iter {
|
||||
#define HAL_RX_MAX_MCS_HT 31
|
||||
#define HAL_RX_MAX_MCS_VHT 9
|
||||
#define HAL_RX_MAX_MCS_HE 11
|
||||
#define HAL_RX_MAX_MCS_BE 15
|
||||
#define HAL_RX_MAX_NSS 8
|
||||
#define HAL_RX_MAX_NUM_LEGACY_RATES 12
|
||||
#define ATH12K_RX_RATE_TABLE_11AX_NUM 576
|
||||
#define ATH12K_RX_RATE_TABLE_NUM 320
|
||||
|
||||
struct ath12k_rx_peer_rate_stats {
|
||||
u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1];
|
||||
u64 vht_mcs_count[HAL_RX_MAX_MCS_VHT + 1];
|
||||
u64 he_mcs_count[HAL_RX_MAX_MCS_HE + 1];
|
||||
u64 be_mcs_count[HAL_RX_MAX_MCS_BE + 1];
|
||||
u64 nss_count[HAL_RX_MAX_NSS];
|
||||
u64 bw_count[HAL_RX_BW_MAX];
|
||||
u64 gi_count[HAL_RX_GI_MAX];
|
||||
u64 legacy_count[HAL_RX_MAX_NUM_LEGACY_RATES];
|
||||
u64 rx_rate[ATH12K_RX_RATE_TABLE_11AX_NUM];
|
||||
u64 rx_rate[HAL_RX_BW_MAX][HAL_RX_GI_MAX][HAL_RX_MAX_NSS][HAL_RX_MAX_MCS_HT + 1];
|
||||
};
|
||||
|
||||
struct ath12k_rx_peer_stats {
|
||||
@@ -477,6 +483,8 @@ struct ath12k_wbm_tx_stats {
|
||||
u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX];
|
||||
};
|
||||
|
||||
DECLARE_EWMA(avg_rssi, 10, 8)
|
||||
|
||||
struct ath12k_link_sta {
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ath12k_sta *ahsta;
|
||||
@@ -496,10 +504,13 @@ struct ath12k_link_sta {
|
||||
u64 rx_duration;
|
||||
u64 tx_duration;
|
||||
u8 rssi_comb;
|
||||
struct ewma_avg_rssi avg_rssi;
|
||||
u8 link_id;
|
||||
struct ath12k_rx_peer_stats *rx_stats;
|
||||
struct ath12k_wbm_tx_stats *wbm_tx_stats;
|
||||
u32 bw_prev;
|
||||
u32 peer_nss;
|
||||
s8 rssi_beacon;
|
||||
|
||||
/* For now the assoc link will be considered primary */
|
||||
bool is_assoc_link;
|
||||
@@ -534,18 +545,26 @@ enum ath12k_hw_state {
|
||||
ATH12K_HW_STATE_RESTARTING,
|
||||
ATH12K_HW_STATE_RESTARTED,
|
||||
ATH12K_HW_STATE_WEDGED,
|
||||
ATH12K_HW_STATE_TM,
|
||||
/* Add other states as required */
|
||||
};
|
||||
|
||||
/* Antenna noise floor */
|
||||
#define ATH12K_DEFAULT_NOISE_FLOOR -95
|
||||
|
||||
struct ath12k_ftm_event_obj {
|
||||
u32 data_pos;
|
||||
u32 expected_seq;
|
||||
u8 *eventdata;
|
||||
};
|
||||
|
||||
struct ath12k_fw_stats {
|
||||
u32 pdev_id;
|
||||
u32 stats_id;
|
||||
struct list_head pdevs;
|
||||
struct list_head vdevs;
|
||||
struct list_head bcn;
|
||||
bool fw_stats_done;
|
||||
};
|
||||
|
||||
struct ath12k_dbg_htt_stats {
|
||||
@@ -559,6 +578,12 @@ struct ath12k_debug {
|
||||
struct dentry *debugfs_pdev;
|
||||
struct dentry *debugfs_pdev_symlink;
|
||||
struct ath12k_dbg_htt_stats htt_stats;
|
||||
enum wmi_halphy_ctrl_path_stats_id tpc_stats_type;
|
||||
bool tpc_request;
|
||||
struct completion tpc_complete;
|
||||
struct wmi_tpc_stats_arg *tpc_stats;
|
||||
u32 rx_filter;
|
||||
bool extd_rx_stats;
|
||||
};
|
||||
|
||||
struct ath12k_per_peer_tx_stats {
|
||||
@@ -712,8 +737,12 @@ struct ath12k {
|
||||
|
||||
bool nlo_enabled;
|
||||
|
||||
struct completion fw_stats_complete;
|
||||
|
||||
struct completion mlo_setup_done;
|
||||
u32 mlo_setup_status;
|
||||
u8 ftm_msgref;
|
||||
struct ath12k_fw_stats fw_stats;
|
||||
};
|
||||
|
||||
struct ath12k_hw {
|
||||
@@ -1026,9 +1055,6 @@ struct ath12k_base {
|
||||
|
||||
const struct hal_rx_ops *hal_rx_ops;
|
||||
|
||||
/* Denotes the whether MLO is possible within the chip */
|
||||
bool single_chip_mlo_supp;
|
||||
|
||||
struct completion restart_completed;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
@@ -1038,6 +1064,13 @@ struct ath12k_base {
|
||||
u32 func_bit;
|
||||
bool acpi_tas_enable;
|
||||
bool acpi_bios_sar_enable;
|
||||
bool acpi_disable_11be;
|
||||
bool acpi_disable_rfkill;
|
||||
bool acpi_cca_enable;
|
||||
bool acpi_band_edge_enable;
|
||||
bool acpi_enable_bdf;
|
||||
u32 bit_flag;
|
||||
char bdf_string[ATH12K_ACPI_BDF_MAX_LEN];
|
||||
u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
|
||||
u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
|
||||
u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
|
||||
@@ -1052,6 +1085,8 @@ struct ath12k_base {
|
||||
|
||||
struct ath12k_hw_group *ag;
|
||||
struct ath12k_wsi_info wsi_info;
|
||||
enum ath12k_firmware_mode fw_mode;
|
||||
struct ath12k_ftm_event_obj ftm_event_obj;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[] __aligned(sizeof(void *));
|
||||
@@ -1062,6 +1097,93 @@ struct ath12k_pdev_map {
|
||||
u8 pdev_idx;
|
||||
};
|
||||
|
||||
struct ath12k_fw_stats_vdev {
|
||||
struct list_head list;
|
||||
|
||||
u32 vdev_id;
|
||||
u32 beacon_snr;
|
||||
u32 data_snr;
|
||||
u32 num_tx_frames[WLAN_MAX_AC];
|
||||
u32 num_rx_frames;
|
||||
u32 num_tx_frames_retries[WLAN_MAX_AC];
|
||||
u32 num_tx_frames_failures[WLAN_MAX_AC];
|
||||
u32 num_rts_fail;
|
||||
u32 num_rts_success;
|
||||
u32 num_rx_err;
|
||||
u32 num_rx_discard;
|
||||
u32 num_tx_not_acked;
|
||||
u32 tx_rate_history[MAX_TX_RATE_VALUES];
|
||||
u32 beacon_rssi_history[MAX_TX_RATE_VALUES];
|
||||
};
|
||||
|
||||
struct ath12k_fw_stats_bcn {
|
||||
struct list_head list;
|
||||
|
||||
u32 vdev_id;
|
||||
u32 tx_bcn_succ_cnt;
|
||||
u32 tx_bcn_outage_cnt;
|
||||
};
|
||||
|
||||
struct ath12k_fw_stats_pdev {
|
||||
struct list_head list;
|
||||
|
||||
/* PDEV stats */
|
||||
s32 ch_noise_floor;
|
||||
u32 tx_frame_count;
|
||||
u32 rx_frame_count;
|
||||
u32 rx_clear_count;
|
||||
u32 cycle_count;
|
||||
u32 phy_err_count;
|
||||
u32 chan_tx_power;
|
||||
u32 ack_rx_bad;
|
||||
u32 rts_bad;
|
||||
u32 rts_good;
|
||||
u32 fcs_bad;
|
||||
u32 no_beacons;
|
||||
u32 mib_int_count;
|
||||
|
||||
/* PDEV TX stats */
|
||||
s32 comp_queued;
|
||||
s32 comp_delivered;
|
||||
s32 msdu_enqued;
|
||||
s32 mpdu_enqued;
|
||||
s32 wmm_drop;
|
||||
s32 local_enqued;
|
||||
s32 local_freed;
|
||||
s32 hw_queued;
|
||||
s32 hw_reaped;
|
||||
s32 underrun;
|
||||
s32 tx_abort;
|
||||
s32 mpdus_requed;
|
||||
u32 tx_ko;
|
||||
u32 data_rc;
|
||||
u32 self_triggers;
|
||||
u32 sw_retry_failure;
|
||||
u32 illgl_rate_phy_err;
|
||||
u32 pdev_cont_xretry;
|
||||
u32 pdev_tx_timeout;
|
||||
u32 pdev_resets;
|
||||
u32 stateless_tid_alloc_failure;
|
||||
u32 phy_underrun;
|
||||
u32 txop_ovf;
|
||||
|
||||
/* PDEV RX stats */
|
||||
s32 mid_ppdu_route_change;
|
||||
s32 status_rcvd;
|
||||
s32 r0_frags;
|
||||
s32 r1_frags;
|
||||
s32 r2_frags;
|
||||
s32 r3_frags;
|
||||
s32 htt_msdus;
|
||||
s32 htt_mpdus;
|
||||
s32 loc_msdus;
|
||||
s32 loc_mpdus;
|
||||
s32 oversize_amsdu;
|
||||
s32 phy_errs;
|
||||
s32 phy_err_drop;
|
||||
s32 mpdu_errs;
|
||||
};
|
||||
|
||||
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab);
|
||||
int ath12k_core_pre_init(struct ath12k_base *ab);
|
||||
int ath12k_core_init(struct ath12k_base *ath12k);
|
||||
@@ -1084,6 +1206,7 @@ int ath12k_core_resume(struct ath12k_base *ab);
|
||||
int ath12k_core_suspend(struct ath12k_base *ab);
|
||||
int ath12k_core_suspend_late(struct ath12k_base *ab);
|
||||
void ath12k_core_hw_group_unassign(struct ath12k_base *ab);
|
||||
u8 ath12k_get_num_partner_link(struct ath12k *ar);
|
||||
|
||||
const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
|
||||
const char *filename);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
@@ -63,8 +63,10 @@ void __ath12k_dbg(struct ath12k_base *ab, enum ath12k_debug_mask mask,
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
if (ath12k_debug_mask & mask)
|
||||
if (likely(ab))
|
||||
dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf);
|
||||
else
|
||||
printk(KERN_DEBUG "ath12k: %pV", &vaf);
|
||||
|
||||
/* TODO: trace log */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ATH12K_DEBUG_H_
|
||||
@@ -37,6 +37,7 @@ __printf(2, 3) void __ath12k_warn(struct device *dev, const char *fmt, ...);
|
||||
#define ath12k_hw_warn(ah, fmt, ...) __ath12k_warn((ah)->dev, fmt, ##__VA_ARGS__)
|
||||
|
||||
extern unsigned int ath12k_debug_mask;
|
||||
extern bool ath12k_ftm_mode;
|
||||
|
||||
#ifdef CONFIG_ATH12K_DEBUG
|
||||
__printf(3, 4) void __ath12k_dbg(struct ath12k_base *ab,
|
||||
@@ -61,11 +62,14 @@ static inline void ath12k_dbg_dump(struct ath12k_base *ab,
|
||||
}
|
||||
#endif /* CONFIG_ATH12K_DEBUG */
|
||||
|
||||
#define ath12k_dbg(ar, dbg_mask, fmt, ...) \
|
||||
#define ath12k_dbg(ab, dbg_mask, fmt, ...) \
|
||||
do { \
|
||||
typeof(dbg_mask) mask = (dbg_mask); \
|
||||
if (ath12k_debug_mask & mask) \
|
||||
__ath12k_dbg(ar, mask, fmt, ##__VA_ARGS__); \
|
||||
__ath12k_dbg(ab, mask, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ath12k_generic_dbg(dbg_mask, fmt, ...) \
|
||||
ath12k_dbg(NULL, dbg_mask, fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif /* _ATH12K_DEBUG_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ATH12K_DEBUGFS_H_
|
||||
@@ -12,6 +12,101 @@ void ath12k_debugfs_soc_create(struct ath12k_base *ab);
|
||||
void ath12k_debugfs_soc_destroy(struct ath12k_base *ab);
|
||||
void ath12k_debugfs_register(struct ath12k *ar);
|
||||
void ath12k_debugfs_unregister(struct ath12k *ar);
|
||||
void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *stats);
|
||||
void ath12k_debugfs_fw_stats_reset(struct ath12k *ar);
|
||||
|
||||
static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar)
|
||||
{
|
||||
return ar->debug.extd_rx_stats;
|
||||
}
|
||||
|
||||
static inline int ath12k_debugfs_rx_filter(struct ath12k *ar)
|
||||
{
|
||||
return ar->debug.rx_filter;
|
||||
}
|
||||
|
||||
#define ATH12K_CCK_RATES 4
|
||||
#define ATH12K_OFDM_RATES 8
|
||||
#define ATH12K_HT_RATES 8
|
||||
#define ATH12K_VHT_RATES 12
|
||||
#define ATH12K_HE_RATES 12
|
||||
#define ATH12K_HE_RATES_WITH_EXTRA_MCS 14
|
||||
#define ATH12K_EHT_RATES 16
|
||||
#define HE_EXTRA_MCS_SUPPORT GENMASK(31, 16)
|
||||
#define ATH12K_NSS_1 1
|
||||
#define ATH12K_NSS_4 4
|
||||
#define ATH12K_NSS_8 8
|
||||
#define ATH12K_HW_NSS(_rcode) (((_rcode) >> 5) & 0x7)
|
||||
#define TPC_STATS_WAIT_TIME (1 * HZ)
|
||||
#define MAX_TPC_PREAM_STR_LEN 7
|
||||
#define TPC_INVAL -128
|
||||
#define TPC_MAX 127
|
||||
#define TPC_STATS_WAIT_TIME (1 * HZ)
|
||||
#define TPC_STATS_TOT_ROW 700
|
||||
#define TPC_STATS_TOT_COLUMN 100
|
||||
#define MODULATION_LIMIT 126
|
||||
|
||||
#define ATH12K_TPC_STATS_BUF_SIZE (TPC_STATS_TOT_ROW * TPC_STATS_TOT_COLUMN)
|
||||
|
||||
enum wmi_tpc_pream_bw {
|
||||
WMI_TPC_PREAM_CCK,
|
||||
WMI_TPC_PREAM_OFDM,
|
||||
WMI_TPC_PREAM_HT20,
|
||||
WMI_TPC_PREAM_HT40,
|
||||
WMI_TPC_PREAM_VHT20,
|
||||
WMI_TPC_PREAM_VHT40,
|
||||
WMI_TPC_PREAM_VHT80,
|
||||
WMI_TPC_PREAM_VHT160,
|
||||
WMI_TPC_PREAM_HE20,
|
||||
WMI_TPC_PREAM_HE40,
|
||||
WMI_TPC_PREAM_HE80,
|
||||
WMI_TPC_PREAM_HE160,
|
||||
WMI_TPC_PREAM_EHT20,
|
||||
WMI_TPC_PREAM_EHT40,
|
||||
WMI_TPC_PREAM_EHT60,
|
||||
WMI_TPC_PREAM_EHT80,
|
||||
WMI_TPC_PREAM_EHT120,
|
||||
WMI_TPC_PREAM_EHT140,
|
||||
WMI_TPC_PREAM_EHT160,
|
||||
WMI_TPC_PREAM_EHT200,
|
||||
WMI_TPC_PREAM_EHT240,
|
||||
WMI_TPC_PREAM_EHT280,
|
||||
WMI_TPC_PREAM_EHT320,
|
||||
WMI_TPC_PREAM_MAX
|
||||
};
|
||||
|
||||
enum ath12k_debug_tpc_stats_ctl_mode {
|
||||
ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ,
|
||||
ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ,
|
||||
|
||||
ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20 = 23,
|
||||
ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20,
|
||||
ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40,
|
||||
ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80,
|
||||
ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120
|
||||
};
|
||||
|
||||
enum ath12k_debug_tpc_stats_support_modes {
|
||||
ATH12K_TPC_STATS_SUPPORT_160 = 0,
|
||||
ATH12K_TPC_STATS_SUPPORT_320,
|
||||
ATH12K_TPC_STATS_SUPPORT_AX,
|
||||
ATH12K_TPC_STATS_SUPPORT_AX_EXTRA_MCS,
|
||||
ATH12K_TPC_STATS_SUPPORT_BE,
|
||||
ATH12K_TPC_STATS_SUPPORT_BE_PUNC,
|
||||
};
|
||||
#else
|
||||
static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab)
|
||||
{
|
||||
@@ -29,6 +124,24 @@ static inline void ath12k_debugfs_unregister(struct ath12k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *stats)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath12k_debugfs_fw_stats_reset(struct ath12k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int ath12k_debugfs_rx_filter(struct ath12k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ATH12K_DEBUGFS */
|
||||
|
||||
#endif /* _ATH12K_DEBUGFS_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_HTT_STATS_H
|
||||
@@ -123,30 +123,38 @@ struct ath12k_htt_extd_stats_msg {
|
||||
|
||||
/* htt_dbg_ext_stats_type */
|
||||
enum ath12k_dbg_htt_ext_stats_type {
|
||||
ATH12K_DBG_HTT_EXT_STATS_RESET = 0,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12,
|
||||
ATH12K_DBG_HTT_EXT_STATS_SRNG_INFO = 15,
|
||||
ATH12K_DBG_HTT_EXT_STATS_SFM_INFO = 16,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF = 31,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TXBF_OFDMA = 32,
|
||||
ATH12K_DBG_HTT_EXT_STATS_DLPAGER_STATS = 36,
|
||||
ATH12K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37,
|
||||
ATH12K_DBG_HTT_EXT_VDEVS_TXRX_STATS = 38,
|
||||
ATH12K_DBG_HTT_EXT_PDEV_PER_STATS = 40,
|
||||
ATH12K_DBG_HTT_EXT_AST_ENTRIES = 41,
|
||||
ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45,
|
||||
ATH12K_DBG_HTT_DBG_PDEV_PUNCTURE_STATS = 46,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49,
|
||||
ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51,
|
||||
ATH12K_DGB_HTT_EXT_STATS_PDEV_MBSSID_CTRL_FRAME = 54,
|
||||
ATH12K_DBG_HTT_EXT_STATS_RESET = 0,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_RATE = 9,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_RX_RATE = 10,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12,
|
||||
ATH12K_DBG_HTT_EXT_STATS_SRNG_INFO = 15,
|
||||
ATH12K_DBG_HTT_EXT_STATS_SFM_INFO = 16,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO = 22,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23,
|
||||
ATH12K_DBG_HTT_EXT_STATS_LATENCY_PROF_STATS = 25,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_UL_TRIG_STATS = 26,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_UL_MUMIMO_TRIG_STATS = 27,
|
||||
ATH12K_DBG_HTT_EXT_STATS_FSE_RX = 28,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_RX_RATE_EXT = 30,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF = 31,
|
||||
ATH12K_DBG_HTT_EXT_STATS_TXBF_OFDMA = 32,
|
||||
ATH12K_DBG_HTT_EXT_STATS_DLPAGER_STATS = 36,
|
||||
ATH12K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37,
|
||||
ATH12K_DBG_HTT_EXT_VDEVS_TXRX_STATS = 38,
|
||||
ATH12K_DBG_HTT_EXT_PDEV_PER_STATS = 40,
|
||||
ATH12K_DBG_HTT_EXT_AST_ENTRIES = 41,
|
||||
ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45,
|
||||
ATH12K_DBG_HTT_DBG_PDEV_PUNCTURE_STATS = 46,
|
||||
ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49,
|
||||
ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51,
|
||||
ATH12K_DGB_HTT_EXT_STATS_PDEV_MBSSID_CTRL_FRAME = 54,
|
||||
|
||||
/* keep this last */
|
||||
ATH12K_DBG_HTT_NUM_EXT_STATS,
|
||||
@@ -173,6 +181,8 @@ enum ath12k_dbg_htt_tlv_tag {
|
||||
HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG = 25,
|
||||
HTT_STATS_SFM_CMN_TAG = 26,
|
||||
HTT_STATS_SRING_STATS_TAG = 27,
|
||||
HTT_STATS_TX_PDEV_RATE_STATS_TAG = 34,
|
||||
HTT_STATS_RX_PDEV_RATE_STATS_TAG = 35,
|
||||
HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36,
|
||||
HTT_STATS_TX_SCHED_CMN_TAG = 37,
|
||||
HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39,
|
||||
@@ -195,12 +205,21 @@ enum ath12k_dbg_htt_tlv_tag {
|
||||
HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG = 72,
|
||||
HTT_STATS_PDEV_CCA_COUNTERS_TAG = 73,
|
||||
HTT_STATS_TX_PDEV_MPDU_STATS_TAG = 74,
|
||||
HTT_STATS_TX_SOUNDING_STATS_TAG = 80,
|
||||
HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG = 86,
|
||||
HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG = 87,
|
||||
HTT_STATS_PDEV_OBSS_PD_TAG = 88,
|
||||
HTT_STATS_HW_WAR_TAG = 89,
|
||||
HTT_STATS_LATENCY_PROF_STATS_TAG = 91,
|
||||
HTT_STATS_LATENCY_CTX_TAG = 92,
|
||||
HTT_STATS_LATENCY_CNT_TAG = 93,
|
||||
HTT_STATS_RX_PDEV_UL_TRIG_STATS_TAG = 94,
|
||||
HTT_STATS_RX_PDEV_UL_OFDMA_USER_STATS_TAG = 95,
|
||||
HTT_STATS_RX_PDEV_UL_MUMIMO_TRIG_STATS_TAG = 97,
|
||||
HTT_STATS_RX_FSE_STATS_TAG = 98,
|
||||
HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100,
|
||||
HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102,
|
||||
HTT_STATS_RX_PDEV_RATE_EXT_STATS_TAG = 103,
|
||||
HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG = 108,
|
||||
HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG = 111,
|
||||
HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG = 112,
|
||||
@@ -387,6 +406,182 @@ struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv {
|
||||
__le32 num_ppdu_posted_per_burst[ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS];
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS 12
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS 4
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS 5
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS 4
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES 7
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_CCK_STATS 4
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS 8
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_LTF 4
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS 2
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS 2
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_11AX_TRIGGER_TYPES 6
|
||||
|
||||
struct ath12k_htt_tx_pdev_rate_stats_tlv {
|
||||
__le32 mac_id_word;
|
||||
__le32 tx_ldpc;
|
||||
__le32 rts_cnt;
|
||||
__le32 ack_rssi;
|
||||
__le32 tx_mcs[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 tx_su_mcs[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 tx_mu_mcs[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
__le32 tx_bw[ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 tx_stbc[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 tx_pream[ATH12K_HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES];
|
||||
__le32 tx_gi[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 tx_dcm[ATH12K_HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS];
|
||||
__le32 rts_success;
|
||||
__le32 tx_legacy_cck_rate[ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_CCK_STATS];
|
||||
__le32 tx_legacy_ofdm_rate[ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS];
|
||||
__le32 ac_mu_mimo_tx_ldpc;
|
||||
__le32 ax_mu_mimo_tx_ldpc;
|
||||
__le32 ofdma_tx_ldpc;
|
||||
__le32 tx_he_ltf[ATH12K_HTT_TX_PDEV_STATS_NUM_LTF];
|
||||
__le32 ac_mu_mimo_tx_mcs[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ax_mu_mimo_tx_mcs[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ofdma_tx_mcs[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ac_mu_mimo_tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
__le32 ax_mu_mimo_tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
__le32 ofdma_tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
__le32 ac_mu_mimo_tx_bw[ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 ax_mu_mimo_tx_bw[ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 ofdma_tx_bw[ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 ac_mu_mimo_tx_gi[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ax_mimo_tx_gi[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ofdma_tx_gi[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 trigger_type_11ax[ATH12K_HTT_TX_PDEV_STATS_NUM_11AX_TRIGGER_TYPES];
|
||||
__le32 tx_11ax_su_ext;
|
||||
__le32 tx_mcs_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 tx_stbc_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 tx_gi_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 ax_mu_mimo_tx_mcs_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 ofdma_tx_mcs_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 ax_tx_gi_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 ofd_tx_gi_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
__le32 tx_mcs_ext_2[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS];
|
||||
__le32 tx_bw_320mhz;
|
||||
};
|
||||
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS 4
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS 8
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS 12
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_GI_COUNTERS 4
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS 5
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_BW_COUNTERS 4
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS 8
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES 7
|
||||
#define ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER 8
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_NSS 16
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_RU_SIZE_COUNTERS 6
|
||||
#define ATH12K_HTT_RX_PDEV_MAX_ULMUMIMO_NUM_USER 8
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS 2
|
||||
|
||||
struct ath12k_htt_rx_pdev_rate_stats_tlv {
|
||||
__le32 mac_id_word;
|
||||
__le32 nsts;
|
||||
__le32 rx_ldpc;
|
||||
__le32 rts_cnt;
|
||||
__le32 rssi_mgmt;
|
||||
__le32 rssi_data;
|
||||
__le32 rssi_comb;
|
||||
__le32 rx_mcs[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 rx_nss[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
__le32 rx_dcm[ATH12K_HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS];
|
||||
__le32 rx_stbc[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 rx_bw[ATH12K_HTT_RX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 rx_pream[ATH12K_HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES];
|
||||
u8 rssi_chain_in_db[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 rx_gi[ATH12K_HTT_RX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 rssi_in_dbm;
|
||||
__le32 rx_11ax_su_ext;
|
||||
__le32 rx_11ac_mumimo;
|
||||
__le32 rx_11ax_mumimo;
|
||||
__le32 rx_11ax_ofdma;
|
||||
__le32 txbf;
|
||||
__le32 rx_legacy_cck_rate[ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS];
|
||||
__le32 rx_legacy_ofdm_rate[ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS];
|
||||
__le32 rx_active_dur_us_low;
|
||||
__le32 rx_active_dur_us_high;
|
||||
__le32 rx_11ax_ul_ofdma;
|
||||
__le32 ul_ofdma_rx_mcs[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ul_ofdma_rx_gi[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 ul_ofdma_rx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
__le32 ul_ofdma_rx_bw[ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 ul_ofdma_rx_stbc;
|
||||
__le32 ul_ofdma_rx_ldpc;
|
||||
__le32 rx_ulofdma_non_data_ppdu[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 rx_ulofdma_data_ppdu[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 rx_ulofdma_mpdu_ok[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 rx_ulofdma_mpdu_fail[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 nss_count;
|
||||
__le32 pilot_count;
|
||||
__le32 rx_pil_evm_db[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_NSS];
|
||||
__le32 rx_pilot_evm_db_mean[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS];
|
||||
s8 rx_ul_fd_rssi[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
|
||||
[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 per_chain_rssi_pkt_type;
|
||||
s8 rx_per_chain_rssi_in_dbm[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_BW_COUNTERS];
|
||||
__le32 rx_su_ndpa;
|
||||
__le32 rx_11ax_su_txbf_mcs[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 rx_mu_ndpa;
|
||||
__le32 rx_11ax_mu_txbf_mcs[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 rx_br_poll;
|
||||
__le32 rx_11ax_dl_ofdma_mcs[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
|
||||
__le32 rx_11ax_dl_ofdma_ru[ATH12K_HTT_RX_PDEV_STATS_NUM_RU_SIZE_COUNTERS];
|
||||
__le32 rx_ulmumimo_non_data_ppdu[ATH12K_HTT_RX_PDEV_MAX_ULMUMIMO_NUM_USER];
|
||||
__le32 rx_ulmumimo_data_ppdu[ATH12K_HTT_RX_PDEV_MAX_ULMUMIMO_NUM_USER];
|
||||
__le32 rx_ulmumimo_mpdu_ok[ATH12K_HTT_RX_PDEV_MAX_ULMUMIMO_NUM_USER];
|
||||
__le32 rx_ulmumimo_mpdu_fail[ATH12K_HTT_RX_PDEV_MAX_ULMUMIMO_NUM_USER];
|
||||
__le32 rx_ulofdma_non_data_nusers[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 rx_ulofdma_data_nusers[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER];
|
||||
__le32 rx_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS];
|
||||
};
|
||||
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT_COUNTERS 4
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT 14
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS 2
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT2_COUNTERS 5
|
||||
#define ATH12K_HTT_RX_PDEV_STATS_NUM_PUNCTURED_MODE_COUNTERS 5
|
||||
|
||||
struct ath12k_htt_rx_pdev_rate_ext_stats_tlv {
|
||||
u8 rssi_chain_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT_COUNTERS];
|
||||
s8 rx_per_chain_rssi_ext_in_dbm[ATH12K_HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT_COUNTERS];
|
||||
__le32 rssi_mcast_in_dbm;
|
||||
__le32 rssi_mgmt_in_dbm;
|
||||
__le32 rx_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 rx_stbc_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 rx_gi_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 ul_ofdma_rx_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 ul_ofdma_rx_gi_ext[ATH12K_HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 rx_11ax_su_txbf_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 rx_11ax_mu_txbf_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 rx_11ax_dl_ofdma_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT];
|
||||
__le32 rx_mcs_ext_2[ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS];
|
||||
__le32 rx_bw_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT2_COUNTERS];
|
||||
__le32 rx_gi_ext_2[ATH12K_HTT_RX_PDEV_STATS_NUM_GI_COUNTERS]
|
||||
[ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS];
|
||||
__le32 rx_su_punctured_mode[ATH12K_HTT_RX_PDEV_STATS_NUM_PUNCTURED_MODE_COUNTERS];
|
||||
};
|
||||
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0)
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID GENMASK(15, 8)
|
||||
|
||||
@@ -1058,6 +1253,82 @@ struct ath12k_htt_pdev_cca_stats_hist_v1_tlv {
|
||||
__le32 collection_interval;
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_TX_CV_CORR_MAX_NUM_COLUMNS 8
|
||||
#define ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS 4
|
||||
#define ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS 8
|
||||
#define ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS 8
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS 4
|
||||
#define ATH12K_HTT_TX_NUM_MCS_CNTRS 12
|
||||
#define ATH12K_HTT_TX_NUM_EXTRA_MCS_CNTRS 2
|
||||
|
||||
#define ATH12K_HTT_TX_NUM_OF_SOUNDING_STATS_WORDS \
|
||||
(ATH12K_HTT_TX_PDEV_STATS_NUM_BW_COUNTERS * \
|
||||
ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS)
|
||||
|
||||
enum ath12k_htt_txbf_sound_steer_modes {
|
||||
ATH12K_HTT_IMPL_STEER_STATS = 0,
|
||||
ATH12K_HTT_EXPL_SUSIFS_STEER_STATS = 1,
|
||||
ATH12K_HTT_EXPL_SURBO_STEER_STATS = 2,
|
||||
ATH12K_HTT_EXPL_MUSIFS_STEER_STATS = 3,
|
||||
ATH12K_HTT_EXPL_MURBO_STEER_STATS = 4,
|
||||
ATH12K_HTT_TXBF_MAX_NUM_OF_MODES = 5
|
||||
};
|
||||
|
||||
enum ath12k_htt_stats_sounding_tx_mode {
|
||||
ATH12K_HTT_TX_AC_SOUNDING_MODE = 0,
|
||||
ATH12K_HTT_TX_AX_SOUNDING_MODE = 1,
|
||||
ATH12K_HTT_TX_BE_SOUNDING_MODE = 2,
|
||||
ATH12K_HTT_TX_CMN_SOUNDING_MODE = 3,
|
||||
};
|
||||
|
||||
struct ath12k_htt_tx_sounding_stats_tlv {
|
||||
__le32 tx_sounding_mode;
|
||||
__le32 cbf_20[ATH12K_HTT_TXBF_MAX_NUM_OF_MODES];
|
||||
__le32 cbf_40[ATH12K_HTT_TXBF_MAX_NUM_OF_MODES];
|
||||
__le32 cbf_80[ATH12K_HTT_TXBF_MAX_NUM_OF_MODES];
|
||||
__le32 cbf_160[ATH12K_HTT_TXBF_MAX_NUM_OF_MODES];
|
||||
__le32 sounding[ATH12K_HTT_TX_NUM_OF_SOUNDING_STATS_WORDS];
|
||||
__le32 cv_nc_mismatch_err;
|
||||
__le32 cv_fcs_err;
|
||||
__le32 cv_frag_idx_mismatch;
|
||||
__le32 cv_invalid_peer_id;
|
||||
__le32 cv_no_txbf_setup;
|
||||
__le32 cv_expiry_in_update;
|
||||
__le32 cv_pkt_bw_exceed;
|
||||
__le32 cv_dma_not_done_err;
|
||||
__le32 cv_update_failed;
|
||||
__le32 cv_total_query;
|
||||
__le32 cv_total_pattern_query;
|
||||
__le32 cv_total_bw_query;
|
||||
__le32 cv_invalid_bw_coding;
|
||||
__le32 cv_forced_sounding;
|
||||
__le32 cv_standalone_sounding;
|
||||
__le32 cv_nc_mismatch;
|
||||
__le32 cv_fb_type_mismatch;
|
||||
__le32 cv_ofdma_bw_mismatch;
|
||||
__le32 cv_bw_mismatch;
|
||||
__le32 cv_pattern_mismatch;
|
||||
__le32 cv_preamble_mismatch;
|
||||
__le32 cv_nr_mismatch;
|
||||
__le32 cv_in_use_cnt_exceeded;
|
||||
__le32 cv_found;
|
||||
__le32 cv_not_found;
|
||||
__le32 sounding_320[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS];
|
||||
__le32 cbf_320[ATH12K_HTT_TXBF_MAX_NUM_OF_MODES];
|
||||
__le32 cv_ntbr_sounding;
|
||||
__le32 cv_found_upload_in_progress;
|
||||
__le32 cv_expired_during_query;
|
||||
__le32 cv_dma_timeout_error;
|
||||
__le32 cv_buf_ibf_uploads;
|
||||
__le32 cv_buf_ebf_uploads;
|
||||
__le32 cv_buf_received;
|
||||
__le32 cv_buf_fed_back;
|
||||
__le32 cv_total_query_ibf;
|
||||
__le32 cv_found_ibf;
|
||||
__le32 cv_not_found_ibf;
|
||||
__le32 cv_expired_during_query_ibf;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_htt_pdev_obss_pd_stats_tlv {
|
||||
__le32 num_obss_tx_ppdu_success;
|
||||
__le32 num_obss_tx_ppdu_failure;
|
||||
@@ -1080,6 +1351,127 @@ struct ath12k_htt_pdev_obss_pd_stats_tlv {
|
||||
__le32 num_sr_ppdu_abort_flush_cnt;
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_STATS_MAX_PROF_STATS_NAME_LEN 32
|
||||
#define ATH12K_HTT_LATENCY_PROFILE_NUM_MAX_HIST 3
|
||||
#define ATH12K_HTT_INTERRUPTS_LATENCY_PROFILE_MAX_HIST 3
|
||||
|
||||
struct ath12k_htt_latency_prof_stats_tlv {
|
||||
__le32 print_header;
|
||||
s8 latency_prof_name[ATH12K_HTT_STATS_MAX_PROF_STATS_NAME_LEN];
|
||||
__le32 cnt;
|
||||
__le32 min;
|
||||
__le32 max;
|
||||
__le32 last;
|
||||
__le32 tot;
|
||||
__le32 avg;
|
||||
__le32 hist_intvl;
|
||||
__le32 hist[ATH12K_HTT_LATENCY_PROFILE_NUM_MAX_HIST];
|
||||
} __packed;
|
||||
|
||||
struct ath12k_htt_latency_prof_ctx_tlv {
|
||||
__le32 duration;
|
||||
__le32 tx_msdu_cnt;
|
||||
__le32 tx_mpdu_cnt;
|
||||
__le32 tx_ppdu_cnt;
|
||||
__le32 rx_msdu_cnt;
|
||||
__le32 rx_mpdu_cnt;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_htt_latency_prof_cnt_tlv {
|
||||
__le32 prof_enable_cnt;
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_RX_NUM_MCS_CNTRS 12
|
||||
#define ATH12K_HTT_RX_NUM_GI_CNTRS 4
|
||||
#define ATH12K_HTT_RX_NUM_SPATIAL_STREAMS 8
|
||||
#define ATH12K_HTT_RX_NUM_BW_CNTRS 4
|
||||
#define ATH12K_HTT_RX_NUM_RU_SIZE_CNTRS 6
|
||||
#define ATH12K_HTT_RX_NUM_RU_SIZE_160MHZ_CNTRS 7
|
||||
#define ATH12K_HTT_RX_UL_MAX_UPLINK_RSSI_TRACK 5
|
||||
#define ATH12K_HTT_RX_NUM_REDUCED_CHAN_TYPES 2
|
||||
#define ATH12K_HTT_RX_NUM_EXTRA_MCS_CNTRS 2
|
||||
|
||||
enum ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE {
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_26,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_52,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_106,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_242,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_484,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_996,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_996x2,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_NUM_AX_RU_SIZE_CNTRS,
|
||||
};
|
||||
|
||||
struct ath12k_htt_rx_pdev_ul_ofdma_user_stats_tlv {
|
||||
__le32 user_index;
|
||||
__le32 rx_ulofdma_non_data_ppdu;
|
||||
__le32 rx_ulofdma_data_ppdu;
|
||||
__le32 rx_ulofdma_mpdu_ok;
|
||||
__le32 rx_ulofdma_mpdu_fail;
|
||||
__le32 rx_ulofdma_non_data_nusers;
|
||||
__le32 rx_ulofdma_data_nusers;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_htt_rx_pdev_ul_trigger_stats_tlv {
|
||||
__le32 mac_id__word;
|
||||
__le32 rx_11ax_ul_ofdma;
|
||||
__le32 ul_ofdma_rx_mcs[ATH12K_HTT_RX_NUM_MCS_CNTRS];
|
||||
__le32 ul_ofdma_rx_gi[ATH12K_HTT_RX_NUM_GI_CNTRS][ATH12K_HTT_RX_NUM_MCS_CNTRS];
|
||||
__le32 ul_ofdma_rx_nss[ATH12K_HTT_RX_NUM_SPATIAL_STREAMS];
|
||||
__le32 ul_ofdma_rx_bw[ATH12K_HTT_RX_NUM_BW_CNTRS];
|
||||
__le32 ul_ofdma_rx_stbc;
|
||||
__le32 ul_ofdma_rx_ldpc;
|
||||
__le32 data_ru_size_ppdu[ATH12K_HTT_RX_NUM_RU_SIZE_160MHZ_CNTRS];
|
||||
__le32 non_data_ru_size_ppdu[ATH12K_HTT_RX_NUM_RU_SIZE_160MHZ_CNTRS];
|
||||
__le32 uplink_sta_aid[ATH12K_HTT_RX_UL_MAX_UPLINK_RSSI_TRACK];
|
||||
__le32 uplink_sta_target_rssi[ATH12K_HTT_RX_UL_MAX_UPLINK_RSSI_TRACK];
|
||||
__le32 uplink_sta_fd_rssi[ATH12K_HTT_RX_UL_MAX_UPLINK_RSSI_TRACK];
|
||||
__le32 uplink_sta_power_headroom[ATH12K_HTT_RX_UL_MAX_UPLINK_RSSI_TRACK];
|
||||
__le32 red_bw[ATH12K_HTT_RX_NUM_REDUCED_CHAN_TYPES][ATH12K_HTT_RX_NUM_BW_CNTRS];
|
||||
__le32 ul_ofdma_bsc_trig_rx_qos_null_only;
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_TX_UL_MUMIMO_USER_STATS 8
|
||||
|
||||
struct ath12k_htt_rx_ul_mumimo_trig_stats_tlv {
|
||||
__le32 mac_id__word;
|
||||
__le32 rx_11ax_ul_mumimo;
|
||||
__le32 ul_mumimo_rx_mcs[ATH12K_HTT_RX_NUM_MCS_CNTRS];
|
||||
__le32 ul_rx_gi[ATH12K_HTT_RX_NUM_GI_CNTRS][ATH12K_HTT_RX_NUM_MCS_CNTRS];
|
||||
__le32 ul_mumimo_rx_nss[ATH12K_HTT_RX_NUM_SPATIAL_STREAMS];
|
||||
__le32 ul_mumimo_rx_bw[ATH12K_HTT_RX_NUM_BW_CNTRS];
|
||||
__le32 ul_mumimo_rx_stbc;
|
||||
__le32 ul_mumimo_rx_ldpc;
|
||||
__le32 ul_mumimo_rx_mcs_ext[ATH12K_HTT_RX_NUM_EXTRA_MCS_CNTRS];
|
||||
__le32 ul_gi_ext[ATH12K_HTT_RX_NUM_GI_CNTRS][ATH12K_HTT_RX_NUM_EXTRA_MCS_CNTRS];
|
||||
s8 ul_rssi[ATH12K_HTT_RX_NUM_SPATIAL_STREAMS][ATH12K_HTT_RX_NUM_BW_CNTRS];
|
||||
s8 tgt_rssi[ATH12K_HTT_TX_UL_MUMIMO_USER_STATS][ATH12K_HTT_RX_NUM_BW_CNTRS];
|
||||
s8 fd[ATH12K_HTT_TX_UL_MUMIMO_USER_STATS][ATH12K_HTT_RX_NUM_SPATIAL_STREAMS];
|
||||
s8 db[ATH12K_HTT_TX_UL_MUMIMO_USER_STATS][ATH12K_HTT_RX_NUM_SPATIAL_STREAMS];
|
||||
__le32 red_bw[ATH12K_HTT_RX_NUM_REDUCED_CHAN_TYPES][ATH12K_HTT_RX_NUM_BW_CNTRS];
|
||||
__le32 mumimo_bsc_trig_rx_qos_null_only;
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_RX_NUM_MAX_PEAK_OCCUPANCY_INDEX 10
|
||||
#define ATH12K_HTT_RX_NUM_MAX_CURR_OCCUPANCY_INDEX 10
|
||||
#define ATH12K_HTT_RX_NUM_SQUARE_INDEX 6
|
||||
#define ATH12K_HTT_RX_NUM_MAX_PEAK_SEARCH_INDEX 4
|
||||
#define ATH12K_HTT_RX_NUM_MAX_PENDING_SEARCH_INDEX 4
|
||||
|
||||
struct ath12k_htt_rx_fse_stats_tlv {
|
||||
__le32 fse_enable_cnt;
|
||||
__le32 fse_disable_cnt;
|
||||
__le32 fse_cache_invalidate_entry_cnt;
|
||||
__le32 fse_full_cache_invalidate_cnt;
|
||||
__le32 fse_num_cache_hits_cnt;
|
||||
__le32 fse_num_searches_cnt;
|
||||
__le32 fse_cache_occupancy_peak_cnt[ATH12K_HTT_RX_NUM_MAX_PEAK_OCCUPANCY_INDEX];
|
||||
__le32 fse_cache_occupancy_curr_cnt[ATH12K_HTT_RX_NUM_MAX_CURR_OCCUPANCY_INDEX];
|
||||
__le32 fse_search_stat_square_cnt[ATH12K_HTT_RX_NUM_SQUARE_INDEX];
|
||||
__le32 fse_search_stat_peak_cnt[ATH12K_HTT_RX_NUM_MAX_PEAK_SEARCH_INDEX];
|
||||
__le32 fse_search_stat_pending_cnt[ATH12K_HTT_RX_NUM_MAX_PENDING_SEARCH_INDEX];
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_HTT_TX_BF_RATE_STATS_NUM_MCS_COUNTERS 14
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS 8
|
||||
#define ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8
|
||||
@@ -1417,17 +1809,6 @@ enum ATH12K_HTT_RC_MODE {
|
||||
ATH12K_HTT_RC_MODE_2D_COUNT
|
||||
};
|
||||
|
||||
enum ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE {
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_26,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_52,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_106,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_242,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_484,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_996,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_AX_RU_SIZE_996x2,
|
||||
ATH12K_HTT_TX_RX_PDEV_STATS_NUM_AX_RU_SIZE_CNTRS
|
||||
};
|
||||
|
||||
enum ath12k_htt_stats_rc_mode {
|
||||
ATH12K_HTT_STATS_RC_MODE_DLSU = 0,
|
||||
ATH12K_HTT_STATS_RC_MODE_DLMUMIMO = 1,
|
||||
|
||||
337
drivers/net/wireless/ath/ath12k/debugfs_sta.c
Normal file
337
drivers/net/wireless/ath/ath12k/debugfs_sta.c
Normal file
@@ -0,0 +1,337 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "debugfs_sta.h"
|
||||
#include "core.h"
|
||||
#include "peer.h"
|
||||
#include "debug.h"
|
||||
#include "debugfs_htt_stats.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
static
|
||||
u32 ath12k_dbg_sta_dump_rate_stats(u8 *buf, u32 offset, const int size,
|
||||
bool he_rates_avail,
|
||||
const struct ath12k_rx_peer_rate_stats *stats)
|
||||
{
|
||||
static const char *legacy_rate_str[HAL_RX_MAX_NUM_LEGACY_RATES] = {
|
||||
"1 Mbps", "2 Mbps", "5.5 Mbps", "6 Mbps",
|
||||
"9 Mbps", "11 Mbps", "12 Mbps", "18 Mbps",
|
||||
"24 Mbps", "36 Mbps", "48 Mbps", "54 Mbps"};
|
||||
u8 max_bw = HAL_RX_BW_MAX, max_gi = HAL_RX_GI_MAX, max_mcs = HAL_RX_MAX_NSS;
|
||||
int mcs = 0, bw = 0, nss = 0, gi = 0, bw_num = 0;
|
||||
u32 i, len = offset, max = max_bw * max_gi * max_mcs;
|
||||
bool found;
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nEHT stats:\n");
|
||||
for (i = 0; i <= HAL_RX_MAX_MCS_BE; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"MCS %d: %llu%s", i, stats->be_mcs_count[i],
|
||||
(i + 1) % 8 ? "\t" : "\n");
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nHE stats:\n");
|
||||
for (i = 0; i <= HAL_RX_MAX_MCS_HE; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"MCS %d: %llu%s", i, stats->he_mcs_count[i],
|
||||
(i + 1) % 6 ? "\t" : "\n");
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nVHT stats:\n");
|
||||
for (i = 0; i <= HAL_RX_MAX_MCS_VHT; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"MCS %d: %llu%s", i, stats->vht_mcs_count[i],
|
||||
(i + 1) % 5 ? "\t" : "\n");
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nHT stats:\n");
|
||||
for (i = 0; i <= HAL_RX_MAX_MCS_HT; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"MCS %d: %llu%s", i, stats->ht_mcs_count[i],
|
||||
(i + 1) % 8 ? "\t" : "\n");
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nLegacy stats:\n");
|
||||
for (i = 0; i < HAL_RX_MAX_NUM_LEGACY_RATES; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%s: %llu%s", legacy_rate_str[i],
|
||||
stats->legacy_count[i],
|
||||
(i + 1) % 4 ? "\t" : "\n");
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nNSS stats:\n");
|
||||
for (i = 0; i < HAL_RX_MAX_NSS; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%dx%d: %llu ", i + 1, i + 1,
|
||||
stats->nss_count[i]);
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\n\nGI: 0.8 us %llu 0.4 us %llu 1.6 us %llu 3.2 us %llu\n",
|
||||
stats->gi_count[0],
|
||||
stats->gi_count[1],
|
||||
stats->gi_count[2],
|
||||
stats->gi_count[3]);
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"BW: 20 MHz %llu 40 MHz %llu 80 MHz %llu 160 MHz %llu 320 MHz %llu\n",
|
||||
stats->bw_count[0],
|
||||
stats->bw_count[1],
|
||||
stats->bw_count[2],
|
||||
stats->bw_count[3],
|
||||
stats->bw_count[4]);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
found = false;
|
||||
|
||||
for (mcs = 0; mcs <= HAL_RX_MAX_MCS_HT; mcs++) {
|
||||
if (stats->rx_rate[bw][gi][nss][mcs]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto skip_report;
|
||||
|
||||
switch (bw) {
|
||||
case HAL_RX_BW_20MHZ:
|
||||
bw_num = 20;
|
||||
break;
|
||||
case HAL_RX_BW_40MHZ:
|
||||
bw_num = 40;
|
||||
break;
|
||||
case HAL_RX_BW_80MHZ:
|
||||
bw_num = 80;
|
||||
break;
|
||||
case HAL_RX_BW_160MHZ:
|
||||
bw_num = 160;
|
||||
break;
|
||||
case HAL_RX_BW_320MHZ:
|
||||
bw_num = 320;
|
||||
break;
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\n%d Mhz gi %d us %dx%d : ",
|
||||
bw_num, gi, nss + 1, nss + 1);
|
||||
|
||||
for (mcs = 0; mcs <= HAL_RX_MAX_MCS_HT; mcs++) {
|
||||
if (stats->rx_rate[bw][gi][nss][mcs])
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" %d:%llu", mcs,
|
||||
stats->rx_rate[bw][gi][nss][mcs]);
|
||||
}
|
||||
|
||||
skip_report:
|
||||
if (nss++ >= max_mcs - 1) {
|
||||
nss = 0;
|
||||
if (gi++ >= max_gi - 1) {
|
||||
gi = 0;
|
||||
if (bw < max_bw - 1)
|
||||
bw++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
static ssize_t ath12k_dbg_sta_dump_rx_stats(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_link_sta *link_sta = file->private_data;
|
||||
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
|
||||
const int size = ATH12K_STA_RX_STATS_BUF_SIZE;
|
||||
struct ath12k_hw *ah = ahsta->ahvif->ah;
|
||||
struct ath12k_rx_peer_stats *rx_stats;
|
||||
struct ath12k_link_sta *arsta;
|
||||
u8 link_id = link_sta->link_id;
|
||||
int len = 0, i, ret = 0;
|
||||
bool he_rates_avail;
|
||||
struct ath12k *ar;
|
||||
|
||||
wiphy_lock(ah->hw->wiphy);
|
||||
|
||||
if (!(BIT(link_id) & ahsta->links_map)) {
|
||||
wiphy_unlock(ah->hw->wiphy);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
|
||||
if (!arsta || !arsta->arvif->ar) {
|
||||
wiphy_unlock(ah->hw->wiphy);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ar = arsta->arvif->ar;
|
||||
|
||||
u8 *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->ab->base_lock);
|
||||
|
||||
rx_stats = arsta->rx_stats;
|
||||
if (!rx_stats) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len, "RX peer stats:\n\n");
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
|
||||
rx_stats->num_msdu);
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
|
||||
rx_stats->tcp_msdu_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
|
||||
rx_stats->udp_msdu_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of other MSDUs: %llu\n",
|
||||
rx_stats->other_msdu_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
|
||||
rx_stats->ampdu_msdu_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
|
||||
rx_stats->non_ampdu_msdu_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
|
||||
rx_stats->stbc_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
|
||||
rx_stats->beamformed_count);
|
||||
len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
|
||||
rx_stats->num_mpdu_fcs_ok);
|
||||
len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
|
||||
rx_stats->num_mpdu_fcs_err);
|
||||
|
||||
he_rates_avail = (rx_stats->pream_cnt[HAL_RX_PREAMBLE_11AX] > 1) ? true : false;
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu 11BE %llu\n",
|
||||
rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
|
||||
rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
|
||||
rx_stats->pream_cnt[4], rx_stats->pream_cnt[6]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
|
||||
rx_stats->reception_type[0], rx_stats->reception_type[1],
|
||||
rx_stats->reception_type[2], rx_stats->reception_type[3]);
|
||||
|
||||
len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
|
||||
for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
|
||||
len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nRX Duration:%llu\n",
|
||||
rx_stats->rx_duration);
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\nDCM: %llu\nRU26: %llu\nRU52: %llu\nRU106: %llu\nRU242: %llu\nRU484: %llu\nRU996: %llu\nRU996x2: %llu\n",
|
||||
rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
|
||||
rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
|
||||
rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
|
||||
rx_stats->ru_alloc_cnt[5], rx_stats->ru_alloc_cnt[6]);
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nRX success packet stats:\n");
|
||||
len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
|
||||
&rx_stats->pkt_stats);
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\nRX success byte stats:\n");
|
||||
len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
|
||||
&rx_stats->byte_stats);
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&ar->ab->base_lock);
|
||||
|
||||
if (len)
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
out:
|
||||
wiphy_unlock(ah->hw->wiphy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_rx_stats = {
|
||||
.read = ath12k_dbg_sta_dump_rx_stats,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath12k_dbg_sta_reset_rx_stats(struct file *file,
|
||||
const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_link_sta *link_sta = file->private_data;
|
||||
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
|
||||
struct ath12k_hw *ah = ahsta->ahvif->ah;
|
||||
struct ath12k_rx_peer_stats *rx_stats;
|
||||
struct ath12k_link_sta *arsta;
|
||||
u8 link_id = link_sta->link_id;
|
||||
struct ath12k *ar;
|
||||
bool reset;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool_from_user(buf, count, &reset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!reset)
|
||||
return -EINVAL;
|
||||
|
||||
wiphy_lock(ah->hw->wiphy);
|
||||
|
||||
if (!(BIT(link_id) & ahsta->links_map)) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
|
||||
if (!arsta || !arsta->arvif->ar) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ar = arsta->arvif->ar;
|
||||
|
||||
spin_lock_bh(&ar->ab->base_lock);
|
||||
|
||||
rx_stats = arsta->rx_stats;
|
||||
if (!rx_stats) {
|
||||
spin_unlock_bh(&ar->ab->base_lock);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(rx_stats, 0, sizeof(*rx_stats));
|
||||
spin_unlock_bh(&ar->ab->base_lock);
|
||||
|
||||
ret = count;
|
||||
out:
|
||||
wiphy_unlock(ah->hw->wiphy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_reset_rx_stats = {
|
||||
.write = ath12k_dbg_sta_reset_rx_stats,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath12k_debugfs_link_sta_op_add(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct dentry *dir)
|
||||
{
|
||||
struct ath12k *ar;
|
||||
|
||||
lockdep_assert_wiphy(hw->wiphy);
|
||||
|
||||
ar = ath12k_get_ar_by_vif(hw, vif, link_sta->link_id);
|
||||
if (!ar)
|
||||
return;
|
||||
|
||||
if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) {
|
||||
debugfs_create_file("rx_stats", 0400, dir, link_sta,
|
||||
&fops_rx_stats);
|
||||
debugfs_create_file("reset_rx_stats", 0200, dir, link_sta,
|
||||
&fops_reset_rx_stats);
|
||||
}
|
||||
}
|
||||
24
drivers/net/wireless/ath/ath12k/debugfs_sta.h
Normal file
24
drivers/net/wireless/ath/ath12k/debugfs_sta.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ATH12K_DEBUGFS_STA_H_
|
||||
#define _ATH12K_DEBUGFS_STA_H_
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define ATH12K_STA_RX_STATS_BUF_SIZE (1024 * 16)
|
||||
|
||||
#ifdef CONFIG_ATH12K_DEBUGFS
|
||||
|
||||
void ath12k_debugfs_link_sta_op_add(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct dentry *dir);
|
||||
|
||||
#endif /* CONFIG_ATH12K_DEBUGFS */
|
||||
|
||||
#endif /* _ATH12K_DEBUGFS_STA_H_ */
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
@@ -1315,6 +1315,9 @@ void ath12k_dp_cc_config(struct ath12k_base *ab)
|
||||
u32 wbm_base = HAL_SEQ_WCSS_UMAC_WBM_REG;
|
||||
u32 val = 0;
|
||||
|
||||
if (ath12k_ftm_mode)
|
||||
return;
|
||||
|
||||
ath12k_hif_write32(ab, reo_base + HAL_REO1_SW_COOKIE_CFG0(ab), cmem_base);
|
||||
|
||||
val |= u32_encode_bits(ATH12K_CMEM_ADDR_MSB,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_DP_H
|
||||
@@ -125,7 +125,6 @@ struct ath12k_mon_data {
|
||||
struct sk_buff_head rx_status_q;
|
||||
struct dp_mon_mpdu *mon_mpdu;
|
||||
struct list_head dp_rx_mon_mpdu_list;
|
||||
struct sk_buff *dest_skb_q[DP_MON_MAX_STATUS_BUF];
|
||||
struct dp_mon_tx_ppdu_info *tx_prot_ppdu_info;
|
||||
struct dp_mon_tx_ppdu_info *tx_data_ppdu_info;
|
||||
};
|
||||
@@ -176,7 +175,7 @@ struct ath12k_pdev_dp {
|
||||
#define DP_RXDMA_ERR_DST_RING_SIZE 1024
|
||||
#define DP_RXDMA_MON_STATUS_RING_SIZE 1024
|
||||
#define DP_RXDMA_MONITOR_BUF_RING_SIZE 4096
|
||||
#define DP_RXDMA_MONITOR_DST_RING_SIZE 2048
|
||||
#define DP_RXDMA_MONITOR_DST_RING_SIZE 8092
|
||||
#define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096
|
||||
#define DP_TX_MONITOR_BUF_RING_SIZE 4096
|
||||
#define DP_TX_MONITOR_DEST_RING_SIZE 2048
|
||||
@@ -373,17 +372,24 @@ struct ath12k_dp {
|
||||
};
|
||||
|
||||
/* HTT definitions */
|
||||
#define HTT_TAG_TCL_METADATA_VERSION 5
|
||||
|
||||
#define HTT_TCL_META_DATA_TYPE BIT(0)
|
||||
#define HTT_TCL_META_DATA_VALID_HTT BIT(1)
|
||||
#define HTT_TCL_META_DATA_TYPE GENMASK(1, 0)
|
||||
#define HTT_TCL_META_DATA_VALID_HTT BIT(2)
|
||||
|
||||
/* vdev meta data */
|
||||
#define HTT_TCL_META_DATA_VDEV_ID GENMASK(9, 2)
|
||||
#define HTT_TCL_META_DATA_PDEV_ID GENMASK(11, 10)
|
||||
#define HTT_TCL_META_DATA_HOST_INSPECTED BIT(12)
|
||||
#define HTT_TCL_META_DATA_VDEV_ID GENMASK(10, 3)
|
||||
#define HTT_TCL_META_DATA_PDEV_ID GENMASK(12, 11)
|
||||
#define HTT_TCL_META_DATA_HOST_INSPECTED_MISSION BIT(13)
|
||||
|
||||
/* peer meta data */
|
||||
#define HTT_TCL_META_DATA_PEER_ID GENMASK(15, 2)
|
||||
#define HTT_TCL_META_DATA_PEER_ID GENMASK(15, 3)
|
||||
|
||||
/* Global sequence number */
|
||||
#define HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM 3
|
||||
#define HTT_TCL_META_DATA_GLOBAL_SEQ_HOST_INSPECTED BIT(2)
|
||||
#define HTT_TCL_META_DATA_GLOBAL_SEQ_NUM GENMASK(14, 3)
|
||||
#define HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID 128
|
||||
|
||||
/* HTT tx completion is overlaid in wbm_release_ring */
|
||||
#define HTT_TX_WBM_COMP_INFO0_STATUS GENMASK(16, 13)
|
||||
@@ -414,9 +420,15 @@ enum htt_h2t_msg_type {
|
||||
};
|
||||
|
||||
#define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0)
|
||||
#define HTT_OPTION_TCL_METADATA_VER_V2 2
|
||||
#define HTT_OPTION_TAG GENMASK(7, 0)
|
||||
#define HTT_OPTION_LEN GENMASK(15, 8)
|
||||
#define HTT_OPTION_VALUE GENMASK(31, 16)
|
||||
#define HTT_TCL_METADATA_VER_SZ 4
|
||||
|
||||
struct htt_ver_req_cmd {
|
||||
__le32 ver_reg_info;
|
||||
__le32 tcl_metadata_version;
|
||||
} __packed;
|
||||
|
||||
enum htt_srng_ring_type {
|
||||
@@ -434,8 +446,11 @@ enum htt_srng_ring_id {
|
||||
HTT_HOST1_TO_FW_RXBUF_RING,
|
||||
HTT_HOST2_TO_FW_RXBUF_RING,
|
||||
HTT_RXDMA_NON_MONITOR_DEST_RING,
|
||||
HTT_RXDMA_HOST_BUF_RING2,
|
||||
HTT_TX_MON_HOST2MON_BUF_RING,
|
||||
HTT_TX_MON_MON2HOST_DEST_RING,
|
||||
HTT_RX_MON_HOST2MON_BUF_RING,
|
||||
HTT_RX_MON_MON2HOST_DEST_RING,
|
||||
};
|
||||
|
||||
/* host -> target HTT_SRING_SETUP message
|
||||
@@ -767,8 +782,22 @@ enum htt_stats_internal_ppdu_frametype {
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID GENMASK(23, 16)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS BIT(24)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS BIT(25)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE GENMASK(15, 0)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_OFFSET_VALID BIT(26)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_OFFSET_VALID BIT(26)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_DROP_THRES_VAL BIT(27)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_EN_RXMON BIT(28)
|
||||
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE GENMASK(15, 0)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_MGMT GENMASK(18, 16)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_CTRL GENMASK(21, 19)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_DATA GENMASK(24, 22)
|
||||
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO2_DROP_THRESHOLD GENMASK(9, 0)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO2_EN_LOG_MGMT_TYPE BIT(17)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO2_EN_CTRL_TYPE BIT(18)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO2_EN_LOG_DATA_TYPE BIT(19)
|
||||
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO3_EN_TLV_PKT_OFFSET BIT(0)
|
||||
#define HTT_RX_RING_SELECTION_CFG_CMD_INFO3_PKT_TLV_OFFSET GENMASK(14, 1)
|
||||
|
||||
#define HTT_RX_RING_SELECTION_CFG_RX_PACKET_OFFSET GENMASK(15, 0)
|
||||
#define HTT_RX_RING_SELECTION_CFG_RX_HEADER_OFFSET GENMASK(31, 16)
|
||||
@@ -797,6 +826,7 @@ enum htt_rx_filter_tlv_flags {
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS = BIT(10),
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT = BIT(11),
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE = BIT(12),
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_START_USER_INFO = BIT(13),
|
||||
};
|
||||
|
||||
enum htt_rx_mgmt_pkt_filter_tlv_flags0 {
|
||||
@@ -1085,6 +1115,21 @@ enum htt_rx_data_pkt_filter_tlv_flasg3 {
|
||||
HTT_RX_FILTER_TLV_FLAGS_PER_MSDU_HEADER | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_ATTENTION)
|
||||
|
||||
#define HTT_RX_MON_FILTER_TLV_FLAGS_MON_DEST_RING \
|
||||
(HTT_RX_FILTER_TLV_FLAGS_MPDU_START | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_MSDU_START | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_RX_PACKET | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_MSDU_END | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_MPDU_END | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PER_MSDU_HEADER | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
|
||||
HTT_RX_FILTER_TLV_FLAGS_PPDU_START_USER_INFO)
|
||||
|
||||
/* msdu start. mpdu end, attention, rx hdr tlv's are not subscribed */
|
||||
#define HTT_RX_TLV_FLAGS_RXDMA_RING \
|
||||
(HTT_RX_FILTER_TLV_FLAGS_MPDU_START | \
|
||||
@@ -1113,6 +1158,10 @@ struct htt_rx_ring_selection_cfg_cmd {
|
||||
__le32 info3;
|
||||
} __packed;
|
||||
|
||||
#define HTT_RX_RING_TLV_DROP_THRESHOLD_VALUE 32
|
||||
#define HTT_RX_RING_DEFAULT_DMA_LENGTH 0x7
|
||||
#define HTT_RX_RING_PKT_TLV_OFFSET 0x1
|
||||
|
||||
struct htt_rx_ring_tlv_filter {
|
||||
u32 rx_filter; /* see htt_rx_filter_tlv_flags */
|
||||
u32 pkt_filter_flags0; /* MGMT */
|
||||
@@ -1130,6 +1179,17 @@ struct htt_rx_ring_tlv_filter {
|
||||
u16 rx_mpdu_start_wmask;
|
||||
u16 rx_mpdu_end_wmask;
|
||||
u32 rx_msdu_end_wmask;
|
||||
u32 conf_len_ctrl;
|
||||
u32 conf_len_mgmt;
|
||||
u32 conf_len_data;
|
||||
u16 rx_drop_threshold;
|
||||
bool enable_log_mgmt_type;
|
||||
bool enable_log_ctrl_type;
|
||||
bool enable_log_data_type;
|
||||
bool enable_rx_tlv_offset;
|
||||
u16 rx_tlv_offset;
|
||||
bool drop_threshold_valid;
|
||||
bool rxmon_disable;
|
||||
};
|
||||
|
||||
#define HTT_STATS_FRAME_CTRL_TYPE_MGMT 0x0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_DP_MON_H
|
||||
@@ -77,14 +77,11 @@ struct dp_mon_tx_ppdu_info {
|
||||
enum hal_rx_mon_status
|
||||
ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
|
||||
struct ath12k_mon_data *pmon,
|
||||
int mac_id, struct sk_buff *skb,
|
||||
struct sk_buff *skb,
|
||||
struct napi_struct *napi);
|
||||
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
|
||||
struct dp_rxdma_mon_ring *buf_ring,
|
||||
int req_entries);
|
||||
int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id,
|
||||
int *budget, enum dp_monitor_mode monitor_mode,
|
||||
struct napi_struct *napi);
|
||||
int ath12k_dp_mon_process_ring(struct ath12k_base *ab, int mac_id,
|
||||
struct napi_struct *napi, int budget,
|
||||
enum dp_monitor_mode monitor_mode);
|
||||
@@ -96,11 +93,9 @@ ath12k_dp_mon_tx_status_get_num_user(u16 tlv_tag,
|
||||
enum hal_rx_mon_status
|
||||
ath12k_dp_mon_tx_parse_mon_status(struct ath12k *ar,
|
||||
struct ath12k_mon_data *pmon,
|
||||
int mac_id,
|
||||
struct sk_buff *skb,
|
||||
struct napi_struct *napi,
|
||||
u32 ppdu_id);
|
||||
void ath12k_dp_mon_rx_process_ulofdma(struct hal_rx_mon_ppdu_info *ppdu_info);
|
||||
int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id,
|
||||
struct napi_struct *napi, int *budget);
|
||||
int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget, struct napi_struct *napi);
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
@@ -2392,6 +2392,23 @@ static void ath12k_dp_rx_h_rate(struct ath12k *ar, struct hal_rx_desc *rx_desc,
|
||||
rx_status->he_gi = ath12k_he_gi_to_nl80211_he_gi(sgi);
|
||||
rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw);
|
||||
break;
|
||||
case RX_MSDU_START_PKT_TYPE_11BE:
|
||||
rx_status->rate_idx = rate_mcs;
|
||||
|
||||
if (rate_mcs > ATH12K_EHT_MCS_MAX) {
|
||||
ath12k_warn(ar->ab,
|
||||
"Received with invalid mcs in EHT mode %d\n",
|
||||
rate_mcs);
|
||||
break;
|
||||
}
|
||||
|
||||
rx_status->encoding = RX_ENC_EHT;
|
||||
rx_status->nss = nss;
|
||||
rx_status->eht.gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(sgi);
|
||||
rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2486,7 +2503,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_DATA,
|
||||
"rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
"rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
msdu,
|
||||
msdu->len,
|
||||
peer ? peer->addr : NULL,
|
||||
@@ -2497,6 +2514,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
|
||||
(status->encoding == RX_ENC_HT) ? "ht" : "",
|
||||
(status->encoding == RX_ENC_VHT) ? "vht" : "",
|
||||
(status->encoding == RX_ENC_HE) ? "he" : "",
|
||||
(status->encoding == RX_ENC_EHT) ? "eht" : "",
|
||||
(status->bw == RATE_INFO_BW_40) ? "40" : "",
|
||||
(status->bw == RATE_INFO_BW_80) ? "80" : "",
|
||||
(status->bw == RATE_INFO_BW_160) ? "160" : "",
|
||||
@@ -2530,6 +2548,29 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
|
||||
ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi);
|
||||
}
|
||||
|
||||
static bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
|
||||
struct hal_rx_desc *rx_desc,
|
||||
struct sk_buff *msdu)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
u8 decap_type;
|
||||
u32 hdr_len;
|
||||
|
||||
decap_type = ath12k_dp_rx_h_decap_type(ab, rx_desc);
|
||||
if (decap_type != DP_RX_DECAP_TYPE_NATIVE_WIFI)
|
||||
return true;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if ((likely(hdr_len <= DP_MAX_NWIFI_HDR_LEN)))
|
||||
return true;
|
||||
|
||||
ab->soc_stats.invalid_rbm++;
|
||||
WARN_ON_ONCE(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
|
||||
struct sk_buff *msdu,
|
||||
struct sk_buff_head *msdu_list,
|
||||
@@ -2588,6 +2629,11 @@ static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
|
||||
ret = -EINVAL;
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
ath12k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
|
||||
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status);
|
||||
|
||||
@@ -2978,6 +3024,9 @@ mic_fail:
|
||||
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
|
||||
skb_pull(msdu, hal_rx_desc_sz);
|
||||
|
||||
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu)))
|
||||
return -EINVAL;
|
||||
|
||||
ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
|
||||
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
|
||||
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
|
||||
@@ -3720,6 +3769,9 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
|
||||
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
||||
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
||||
}
|
||||
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
|
||||
return -EINVAL;
|
||||
|
||||
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
||||
|
||||
ath12k_dp_rx_h_mpdu(ar, msdu, desc, status);
|
||||
@@ -3764,7 +3816,7 @@ static bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
return drop;
|
||||
}
|
||||
|
||||
static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
static bool ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
@@ -3782,6 +3834,9 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
||||
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
||||
|
||||
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
|
||||
return true;
|
||||
|
||||
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
||||
|
||||
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
|
||||
@@ -3789,6 +3844,7 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
|
||||
ath12k_dp_rx_h_undecap(ar, msdu, desc,
|
||||
HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
@@ -3807,7 +3863,7 @@ static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
|
||||
err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
|
||||
if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {
|
||||
ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status);
|
||||
drop = ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
@@ -4032,7 +4088,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
|
||||
hw_links[hw_link_id].pdev_idx);
|
||||
ar = partner_ab->pdevs[pdev_id].ar;
|
||||
|
||||
if (!ar || !rcu_dereference(ar->ab->pdevs_active[hw_link_id])) {
|
||||
if (!ar || !rcu_dereference(ar->ab->pdevs_active[pdev_id])) {
|
||||
dev_kfree_skb_any(msdu);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef ATH12K_DP_RX_H
|
||||
#define ATH12K_DP_RX_H
|
||||
@@ -79,6 +79,9 @@ static inline u32 ath12k_he_gi_to_nl80211_he_gi(u8 sgi)
|
||||
case RX_MSDU_START_SGI_3_2_US:
|
||||
ret = NL80211_RATE_INFO_HE_GI_3_2;
|
||||
break;
|
||||
default:
|
||||
ret = NL80211_RATE_INFO_HE_GI_0_8;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -135,9 +138,6 @@ u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab,
|
||||
struct hal_rx_desc *desc);
|
||||
void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct hal_rx_desc *rx_desc,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
struct ath12k_peer *
|
||||
ath12k_dp_rx_h_find_peer(struct ath12k_base *ab, struct sk_buff *msdu);
|
||||
|
||||
int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab);
|
||||
int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab);
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "dp_tx.h"
|
||||
#include "debug.h"
|
||||
#include "hw.h"
|
||||
#include "peer.h"
|
||||
#include "mac.h"
|
||||
|
||||
static enum hal_tcl_encap_type
|
||||
ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb)
|
||||
@@ -117,7 +119,7 @@ static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
|
||||
le32_encode_bits(ti->data_len,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_LEN);
|
||||
|
||||
tcl_ext_cmd->info1 = le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
|
||||
tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
|
||||
le32_encode_bits(ti->encap_type,
|
||||
HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) |
|
||||
le32_encode_bits(ti->encrypt_type,
|
||||
@@ -217,7 +219,7 @@ out:
|
||||
}
|
||||
|
||||
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
@@ -290,13 +292,27 @@ tcl_ring_sel:
|
||||
msdu_ext_desc = true;
|
||||
}
|
||||
|
||||
if (gsn_valid) {
|
||||
/* Reset and Initialize meta_data_flags with Global Sequence
|
||||
* Number (GSN) info.
|
||||
*/
|
||||
ti.meta_data_flags =
|
||||
u32_encode_bits(HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM,
|
||||
HTT_TCL_META_DATA_TYPE) |
|
||||
u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM);
|
||||
}
|
||||
|
||||
ti.encap_type = ath12k_dp_tx_get_encap_type(arvif, skb);
|
||||
ti.addr_search_flags = arvif->hal_addr_search_flags;
|
||||
ti.search_type = arvif->search_type;
|
||||
ti.type = HAL_TCL_DESC_TYPE_BUFFER;
|
||||
ti.pkt_offset = 0;
|
||||
ti.lmac_id = ar->lmac_id;
|
||||
|
||||
ti.vdev_id = arvif->vdev_id;
|
||||
if (gsn_valid)
|
||||
ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
|
||||
|
||||
ti.bss_ast_hash = arvif->ast_hash;
|
||||
ti.bss_ast_idx = arvif->ast_idx;
|
||||
ti.dscp_tid_tbl_idx = 0;
|
||||
@@ -368,6 +384,7 @@ map:
|
||||
add_htt_metadata = true;
|
||||
msdu_ext_desc = true;
|
||||
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
|
||||
ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
|
||||
ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
|
||||
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
|
||||
}
|
||||
@@ -398,6 +415,7 @@ map:
|
||||
if (ret < 0) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_DP_TX,
|
||||
"Failed to add HTT meta data, dropping packet\n");
|
||||
kfree_skb(skb_ext_desc);
|
||||
goto fail_unmap_dma;
|
||||
}
|
||||
}
|
||||
@@ -558,13 +576,13 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab,
|
||||
|
||||
switch (wbm_status) {
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK:
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
|
||||
ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
|
||||
ts.ack_rssi = le32_get_bits(status_desc->info2,
|
||||
HTT_TX_WBM_COMP_INFO2_ACK_RSSI);
|
||||
ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts);
|
||||
break;
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
|
||||
case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
|
||||
ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring);
|
||||
@@ -580,6 +598,124 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab,
|
||||
}
|
||||
}
|
||||
|
||||
static void ath12k_dp_tx_update_txcompl(struct ath12k *ar, struct hal_tx_status *ts)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_peer *peer;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath12k_sta *ahsta;
|
||||
struct ath12k_link_sta *arsta;
|
||||
struct rate_info txrate = {0};
|
||||
u16 rate, ru_tones;
|
||||
u8 rate_idx = 0;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&ab->base_lock);
|
||||
peer = ath12k_peer_find_by_id(ab, ts->peer_id);
|
||||
if (!peer || !peer->sta) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_DP_TX,
|
||||
"failed to find the peer by id %u\n", ts->peer_id);
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
return;
|
||||
}
|
||||
sta = peer->sta;
|
||||
ahsta = ath12k_sta_to_ahsta(sta);
|
||||
arsta = &ahsta->deflink;
|
||||
|
||||
/* This is to prefer choose the real NSS value arsta->last_txrate.nss,
|
||||
* if it is invalid, then choose the NSS value while assoc.
|
||||
*/
|
||||
if (arsta->last_txrate.nss)
|
||||
txrate.nss = arsta->last_txrate.nss;
|
||||
else
|
||||
txrate.nss = arsta->peer_nss;
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
|
||||
switch (ts->pkt_type) {
|
||||
case HAL_TX_RATE_STATS_PKT_TYPE_11A:
|
||||
case HAL_TX_RATE_STATS_PKT_TYPE_11B:
|
||||
ret = ath12k_mac_hw_ratecode_to_legacy_rate(ts->mcs,
|
||||
ts->pkt_type,
|
||||
&rate_idx,
|
||||
&rate);
|
||||
if (ret < 0) {
|
||||
ath12k_warn(ab, "Invalid tx legacy rate %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
txrate.legacy = rate;
|
||||
break;
|
||||
case HAL_TX_RATE_STATS_PKT_TYPE_11N:
|
||||
if (ts->mcs > ATH12K_HT_MCS_MAX) {
|
||||
ath12k_warn(ab, "Invalid HT mcs index %d\n", ts->mcs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (txrate.nss != 0)
|
||||
txrate.mcs = ts->mcs + 8 * (txrate.nss - 1);
|
||||
|
||||
txrate.flags = RATE_INFO_FLAGS_MCS;
|
||||
|
||||
if (ts->sgi)
|
||||
txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
break;
|
||||
case HAL_TX_RATE_STATS_PKT_TYPE_11AC:
|
||||
if (ts->mcs > ATH12K_VHT_MCS_MAX) {
|
||||
ath12k_warn(ab, "Invalid VHT mcs index %d\n", ts->mcs);
|
||||
return;
|
||||
}
|
||||
|
||||
txrate.mcs = ts->mcs;
|
||||
txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
|
||||
|
||||
if (ts->sgi)
|
||||
txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
break;
|
||||
case HAL_TX_RATE_STATS_PKT_TYPE_11AX:
|
||||
if (ts->mcs > ATH12K_HE_MCS_MAX) {
|
||||
ath12k_warn(ab, "Invalid HE mcs index %d\n", ts->mcs);
|
||||
return;
|
||||
}
|
||||
|
||||
txrate.mcs = ts->mcs;
|
||||
txrate.flags = RATE_INFO_FLAGS_HE_MCS;
|
||||
txrate.he_gi = ath12k_he_gi_to_nl80211_he_gi(ts->sgi);
|
||||
break;
|
||||
case HAL_TX_RATE_STATS_PKT_TYPE_11BE:
|
||||
if (ts->mcs > ATH12K_EHT_MCS_MAX) {
|
||||
ath12k_warn(ab, "Invalid EHT mcs index %d\n", ts->mcs);
|
||||
return;
|
||||
}
|
||||
|
||||
txrate.mcs = ts->mcs;
|
||||
txrate.flags = RATE_INFO_FLAGS_EHT_MCS;
|
||||
txrate.eht_gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(ts->sgi);
|
||||
break;
|
||||
default:
|
||||
ath12k_warn(ab, "Invalid tx pkt type: %d\n", ts->pkt_type);
|
||||
return;
|
||||
}
|
||||
|
||||
txrate.bw = ath12k_mac_bw_to_mac80211_bw(ts->bw);
|
||||
|
||||
if (ts->ofdma && ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
|
||||
txrate.bw = RATE_INFO_BW_HE_RU;
|
||||
ru_tones = ath12k_mac_he_convert_tones_to_ru_tones(ts->tones);
|
||||
txrate.he_ru_alloc =
|
||||
ath12k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);
|
||||
}
|
||||
|
||||
if (ts->ofdma && ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11BE) {
|
||||
txrate.bw = RATE_INFO_BW_EHT_RU;
|
||||
txrate.eht_ru_alloc =
|
||||
ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(ts->tones);
|
||||
}
|
||||
|
||||
spin_lock_bh(&ab->base_lock);
|
||||
arsta->txrate = txrate;
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
}
|
||||
|
||||
static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
|
||||
struct sk_buff *msdu,
|
||||
struct hal_tx_status *ts)
|
||||
@@ -658,6 +794,8 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
|
||||
* Might end up reporting it out-of-band from HTT stats.
|
||||
*/
|
||||
|
||||
ath12k_dp_tx_update_txcompl(ar, ts);
|
||||
|
||||
ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu);
|
||||
|
||||
exit:
|
||||
@@ -668,6 +806,8 @@ static void ath12k_dp_tx_status_parse(struct ath12k_base *ab,
|
||||
struct hal_wbm_completion_ring_tx *desc,
|
||||
struct hal_tx_status *ts)
|
||||
{
|
||||
u32 info0 = le32_to_cpu(desc->rate_stats.info0);
|
||||
|
||||
ts->buf_rel_source =
|
||||
le32_get_bits(desc->info0, HAL_WBM_COMPL_TX_INFO0_REL_SRC_MODULE);
|
||||
if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW &&
|
||||
@@ -682,10 +822,17 @@ static void ath12k_dp_tx_status_parse(struct ath12k_base *ab,
|
||||
|
||||
ts->ppdu_id = le32_get_bits(desc->info1,
|
||||
HAL_WBM_COMPL_TX_INFO1_TQM_STATUS_NUMBER);
|
||||
if (le32_to_cpu(desc->rate_stats.info0) & HAL_TX_RATE_STATS_INFO0_VALID)
|
||||
ts->rate_stats = le32_to_cpu(desc->rate_stats.info0);
|
||||
else
|
||||
ts->rate_stats = 0;
|
||||
|
||||
ts->peer_id = le32_get_bits(desc->info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID);
|
||||
|
||||
if (info0 & HAL_TX_RATE_STATS_INFO0_VALID) {
|
||||
ts->pkt_type = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_PKT_TYPE);
|
||||
ts->mcs = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_MCS);
|
||||
ts->sgi = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_SGI);
|
||||
ts->bw = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_BW);
|
||||
ts->tones = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_TONES_IN_RU);
|
||||
ts->ofdma = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_OFDMA_TX);
|
||||
}
|
||||
}
|
||||
|
||||
void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id)
|
||||
@@ -814,7 +961,7 @@ ath12k_dp_tx_get_ring_id_type(struct ath12k_base *ab,
|
||||
*htt_ring_type = HTT_HW_TO_SW_RING;
|
||||
break;
|
||||
case HAL_RXDMA_MONITOR_BUF:
|
||||
*htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING;
|
||||
*htt_ring_id = HTT_RX_MON_HOST2MON_BUF_RING;
|
||||
*htt_ring_type = HTT_SW_TO_HW_RING;
|
||||
break;
|
||||
case HAL_RXDMA_MONITOR_STATUS:
|
||||
@@ -822,7 +969,7 @@ ath12k_dp_tx_get_ring_id_type(struct ath12k_base *ab,
|
||||
*htt_ring_type = HTT_SW_TO_HW_RING;
|
||||
break;
|
||||
case HAL_RXDMA_MONITOR_DST:
|
||||
*htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING;
|
||||
*htt_ring_id = HTT_RX_MON_MON2HOST_DEST_RING;
|
||||
*htt_ring_type = HTT_HW_TO_SW_RING;
|
||||
break;
|
||||
case HAL_RXDMA_MONITOR_DESC:
|
||||
@@ -971,7 +1118,14 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab)
|
||||
skb_put(skb, len);
|
||||
cmd = (struct htt_ver_req_cmd *)skb->data;
|
||||
cmd->ver_reg_info = le32_encode_bits(HTT_H2T_MSG_TYPE_VERSION_REQ,
|
||||
HTT_VER_REQ_INFO_MSG_ID);
|
||||
HTT_OPTION_TAG);
|
||||
|
||||
cmd->tcl_metadata_version = le32_encode_bits(HTT_TAG_TCL_METADATA_VERSION,
|
||||
HTT_OPTION_TAG) |
|
||||
le32_encode_bits(HTT_TCL_METADATA_VER_SZ,
|
||||
HTT_OPTION_LEN) |
|
||||
le32_encode_bits(HTT_OPTION_TCL_METADATA_VER_V2,
|
||||
HTT_OPTION_VALUE);
|
||||
|
||||
ret = ath12k_htc_send(&ab->htc, dp->eid, skb);
|
||||
if (ret) {
|
||||
@@ -1077,15 +1231,46 @@ int ath12k_dp_tx_htt_rx_filter_setup(struct ath12k_base *ab, u32 ring_id,
|
||||
cmd->info0 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP),
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS);
|
||||
cmd->info0 |= le32_encode_bits(tlv_filter->offset_valid,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_OFFSET_VALID);
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO0_OFFSET_VALID);
|
||||
cmd->info0 |=
|
||||
le32_encode_bits(tlv_filter->drop_threshold_valid,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO0_DROP_THRES_VAL);
|
||||
cmd->info0 |= le32_encode_bits(!tlv_filter->rxmon_disable,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO0_EN_RXMON);
|
||||
|
||||
cmd->info1 = le32_encode_bits(rx_buf_size,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE);
|
||||
cmd->info1 |= le32_encode_bits(tlv_filter->conf_len_mgmt,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_MGMT);
|
||||
cmd->info1 |= le32_encode_bits(tlv_filter->conf_len_ctrl,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_CTRL);
|
||||
cmd->info1 |= le32_encode_bits(tlv_filter->conf_len_data,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_DATA);
|
||||
cmd->pkt_type_en_flags0 = cpu_to_le32(tlv_filter->pkt_filter_flags0);
|
||||
cmd->pkt_type_en_flags1 = cpu_to_le32(tlv_filter->pkt_filter_flags1);
|
||||
cmd->pkt_type_en_flags2 = cpu_to_le32(tlv_filter->pkt_filter_flags2);
|
||||
cmd->pkt_type_en_flags3 = cpu_to_le32(tlv_filter->pkt_filter_flags3);
|
||||
cmd->rx_filter_tlv = cpu_to_le32(tlv_filter->rx_filter);
|
||||
|
||||
cmd->info2 = le32_encode_bits(tlv_filter->rx_drop_threshold,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO2_DROP_THRESHOLD);
|
||||
cmd->info2 |=
|
||||
le32_encode_bits(tlv_filter->enable_log_mgmt_type,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO2_EN_LOG_MGMT_TYPE);
|
||||
cmd->info2 |=
|
||||
le32_encode_bits(tlv_filter->enable_log_ctrl_type,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO2_EN_CTRL_TYPE);
|
||||
cmd->info2 |=
|
||||
le32_encode_bits(tlv_filter->enable_log_data_type,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO2_EN_LOG_DATA_TYPE);
|
||||
|
||||
cmd->info3 =
|
||||
le32_encode_bits(tlv_filter->enable_rx_tlv_offset,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO3_EN_TLV_PKT_OFFSET);
|
||||
cmd->info3 |=
|
||||
le32_encode_bits(tlv_filter->rx_tlv_offset,
|
||||
HTT_RX_RING_SELECTION_CFG_CMD_INFO3_PKT_TLV_OFFSET);
|
||||
|
||||
if (tlv_filter->offset_valid) {
|
||||
cmd->rx_packet_offset =
|
||||
le32_encode_bits(tlv_filter->rx_packet_offset,
|
||||
@@ -1210,15 +1395,28 @@ int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset)
|
||||
int ath12k_dp_tx_htt_rx_monitor_mode_ring_config(struct ath12k *ar, bool reset)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
struct htt_rx_ring_tlv_filter tlv_filter = {0};
|
||||
int ret, ring_id;
|
||||
int ret, ring_id, i;
|
||||
|
||||
ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
|
||||
tlv_filter.offset_valid = false;
|
||||
|
||||
if (!reset) {
|
||||
tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING;
|
||||
tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_DEST_RING;
|
||||
|
||||
tlv_filter.drop_threshold_valid = true;
|
||||
tlv_filter.rx_drop_threshold = HTT_RX_RING_TLV_DROP_THRESHOLD_VALUE;
|
||||
|
||||
tlv_filter.enable_log_mgmt_type = true;
|
||||
tlv_filter.enable_log_ctrl_type = true;
|
||||
tlv_filter.enable_log_data_type = true;
|
||||
|
||||
tlv_filter.conf_len_ctrl = HTT_RX_RING_DEFAULT_DMA_LENGTH;
|
||||
tlv_filter.conf_len_mgmt = HTT_RX_RING_DEFAULT_DMA_LENGTH;
|
||||
tlv_filter.conf_len_data = HTT_RX_RING_DEFAULT_DMA_LENGTH;
|
||||
|
||||
tlv_filter.enable_rx_tlv_offset = true;
|
||||
tlv_filter.rx_tlv_offset = HTT_RX_RING_PKT_TLV_OFFSET;
|
||||
|
||||
tlv_filter.pkt_filter_flags0 =
|
||||
HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 |
|
||||
HTT_RX_MON_MO_MGMT_FILTER_FLAGS0;
|
||||
@@ -1236,14 +1434,19 @@ int ath12k_dp_tx_htt_rx_monitor_mode_ring_config(struct ath12k *ar, bool reset)
|
||||
}
|
||||
|
||||
if (ab->hw_params->rxdma1_enable) {
|
||||
ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, 0,
|
||||
HAL_RXDMA_MONITOR_BUF,
|
||||
DP_RXDMA_REFILL_RING_SIZE,
|
||||
&tlv_filter);
|
||||
if (ret) {
|
||||
ath12k_err(ab,
|
||||
"failed to setup filter for monitor buf %d\n", ret);
|
||||
return ret;
|
||||
for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) {
|
||||
ring_id = ar->dp.rxdma_mon_dst_ring[i].ring_id;
|
||||
ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id,
|
||||
ar->dp.mac_id + i,
|
||||
HAL_RXDMA_MONITOR_DST,
|
||||
DP_RXDMA_REFILL_RING_SIZE,
|
||||
&tlv_filter);
|
||||
if (ret) {
|
||||
ath12k_err(ab,
|
||||
"failed to setup filter for monitor buf %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_DP_TX_H
|
||||
@@ -17,7 +17,7 @@ struct ath12k_dp_htt_wbm_tx_status {
|
||||
|
||||
int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);
|
||||
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct sk_buff *skb);
|
||||
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn);
|
||||
void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id);
|
||||
|
||||
int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask);
|
||||
|
||||
@@ -2968,9 +2968,8 @@ struct hal_mon_buf_ring {
|
||||
|
||||
#define HAL_MON_DEST_COOKIE_BUF_ID GENMASK(17, 0)
|
||||
|
||||
#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(15, 0)
|
||||
#define HAL_MON_DEST_INFO0_FLUSH_DETECTED BIT(16)
|
||||
#define HAL_MON_DEST_INFO0_END_OF_PPDU BIT(17)
|
||||
#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(11, 0)
|
||||
#define HAL_MON_DEST_INFO0_END_REASON GENMASK(17, 16)
|
||||
#define HAL_MON_DEST_INFO0_INITIATOR BIT(18)
|
||||
#define HAL_MON_DEST_INFO0_EMPTY_DESC BIT(19)
|
||||
#define HAL_MON_DEST_INFO0_RING_ID GENMASK(27, 20)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_HAL_RX_H
|
||||
@@ -22,9 +22,6 @@ struct hal_rx_wbm_rel_info {
|
||||
#define HAL_INVALID_PEERID 0x3fff
|
||||
#define VHT_SIG_SU_NSS_MASK 0x7
|
||||
|
||||
#define HAL_RX_MAX_MCS 12
|
||||
#define HAL_RX_MAX_NSS 8
|
||||
|
||||
#define HAL_RX_MPDU_INFO_PN_GET_BYTE1(__val) \
|
||||
le32_get_bits((__val), GENMASK(7, 0))
|
||||
|
||||
@@ -71,6 +68,8 @@ enum hal_rx_preamble {
|
||||
HAL_RX_PREAMBLE_11N,
|
||||
HAL_RX_PREAMBLE_11AC,
|
||||
HAL_RX_PREAMBLE_11AX,
|
||||
HAL_RX_PREAMBLE_11BA,
|
||||
HAL_RX_PREAMBLE_11BE,
|
||||
HAL_RX_PREAMBLE_MAX,
|
||||
};
|
||||
|
||||
@@ -108,6 +107,9 @@ enum hal_rx_mon_status {
|
||||
HAL_RX_MON_STATUS_PPDU_NOT_DONE,
|
||||
HAL_RX_MON_STATUS_PPDU_DONE,
|
||||
HAL_RX_MON_STATUS_BUF_DONE,
|
||||
HAL_RX_MON_STATUS_BUF_ADDR,
|
||||
HAL_RX_MON_STATUS_MPDU_END,
|
||||
HAL_RX_MON_STATUS_MSDU_END,
|
||||
};
|
||||
|
||||
#define HAL_RX_MAX_MPDU 256
|
||||
@@ -143,10 +145,43 @@ struct hal_rx_user_status {
|
||||
u32 mpdu_fcs_ok_bitmap[HAL_RX_NUM_WORDS_PER_PPDU_BITMAP];
|
||||
u32 mpdu_ok_byte_count;
|
||||
u32 mpdu_err_byte_count;
|
||||
bool ampdu_present;
|
||||
u16 ampdu_id;
|
||||
};
|
||||
|
||||
#define HAL_MAX_UL_MU_USERS 37
|
||||
|
||||
struct hal_rx_u_sig_info {
|
||||
bool ul_dl;
|
||||
u8 bw;
|
||||
u8 ppdu_type_comp_mode;
|
||||
u8 eht_sig_mcs;
|
||||
u8 num_eht_sig_sym;
|
||||
struct ieee80211_radiotap_eht_usig usig;
|
||||
};
|
||||
|
||||
#define HAL_RX_MON_MAX_AGGR_SIZE 128
|
||||
|
||||
struct hal_rx_tlv_aggr_info {
|
||||
bool in_progress;
|
||||
u16 cur_len;
|
||||
u16 tlv_tag;
|
||||
u8 buf[HAL_RX_MON_MAX_AGGR_SIZE];
|
||||
};
|
||||
|
||||
struct hal_rx_radiotap_eht {
|
||||
__le32 known;
|
||||
__le32 data[9];
|
||||
};
|
||||
|
||||
#define EHT_MAX_USER_INFO 4
|
||||
|
||||
struct hal_rx_eht_info {
|
||||
u8 num_user_info;
|
||||
struct hal_rx_radiotap_eht eht;
|
||||
u32 user_info[EHT_MAX_USER_INFO];
|
||||
};
|
||||
|
||||
struct hal_rx_mon_ppdu_info {
|
||||
u32 ppdu_id;
|
||||
u32 last_ppdu_id;
|
||||
@@ -227,10 +262,15 @@ struct hal_rx_mon_ppdu_info {
|
||||
u8 addr4[ETH_ALEN];
|
||||
struct hal_rx_user_status userstats[HAL_MAX_UL_MU_USERS];
|
||||
u8 userid;
|
||||
u16 ampdu_id[HAL_MAX_UL_MU_USERS];
|
||||
bool first_msdu_in_mpdu;
|
||||
bool is_ampdu;
|
||||
u8 medium_prot_type;
|
||||
bool ppdu_continuation;
|
||||
bool eht_usig;
|
||||
struct hal_rx_u_sig_info u_sig_info;
|
||||
bool is_eht;
|
||||
struct hal_rx_eht_info eht_info;
|
||||
struct hal_rx_tlv_aggr_info tlv_aggr;
|
||||
};
|
||||
|
||||
#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0)
|
||||
@@ -641,6 +681,395 @@ struct hal_rx_resp_req_info {
|
||||
#define HAL_RX_MPDU_ERR_MPDU_LEN BIT(6)
|
||||
#define HAL_RX_MPDU_ERR_UNENCRYPTED_FRAME BIT(7)
|
||||
|
||||
#define HAL_RX_PHY_CMN_USER_INFO0_GI GENMASK(17, 16)
|
||||
|
||||
struct hal_phyrx_common_user_info {
|
||||
__le32 rsvd[2];
|
||||
__le32 info0;
|
||||
__le32 rsvd1;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_SPATIAL_REUSE GENMASK(3, 0)
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_GI_LTF GENMASK(5, 4)
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_NUM_LTF_SYM GENMASK(8, 6)
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_NSS GENMASK(10, 7)
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_BEAMFORMED BIT(11)
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_DISREGARD GENMASK(13, 12)
|
||||
#define HAL_RX_EHT_SIG_NDP_CMN_INFO0_CRC GENMASK(17, 14)
|
||||
|
||||
struct hal_eht_sig_ndp_cmn_eb {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_SPATIAL_REUSE GENMASK(3, 0)
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_GI_LTF GENMASK(5, 4)
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_NUM_LTF_SYM GENMASK(8, 6)
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_LDPC_EXTA_SYM BIT(9)
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_PRE_FEC_PAD_FACTOR GENMASK(11, 10)
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_DISAMBIGUITY BIT(12)
|
||||
#define HAL_RX_EHT_SIG_OVERFLOW_INFO0_DISREGARD GENMASK(16, 13)
|
||||
|
||||
struct hal_eht_sig_usig_overflow {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_STA_ID GENMASK(10, 0)
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_MCS GENMASK(14, 11)
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_VALIDATE BIT(15)
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_NSS GENMASK(19, 16)
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_BEAMFORMED BIT(20)
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_CODING BIT(21)
|
||||
#define HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_CRC GENMASK(25, 22)
|
||||
|
||||
struct hal_eht_sig_non_mu_mimo {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_STA_ID GENMASK(10, 0)
|
||||
#define HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_MCS GENMASK(14, 11)
|
||||
#define HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_CODING BIT(15)
|
||||
#define HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_SPATIAL_CODING GENMASK(22, 16)
|
||||
#define HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_CRC GENMASK(26, 23)
|
||||
|
||||
struct hal_eht_sig_mu_mimo {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
union hal_eht_sig_user_field {
|
||||
struct hal_eht_sig_mu_mimo mu_mimo;
|
||||
struct hal_eht_sig_non_mu_mimo n_mu_mimo;
|
||||
};
|
||||
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_SPATIAL_REUSE GENMASK(3, 0)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_GI_LTF GENMASK(5, 4)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_NUM_LTF_SYM GENMASK(8, 6)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_LDPC_EXTA_SYM BIT(9)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_PRE_FEC_PAD_FACTOR GENMASK(11, 10)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_DISAMBIGUITY BIT(12)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_DISREGARD GENMASK(16, 13)
|
||||
#define HAL_RX_EHT_SIG_NON_OFDMA_INFO0_NUM_USERS GENMASK(19, 17)
|
||||
|
||||
struct hal_eht_sig_non_ofdma_cmn_eb {
|
||||
__le32 info0;
|
||||
union hal_eht_sig_user_field user_field;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_SPATIAL_REUSE GENMASK_ULL(3, 0)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_GI_LTF GENMASK_ULL(5, 4)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_NUM_LFT_SYM GENMASK_ULL(8, 6)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_LDPC_EXTRA_SYM BIT(9)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_PRE_FEC_PAD_FACTOR GENMASK_ULL(11, 10)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_PRE_DISAMBIGUITY BIT(12)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_DISREGARD GENMASK_ULL(16, 13)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_RU_ALLOC_1_1 GENMASK_ULL(25, 17)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_RU_ALLOC_1_2 GENMASK_ULL(34, 26)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB1_CRC GENMASK_ULL(30, 27)
|
||||
|
||||
struct hal_eht_sig_ofdma_cmn_eb1 {
|
||||
__le64 info0;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_1 GENMASK_ULL(8, 0)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_2 GENMASK_ULL(17, 9)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_3 GENMASK_ULL(26, 18)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_4 GENMASK_ULL(35, 27)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_5 GENMASK_ULL(44, 36)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_6 GENMASK_ULL(53, 45)
|
||||
#define HAL_RX_EHT_SIG_OFDMA_EB2_MCS GNEMASK_ULL(57, 54)
|
||||
|
||||
struct hal_eht_sig_ofdma_cmn_eb2 {
|
||||
__le64 info0;
|
||||
} __packed;
|
||||
|
||||
struct hal_eht_sig_ofdma_cmn_eb {
|
||||
struct hal_eht_sig_ofdma_cmn_eb1 eb1;
|
||||
struct hal_eht_sig_ofdma_cmn_eb2 eb2;
|
||||
union hal_eht_sig_user_field user_field;
|
||||
} __packed;
|
||||
|
||||
enum hal_eht_bw {
|
||||
HAL_EHT_BW_20,
|
||||
HAL_EHT_BW_40,
|
||||
HAL_EHT_BW_80,
|
||||
HAL_EHT_BW_160,
|
||||
HAL_EHT_BW_320_1,
|
||||
HAL_EHT_BW_320_2,
|
||||
};
|
||||
|
||||
#define HAL_RX_USIG_CMN_INFO0_PHY_VERSION GENMASK(2, 0)
|
||||
#define HAL_RX_USIG_CMN_INFO0_BW GENMASK(5, 3)
|
||||
#define HAL_RX_USIG_CMN_INFO0_UL_DL BIT(6)
|
||||
#define HAL_RX_USIG_CMN_INFO0_BSS_COLOR GENMASK(12, 7)
|
||||
#define HAL_RX_USIG_CMN_INFO0_TXOP GENMASK(19, 13)
|
||||
#define HAL_RX_USIG_CMN_INFO0_DISREGARD GENMASK(25, 20)
|
||||
#define HAL_RX_USIG_CMN_INFO0_VALIDATE BIT(26)
|
||||
|
||||
struct hal_mon_usig_cmn {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_USIG_TB_INFO0_PPDU_TYPE_COMP_MODE GENMASK(1, 0)
|
||||
#define HAL_RX_USIG_TB_INFO0_VALIDATE BIT(2)
|
||||
#define HAL_RX_USIG_TB_INFO0_SPATIAL_REUSE_1 GENMASK(6, 3)
|
||||
#define HAL_RX_USIG_TB_INFO0_SPATIAL_REUSE_2 GENMASK(10, 7)
|
||||
#define HAL_RX_USIG_TB_INFO0_DISREGARD_1 GENMASK(15, 11)
|
||||
#define HAL_RX_USIG_TB_INFO0_CRC GENMASK(19, 16)
|
||||
#define HAL_RX_USIG_TB_INFO0_TAIL GENMASK(25, 20)
|
||||
#define HAL_RX_USIG_TB_INFO0_RX_INTEG_CHECK_PASS BIT(31)
|
||||
|
||||
struct hal_mon_usig_tb {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_USIG_MU_INFO0_PPDU_TYPE_COMP_MODE GENMASK(1, 0)
|
||||
#define HAL_RX_USIG_MU_INFO0_VALIDATE_1 BIT(2)
|
||||
#define HAL_RX_USIG_MU_INFO0_PUNC_CH_INFO GENMASK(7, 3)
|
||||
#define HAL_RX_USIG_MU_INFO0_VALIDATE_2 BIT(8)
|
||||
#define HAL_RX_USIG_MU_INFO0_EHT_SIG_MCS GENMASK(10, 9)
|
||||
#define HAL_RX_USIG_MU_INFO0_NUM_EHT_SIG_SYM GENMASK(15, 11)
|
||||
#define HAL_RX_USIG_MU_INFO0_CRC GENMASK(20, 16)
|
||||
#define HAL_RX_USIG_MU_INFO0_TAIL GENMASK(26, 21)
|
||||
#define HAL_RX_USIG_MU_INFO0_RX_INTEG_CHECK_PASS BIT(31)
|
||||
|
||||
struct hal_mon_usig_mu {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
union hal_mon_usig_non_cmn {
|
||||
struct hal_mon_usig_tb tb;
|
||||
struct hal_mon_usig_mu mu;
|
||||
};
|
||||
|
||||
struct hal_mon_usig_hdr {
|
||||
struct hal_mon_usig_cmn cmn;
|
||||
union hal_mon_usig_non_cmn non_cmn;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_USR_INFO0_PHY_PPDU_ID GENMASK(15, 0)
|
||||
#define HAL_RX_USR_INFO0_USR_RSSI GENMASK(23, 16)
|
||||
#define HAL_RX_USR_INFO0_PKT_TYPE GENMASK(27, 24)
|
||||
#define HAL_RX_USR_INFO0_STBC BIT(28)
|
||||
#define HAL_RX_USR_INFO0_RECEPTION_TYPE GENMASK(31, 29)
|
||||
|
||||
#define HAL_RX_USR_INFO1_MCS GENMASK(3, 0)
|
||||
#define HAL_RX_USR_INFO1_SGI GENMASK(5, 4)
|
||||
#define HAL_RX_USR_INFO1_HE_RANGING_NDP BIT(6)
|
||||
#define HAL_RX_USR_INFO1_MIMO_SS_BITMAP GENMASK(15, 8)
|
||||
#define HAL_RX_USR_INFO1_RX_BW GENMASK(18, 16)
|
||||
#define HAL_RX_USR_INFO1_DL_OFMDA_USR_IDX GENMASK(31, 24)
|
||||
|
||||
#define HAL_RX_USR_INFO2_DL_OFDMA_CONTENT_CHAN BIT(0)
|
||||
#define HAL_RX_USR_INFO2_NSS GENMASK(10, 8)
|
||||
#define HAL_RX_USR_INFO2_STREAM_OFFSET GENMASK(13, 11)
|
||||
#define HAL_RX_USR_INFO2_STA_DCM BIT(14)
|
||||
#define HAL_RX_USR_INFO2_LDPC BIT(15)
|
||||
#define HAL_RX_USR_INFO2_RU_TYPE_80_0 GENMASK(19, 16)
|
||||
#define HAL_RX_USR_INFO2_RU_TYPE_80_1 GENMASK(23, 20)
|
||||
#define HAL_RX_USR_INFO2_RU_TYPE_80_2 GENMASK(27, 24)
|
||||
#define HAL_RX_USR_INFO2_RU_TYPE_80_3 GENMASK(31, 28)
|
||||
|
||||
#define HAL_RX_USR_INFO3_RU_START_IDX_80_0 GENMASK(5, 0)
|
||||
#define HAL_RX_USR_INFO3_RU_START_IDX_80_1 GENMASK(13, 8)
|
||||
#define HAL_RX_USR_INFO3_RU_START_IDX_80_2 GENMASK(21, 16)
|
||||
#define HAL_RX_USR_INFO3_RU_START_IDX_80_3 GENMASK(29, 24)
|
||||
|
||||
struct hal_receive_user_info {
|
||||
__le32 info0;
|
||||
__le32 info1;
|
||||
__le32 info2;
|
||||
__le32 info3;
|
||||
__le32 user_fd_rssi_seg0;
|
||||
__le32 user_fd_rssi_seg1;
|
||||
__le32 user_fd_rssi_seg2;
|
||||
__le32 user_fd_rssi_seg3;
|
||||
} __packed;
|
||||
|
||||
enum hal_mon_reception_type {
|
||||
HAL_RECEPTION_TYPE_SU,
|
||||
HAL_RECEPTION_TYPE_DL_MU_MIMO,
|
||||
HAL_RECEPTION_TYPE_DL_MU_OFMA,
|
||||
HAL_RECEPTION_TYPE_DL_MU_OFDMA_MIMO,
|
||||
HAL_RECEPTION_TYPE_UL_MU_MIMO,
|
||||
HAL_RECEPTION_TYPE_UL_MU_OFDMA,
|
||||
HAL_RECEPTION_TYPE_UL_MU_OFDMA_MIMO,
|
||||
};
|
||||
|
||||
/* Different allowed RU in 11BE */
|
||||
#define HAL_EHT_RU_26 0ULL
|
||||
#define HAL_EHT_RU_52 1ULL
|
||||
#define HAL_EHT_RU_78 2ULL
|
||||
#define HAL_EHT_RU_106 3ULL
|
||||
#define HAL_EHT_RU_132 4ULL
|
||||
#define HAL_EHT_RU_242 5ULL
|
||||
#define HAL_EHT_RU_484 6ULL
|
||||
#define HAL_EHT_RU_726 7ULL
|
||||
#define HAL_EHT_RU_996 8ULL
|
||||
#define HAL_EHT_RU_996x2 9ULL
|
||||
#define HAL_EHT_RU_996x3 10ULL
|
||||
#define HAL_EHT_RU_996x4 11ULL
|
||||
#define HAL_EHT_RU_NONE 15ULL
|
||||
#define HAL_EHT_RU_INVALID 31ULL
|
||||
/* MRUs spanning above 80Mhz
|
||||
* HAL_EHT_RU_996_484 = HAL_EHT_RU_484 + HAL_EHT_RU_996 + 4 (reserved)
|
||||
*/
|
||||
#define HAL_EHT_RU_996_484 18ULL
|
||||
#define HAL_EHT_RU_996x2_484 28ULL
|
||||
#define HAL_EHT_RU_996x3_484 40ULL
|
||||
#define HAL_EHT_RU_996_484_242 23ULL
|
||||
|
||||
#define NUM_RU_BITS_PER80 16
|
||||
#define NUM_RU_BITS_PER20 4
|
||||
|
||||
/* Different per_80Mhz band in 320Mhz bandwidth */
|
||||
#define HAL_80_0 0
|
||||
#define HAL_80_1 1
|
||||
#define HAL_80_2 2
|
||||
#define HAL_80_3 3
|
||||
|
||||
#define HAL_RU_80MHZ(num_band) ((num_band) * NUM_RU_BITS_PER80)
|
||||
#define HAL_RU_20MHZ(idx_per_80) ((idx_per_80) * NUM_RU_BITS_PER20)
|
||||
|
||||
#define HAL_RU_SHIFT(num_band, idx_per_80) \
|
||||
(HAL_RU_80MHZ(num_band) + HAL_RU_20MHZ(idx_per_80))
|
||||
|
||||
#define HAL_RU(ru, num_band, idx_per_80) \
|
||||
((u64)(ru) << HAL_RU_SHIFT(num_band, idx_per_80))
|
||||
|
||||
/* MRU-996+484 */
|
||||
#define HAL_EHT_RU_996_484_0 (HAL_RU(HAL_EHT_RU_484, HAL_80_0, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996, HAL_80_1, 0))
|
||||
#define HAL_EHT_RU_996_484_1 (HAL_RU(HAL_EHT_RU_484, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996, HAL_80_1, 0))
|
||||
#define HAL_EHT_RU_996_484_2 (HAL_RU(HAL_EHT_RU_996, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_1, 1))
|
||||
#define HAL_EHT_RU_996_484_3 (HAL_RU(HAL_EHT_RU_996, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_1, 0))
|
||||
#define HAL_EHT_RU_996_484_4 (HAL_RU(HAL_EHT_RU_484, HAL_80_2, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996_484_5 (HAL_RU(HAL_EHT_RU_484, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996_484_6 (HAL_RU(HAL_EHT_RU_996, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_3, 1))
|
||||
#define HAL_EHT_RU_996_484_7 (HAL_RU(HAL_EHT_RU_996, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_3, 0))
|
||||
|
||||
/* MRU-996x2+484 */
|
||||
#define HAL_EHT_RU_996x2_484_0 (HAL_RU(HAL_EHT_RU_484, HAL_80_0, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0))
|
||||
#define HAL_EHT_RU_996x2_484_1 (HAL_RU(HAL_EHT_RU_484, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0))
|
||||
#define HAL_EHT_RU_996x2_484_2 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_1, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0))
|
||||
#define HAL_EHT_RU_996x2_484_3 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0))
|
||||
#define HAL_EHT_RU_996x2_484_4 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_2, 1))
|
||||
#define HAL_EHT_RU_996x2_484_5 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_2, 0))
|
||||
#define HAL_EHT_RU_996x2_484_6 (HAL_RU(HAL_EHT_RU_484, HAL_80_1, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x2_484_7 (HAL_RU(HAL_EHT_RU_484, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x2_484_8 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_2, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x2_484_9 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x2_484_10 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_3, 1))
|
||||
#define HAL_EHT_RU_996x2_484_11 (HAL_RU(HAL_EHT_RU_996x2, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x2, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_3, 0))
|
||||
|
||||
/* MRU-996x3+484 */
|
||||
#define HAL_EHT_RU_996x3_484_0 (HAL_RU(HAL_EHT_RU_484, HAL_80_0, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x3_484_1 (HAL_RU(HAL_EHT_RU_484, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x3_484_2 (HAL_RU(HAL_EHT_RU_996x3, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_1, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x3_484_3 (HAL_RU(HAL_EHT_RU_996x3, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x3_484_4 (HAL_RU(HAL_EHT_RU_996x3, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_2, 1) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x3_484_5 (HAL_RU(HAL_EHT_RU_996x3, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_3, 0))
|
||||
#define HAL_EHT_RU_996x3_484_6 (HAL_RU(HAL_EHT_RU_996x3, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_3, 1))
|
||||
#define HAL_EHT_RU_996x3_484_7 (HAL_RU(HAL_EHT_RU_996x3, HAL_80_0, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_1, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_996x3, HAL_80_2, 0) | \
|
||||
HAL_RU(HAL_EHT_RU_484, HAL_80_3, 0))
|
||||
|
||||
#define HAL_RU_PER80(ru_per80, num_80mhz, ru_idx_per80mhz) \
|
||||
(HAL_RU(ru_per80, num_80mhz, ru_idx_per80mhz))
|
||||
|
||||
#define RU_INVALID 0
|
||||
#define RU_26 1
|
||||
#define RU_52 2
|
||||
#define RU_106 4
|
||||
#define RU_242 9
|
||||
#define RU_484 18
|
||||
#define RU_996 37
|
||||
#define RU_2X996 74
|
||||
#define RU_3X996 111
|
||||
#define RU_4X996 148
|
||||
#define RU_52_26 (RU_52 + RU_26)
|
||||
#define RU_106_26 (RU_106 + RU_26)
|
||||
#define RU_484_242 (RU_484 + RU_242)
|
||||
#define RU_996_484 (RU_996 + RU_484)
|
||||
#define RU_996_484_242 (RU_996 + RU_484_242)
|
||||
#define RU_2X996_484 (RU_2X996 + RU_484)
|
||||
#define RU_3X996_484 (RU_3X996 + RU_484)
|
||||
|
||||
enum ath12k_eht_ru_size {
|
||||
ATH12K_EHT_RU_26,
|
||||
ATH12K_EHT_RU_52,
|
||||
ATH12K_EHT_RU_106,
|
||||
ATH12K_EHT_RU_242,
|
||||
ATH12K_EHT_RU_484,
|
||||
ATH12K_EHT_RU_996,
|
||||
ATH12K_EHT_RU_996x2,
|
||||
ATH12K_EHT_RU_996x4,
|
||||
ATH12K_EHT_RU_52_26,
|
||||
ATH12K_EHT_RU_106_26,
|
||||
ATH12K_EHT_RU_484_242,
|
||||
ATH12K_EHT_RU_996_484,
|
||||
ATH12K_EHT_RU_996_484_242,
|
||||
ATH12K_EHT_RU_996x2_484,
|
||||
ATH12K_EHT_RU_996x3,
|
||||
ATH12K_EHT_RU_996x3_484,
|
||||
|
||||
/* Keep last */
|
||||
ATH12K_EHT_RU_INVALID,
|
||||
};
|
||||
|
||||
#define HAL_RX_RU_ALLOC_TYPE_MAX ATH12K_EHT_RU_INVALID
|
||||
|
||||
static inline
|
||||
enum nl80211_he_ru_alloc ath12k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones)
|
||||
{
|
||||
@@ -662,6 +1091,9 @@ enum nl80211_he_ru_alloc ath12k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones)
|
||||
case RU_996:
|
||||
ret = NL80211_RATE_INFO_HE_RU_ALLOC_996;
|
||||
break;
|
||||
case RU_2X996:
|
||||
ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
|
||||
break;
|
||||
case RU_26:
|
||||
fallthrough;
|
||||
default:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_HAL_TX_H
|
||||
@@ -63,7 +64,12 @@ struct hal_tx_status {
|
||||
u8 try_cnt;
|
||||
u8 tid;
|
||||
u16 peer_id;
|
||||
u32 rate_stats;
|
||||
enum hal_tx_rate_stats_pkt_type pkt_type;
|
||||
enum hal_tx_rate_stats_sgi sgi;
|
||||
enum ath12k_supported_bw bw;
|
||||
u8 mcs;
|
||||
u16 tones;
|
||||
u8 ofdma;
|
||||
};
|
||||
|
||||
#define HAL_TX_PHY_DESC_INFO0_BF_TYPE GENMASK(17, 16)
|
||||
|
||||
@@ -543,7 +543,11 @@ static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_qcn9274 = {
|
||||
ATH12K_TX_RING_MASK_3,
|
||||
},
|
||||
.rx_mon_dest = {
|
||||
0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
ATH12K_RX_MON_RING_MASK_0,
|
||||
ATH12K_RX_MON_RING_MASK_1,
|
||||
ATH12K_RX_MON_RING_MASK_2,
|
||||
},
|
||||
.rx = {
|
||||
0, 0, 0, 0,
|
||||
@@ -1035,7 +1039,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
|
||||
|
||||
.hal_params = &ath12k_hw_hal_params_qcn9274,
|
||||
|
||||
.rxdma1_enable = false,
|
||||
.rxdma1_enable = true,
|
||||
.num_rxdma_per_pdev = 1,
|
||||
.num_rxdma_dst_ring = 0,
|
||||
.rx_mac_buf_ring = false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_MAC_H
|
||||
@@ -108,5 +108,11 @@ int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif);
|
||||
void ath12k_mac_get_any_chanctx_conf_iter(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *conf,
|
||||
void *data);
|
||||
|
||||
u16 ath12k_mac_he_convert_tones_to_ru_tones(u16 tones);
|
||||
enum nl80211_eht_ru_alloc ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(u16 ru_tones);
|
||||
enum nl80211_eht_gi ath12k_mac_eht_gi_to_nl80211_eht_gi(u8 sgi);
|
||||
struct ieee80211_bss_conf *ath12k_mac_get_link_bss_conf(struct ath12k_link_vif *arvif);
|
||||
struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u8 link_id);
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -483,8 +483,11 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab)
|
||||
|
||||
ath12k_pci_ext_grp_disable(irq_grp);
|
||||
|
||||
napi_synchronize(&irq_grp->napi);
|
||||
napi_disable(&irq_grp->napi);
|
||||
if (irq_grp->napi_enabled) {
|
||||
napi_synchronize(&irq_grp->napi);
|
||||
napi_disable(&irq_grp->napi);
|
||||
irq_grp->napi_enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +649,7 @@ static int ath12k_pci_set_irq_affinity_hint(struct ath12k_pci *ab_pci,
|
||||
if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||
return 0;
|
||||
|
||||
return irq_set_affinity_hint(ab_pci->pdev->irq, m);
|
||||
return irq_set_affinity_and_hint(ab_pci->pdev->irq, m);
|
||||
}
|
||||
|
||||
static int ath12k_pci_config_irq(struct ath12k_base *ab)
|
||||
@@ -1114,7 +1117,11 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab)
|
||||
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
||||
struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
|
||||
|
||||
napi_enable(&irq_grp->napi);
|
||||
if (!irq_grp->napi_enabled) {
|
||||
napi_enable(&irq_grp->napi);
|
||||
irq_grp->napi_enabled = true;
|
||||
}
|
||||
|
||||
ath12k_pci_ext_grp_enable(irq_grp);
|
||||
}
|
||||
|
||||
@@ -1561,6 +1568,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
|
||||
ab_pci->ab = ab;
|
||||
ab_pci->pdev = pdev;
|
||||
ab->hif.ops = &ath12k_pci_hif_ops;
|
||||
ab->fw_mode = ATH12K_FIRMWARE_MODE_NORMAL;
|
||||
pci_set_drvdata(pdev, ab);
|
||||
spin_lock_init(&ab_pci->window_lock);
|
||||
|
||||
@@ -1689,6 +1697,8 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
/* __free_irq() expects the caller to have cleared the affinity hint */
|
||||
ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
|
||||
ath12k_pci_free_irq(ab);
|
||||
|
||||
err_ce_free:
|
||||
@@ -1734,9 +1744,9 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
|
||||
cancel_work_sync(&ab->reset_work);
|
||||
cancel_work_sync(&ab->dump_work);
|
||||
ath12k_core_deinit(ab);
|
||||
ath12k_fw_unmap(ab);
|
||||
|
||||
qmi_fail:
|
||||
ath12k_fw_unmap(ab);
|
||||
ath12k_mhi_unregister(ab_pci);
|
||||
|
||||
ath12k_pci_free_irq(ab);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/elf.h>
|
||||
@@ -2056,8 +2056,7 @@ static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
|
||||
}
|
||||
|
||||
if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) {
|
||||
ab->single_chip_mlo_supp = false;
|
||||
|
||||
ag->mlo_capable = false;
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"skip QMI MLO cap due to invalid num_radio %d\n",
|
||||
ab->qmi.num_radios);
|
||||
@@ -2265,10 +2264,6 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (resp.single_chip_mlo_support_valid &&
|
||||
resp.single_chip_mlo_support)
|
||||
ab->single_chip_mlo_supp = true;
|
||||
|
||||
if (!resp.num_phy_valid) {
|
||||
ret = -ENODATA;
|
||||
goto out;
|
||||
@@ -2277,10 +2272,9 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
|
||||
ab->qmi.num_radios = resp.num_phy;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"phy capability resp valid %d num_phy %d valid %d board_id %d valid %d single_chip_mlo_support %d\n",
|
||||
"phy capability resp valid %d num_phy %d valid %d board_id %d\n",
|
||||
resp.num_phy_valid, resp.num_phy,
|
||||
resp.board_id_valid, resp.board_id,
|
||||
resp.single_chip_mlo_support_valid, resp.single_chip_mlo_support);
|
||||
resp.board_id_valid, resp.board_id);
|
||||
|
||||
return;
|
||||
|
||||
@@ -2740,6 +2734,15 @@ int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
|
||||
if (r)
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "SMBIOS bdf variant name not set.\n");
|
||||
|
||||
r = ath12k_acpi_start(ab);
|
||||
if (r)
|
||||
/* ACPI is optional so continue in case of an error */
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi failed: %d\n", r);
|
||||
|
||||
r = ath12k_acpi_check_bdf_variant_name(ab);
|
||||
if (r)
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT, "ACPI bdf variant name not set.\n");
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_REG_H
|
||||
@@ -13,6 +13,9 @@
|
||||
struct ath12k_base;
|
||||
struct ath12k;
|
||||
|
||||
#define ATH12K_2GHZ_MAX_FREQUENCY 2495
|
||||
#define ATH12K_5GHZ_MAX_FREQUENCY 5920
|
||||
|
||||
/* DFS regdomains supported by Firmware */
|
||||
enum ath12k_dfs_region {
|
||||
ATH12K_DFS_REG_UNSET,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef ATH12K_RX_DESC_H
|
||||
#define ATH12K_RX_DESC_H
|
||||
@@ -637,6 +637,8 @@ enum rx_msdu_start_pkt_type {
|
||||
RX_MSDU_START_PKT_TYPE_11N,
|
||||
RX_MSDU_START_PKT_TYPE_11AC,
|
||||
RX_MSDU_START_PKT_TYPE_11AX,
|
||||
RX_MSDU_START_PKT_TYPE_11BA,
|
||||
RX_MSDU_START_PKT_TYPE_11BE,
|
||||
};
|
||||
|
||||
enum rx_msdu_start_sgi {
|
||||
@@ -1539,12 +1541,4 @@ struct hal_rx_desc {
|
||||
#define MAX_MU_GROUP_SHOW 16
|
||||
#define MAX_MU_GROUP_LENGTH (6 * MAX_MU_GROUP_SHOW)
|
||||
|
||||
#define HAL_RX_RU_ALLOC_TYPE_MAX 6
|
||||
#define RU_26 1
|
||||
#define RU_52 2
|
||||
#define RU_106 4
|
||||
#define RU_242 9
|
||||
#define RU_484 18
|
||||
#define RU_996 37
|
||||
|
||||
#endif /* ATH12K_RX_DESC_H */
|
||||
|
||||
395
drivers/net/wireless/ath/ath12k/testmode.c
Normal file
395
drivers/net/wireless/ath/ath12k/testmode.c
Normal file
@@ -0,0 +1,395 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "testmode.h"
|
||||
#include <net/netlink.h>
|
||||
#include "debug.h"
|
||||
#include "wmi.h"
|
||||
#include "hw.h"
|
||||
#include "core.h"
|
||||
#include "hif.h"
|
||||
#include "../testmode_i.h"
|
||||
|
||||
#define ATH12K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0)
|
||||
#define ATH12K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4)
|
||||
|
||||
static const struct nla_policy ath12k_tm_policy[ATH_TM_ATTR_MAX + 1] = {
|
||||
[ATH_TM_ATTR_CMD] = { .type = NLA_U32 },
|
||||
[ATH_TM_ATTR_DATA] = { .type = NLA_BINARY,
|
||||
.len = ATH_TM_DATA_MAX_LEN },
|
||||
[ATH_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
|
||||
[ATH_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
|
||||
[ATH_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static struct ath12k *ath12k_tm_get_ar(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_pdev *pdev;
|
||||
struct ath12k *ar;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
pdev = &ab->pdevs[i];
|
||||
ar = pdev->ar;
|
||||
|
||||
if (ar && ar->ah->state == ATH12K_HW_STATE_TM)
|
||||
return ar;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ath12k_tm_wmi_event_unsegmented(struct ath12k_base *ab, u32 cmd_id,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *nl_skb;
|
||||
struct ath12k *ar;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_TESTMODE,
|
||||
"testmode event wmi cmd_id %d skb length %d\n",
|
||||
cmd_id, skb->len);
|
||||
|
||||
ath12k_dbg_dump(ab, ATH12K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
|
||||
|
||||
ar = ath12k_tm_get_ar(ab);
|
||||
if (!ar) {
|
||||
ath12k_warn(ab, "testmode event not handled due to invalid pdev\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
nl_skb = cfg80211_testmode_alloc_event_skb(ar->ah->hw->wiphy,
|
||||
2 * nla_total_size(sizeof(u32)) +
|
||||
nla_total_size(skb->len),
|
||||
GFP_ATOMIC);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!nl_skb) {
|
||||
ath12k_warn(ab,
|
||||
"failed to allocate skb for unsegmented testmode wmi event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nla_put_u32(nl_skb, ATH_TM_ATTR_CMD, ATH_TM_CMD_WMI) ||
|
||||
nla_put_u32(nl_skb, ATH_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||
nla_put(nl_skb, ATH_TM_ATTR_DATA, skb->len, skb->data)) {
|
||||
ath12k_warn(ab, "failed to populate testmode unsegmented event\n");
|
||||
kfree_skb(nl_skb);
|
||||
return;
|
||||
}
|
||||
|
||||
cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
void ath12k_tm_process_event(struct ath12k_base *ab, u32 cmd_id,
|
||||
const struct ath12k_wmi_ftm_event *ftm_msg,
|
||||
u16 length)
|
||||
{
|
||||
struct sk_buff *nl_skb;
|
||||
struct ath12k *ar;
|
||||
u32 data_pos, pdev_id;
|
||||
u16 datalen;
|
||||
u8 total_segments, current_seq;
|
||||
u8 const *buf_pos;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_TESTMODE,
|
||||
"testmode event wmi cmd_id %d ftm event msg %pK datalen %d\n",
|
||||
cmd_id, ftm_msg, length);
|
||||
ath12k_dbg_dump(ab, ATH12K_DBG_TESTMODE, NULL, "", ftm_msg, length);
|
||||
pdev_id = DP_HW2SW_MACID(le32_to_cpu(ftm_msg->seg_hdr.pdev_id));
|
||||
|
||||
if (pdev_id >= ab->num_radios) {
|
||||
ath12k_warn(ab, "testmode event not handled due to invalid pdev id\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ar = ab->pdevs[pdev_id].ar;
|
||||
|
||||
if (!ar) {
|
||||
ath12k_warn(ab, "testmode event not handled due to absence of pdev\n");
|
||||
return;
|
||||
}
|
||||
|
||||
current_seq = le32_get_bits(ftm_msg->seg_hdr.segmentinfo,
|
||||
ATH12K_FTM_SEGHDR_CURRENT_SEQ);
|
||||
total_segments = le32_get_bits(ftm_msg->seg_hdr.segmentinfo,
|
||||
ATH12K_FTM_SEGHDR_TOTAL_SEGMENTS);
|
||||
datalen = length - (sizeof(struct ath12k_wmi_ftm_seg_hdr_params));
|
||||
buf_pos = ftm_msg->data;
|
||||
|
||||
if (current_seq == 0) {
|
||||
ab->ftm_event_obj.expected_seq = 0;
|
||||
ab->ftm_event_obj.data_pos = 0;
|
||||
}
|
||||
|
||||
data_pos = ab->ftm_event_obj.data_pos;
|
||||
|
||||
if ((data_pos + datalen) > ATH_FTM_EVENT_MAX_BUF_LENGTH) {
|
||||
ath12k_warn(ab,
|
||||
"Invalid event length date_pos[%d] datalen[%d]\n",
|
||||
data_pos, datalen);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ab->ftm_event_obj.eventdata[data_pos], buf_pos, datalen);
|
||||
data_pos += datalen;
|
||||
|
||||
if (++ab->ftm_event_obj.expected_seq != total_segments) {
|
||||
ab->ftm_event_obj.data_pos = data_pos;
|
||||
ath12k_dbg(ab, ATH12K_DBG_TESTMODE,
|
||||
"partial data received current_seq[%d], total_seg[%d]\n",
|
||||
current_seq, total_segments);
|
||||
return;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_TESTMODE,
|
||||
"total data length[%d] = [%d]\n",
|
||||
data_pos, ftm_msg->seg_hdr.len);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
nl_skb = cfg80211_testmode_alloc_event_skb(ar->ah->hw->wiphy,
|
||||
2 * nla_total_size(sizeof(u32)) +
|
||||
nla_total_size(data_pos),
|
||||
GFP_ATOMIC);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!nl_skb) {
|
||||
ath12k_warn(ab,
|
||||
"failed to allocate skb for testmode wmi event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nla_put_u32(nl_skb, ATH_TM_ATTR_CMD,
|
||||
ATH_TM_CMD_WMI_FTM) ||
|
||||
nla_put_u32(nl_skb, ATH_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||
nla_put(nl_skb, ATH_TM_ATTR_DATA, data_pos,
|
||||
&ab->ftm_event_obj.eventdata[0])) {
|
||||
ath12k_warn(ab, "failed to populate testmode event");
|
||||
kfree_skb(nl_skb);
|
||||
return;
|
||||
}
|
||||
|
||||
cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static int ath12k_tm_cmd_get_version(struct ath12k *ar, struct nlattr *tb[])
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_TESTMODE,
|
||||
"testmode cmd get version_major %d version_minor %d\n",
|
||||
ATH_TESTMODE_VERSION_MAJOR,
|
||||
ATH_TESTMODE_VERSION_MINOR);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
skb = cfg80211_testmode_alloc_reply_skb(ar->ah->hw->wiphy,
|
||||
2 * nla_total_size(sizeof(u32)));
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nla_put_u32(skb, ATH_TM_ATTR_VERSION_MAJOR,
|
||||
ATH_TESTMODE_VERSION_MAJOR) ||
|
||||
nla_put_u32(skb, ATH_TM_ATTR_VERSION_MINOR,
|
||||
ATH_TESTMODE_VERSION_MINOR)) {
|
||||
kfree_skb(skb);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
return cfg80211_testmode_reply(skb);
|
||||
}
|
||||
|
||||
static int ath12k_tm_cmd_process_ftm(struct ath12k *ar, struct nlattr *tb[])
|
||||
{
|
||||
struct ath12k_wmi_pdev *wmi = ar->wmi;
|
||||
struct sk_buff *skb;
|
||||
struct ath12k_wmi_ftm_cmd *ftm_cmd;
|
||||
int ret = 0;
|
||||
void *buf;
|
||||
size_t aligned_len;
|
||||
u32 cmd_id, buf_len;
|
||||
u16 chunk_len, total_bytes, num_segments;
|
||||
u8 segnumber = 0, *bufpos;
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_TESTMODE, "ah->state %d\n", ar->ah->state);
|
||||
if (ar->ah->state != ATH12K_HW_STATE_TM)
|
||||
return -ENETDOWN;
|
||||
|
||||
if (!tb[ATH_TM_ATTR_DATA])
|
||||
return -EINVAL;
|
||||
|
||||
buf = nla_data(tb[ATH_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH_TM_ATTR_DATA]);
|
||||
cmd_id = WMI_PDEV_UTF_CMDID;
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_TESTMODE,
|
||||
"testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
|
||||
cmd_id, buf, buf_len);
|
||||
ath12k_dbg_dump(ar->ab, ATH12K_DBG_TESTMODE, NULL, "", buf, buf_len);
|
||||
bufpos = buf;
|
||||
total_bytes = buf_len;
|
||||
num_segments = total_bytes / MAX_WMI_UTF_LEN;
|
||||
|
||||
if (buf_len - (num_segments * MAX_WMI_UTF_LEN))
|
||||
num_segments++;
|
||||
|
||||
while (buf_len) {
|
||||
if (buf_len > MAX_WMI_UTF_LEN)
|
||||
chunk_len = MAX_WMI_UTF_LEN; /* MAX message */
|
||||
else
|
||||
chunk_len = buf_len;
|
||||
|
||||
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, (chunk_len +
|
||||
sizeof(struct ath12k_wmi_ftm_cmd)));
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
ftm_cmd = (struct ath12k_wmi_ftm_cmd *)skb->data;
|
||||
aligned_len = chunk_len + sizeof(struct ath12k_wmi_ftm_seg_hdr_params);
|
||||
ftm_cmd->tlv_header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, aligned_len);
|
||||
ftm_cmd->seg_hdr.len = cpu_to_le32(total_bytes);
|
||||
ftm_cmd->seg_hdr.msgref = cpu_to_le32(ar->ftm_msgref);
|
||||
ftm_cmd->seg_hdr.segmentinfo =
|
||||
le32_encode_bits(num_segments,
|
||||
ATH12K_FTM_SEGHDR_TOTAL_SEGMENTS) |
|
||||
le32_encode_bits(segnumber,
|
||||
ATH12K_FTM_SEGHDR_CURRENT_SEQ);
|
||||
ftm_cmd->seg_hdr.pdev_id = cpu_to_le32(ar->pdev->pdev_id);
|
||||
segnumber++;
|
||||
memcpy(&ftm_cmd->data, bufpos, chunk_len);
|
||||
ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id);
|
||||
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab, "ftm wmi command fail: %d\n", ret);
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf_len -= chunk_len;
|
||||
bufpos += chunk_len;
|
||||
}
|
||||
|
||||
++ar->ftm_msgref;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath12k_tm_cmd_testmode_start(struct ath12k *ar, struct nlattr *tb[])
|
||||
{
|
||||
if (ar->ah->state == ATH12K_HW_STATE_TM)
|
||||
return -EALREADY;
|
||||
|
||||
if (ar->ah->state != ATH12K_HW_STATE_OFF)
|
||||
return -EBUSY;
|
||||
|
||||
ar->ab->ftm_event_obj.eventdata = kzalloc(ATH_FTM_EVENT_MAX_BUF_LENGTH,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!ar->ab->ftm_event_obj.eventdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ar->ah->state = ATH12K_HW_STATE_TM;
|
||||
ar->ftm_msgref = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_tm_cmd_wmi(struct ath12k *ar, struct nlattr *tb[])
|
||||
{
|
||||
struct ath12k_wmi_pdev *wmi = ar->wmi;
|
||||
struct sk_buff *skb;
|
||||
struct wmi_pdev_set_param_cmd *cmd;
|
||||
int ret = 0, tag;
|
||||
void *buf;
|
||||
u32 cmd_id, buf_len;
|
||||
|
||||
if (!tb[ATH_TM_ATTR_DATA])
|
||||
return -EINVAL;
|
||||
|
||||
if (!tb[ATH_TM_ATTR_WMI_CMDID])
|
||||
return -EINVAL;
|
||||
|
||||
buf = nla_data(tb[ATH_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH_TM_ATTR_DATA]);
|
||||
|
||||
if (!buf_len) {
|
||||
ath12k_warn(ar->ab, "No data present in testmode command\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd_id = nla_get_u32(tb[ATH_TM_ATTR_WMI_CMDID]);
|
||||
|
||||
cmd = buf;
|
||||
tag = le32_get_bits(cmd->tlv_header, WMI_TLV_TAG);
|
||||
|
||||
if (tag == WMI_TAG_PDEV_SET_PARAM_CMD)
|
||||
cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_TESTMODE,
|
||||
"testmode cmd wmi cmd_id %d buf length %d\n",
|
||||
cmd_id, buf_len);
|
||||
|
||||
ath12k_dbg_dump(ar->ab, ATH12K_DBG_TESTMODE, NULL, "", buf, buf_len);
|
||||
|
||||
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, buf_len);
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(skb->data, buf, buf_len);
|
||||
|
||||
ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id);
|
||||
if (ret) {
|
||||
dev_kfree_skb(skb);
|
||||
ath12k_warn(ar->ab, "failed to transmit wmi command (testmode): %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath12k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
void *data, int len)
|
||||
{
|
||||
struct ath12k_hw *ah = hw->priv;
|
||||
struct ath12k *ar = NULL;
|
||||
struct nlattr *tb[ATH_TM_ATTR_MAX + 1];
|
||||
struct ath12k_base *ab;
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&wiphy->mtx);
|
||||
|
||||
ret = nla_parse(tb, ATH_TM_ATTR_MAX, data, len, ath12k_tm_policy,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!tb[ATH_TM_ATTR_CMD])
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: have to handle ar for MLO case */
|
||||
if (ah->num_radio)
|
||||
ar = ah->radio;
|
||||
|
||||
if (!ar)
|
||||
return -EINVAL;
|
||||
|
||||
ab = ar->ab;
|
||||
switch (nla_get_u32(tb[ATH_TM_ATTR_CMD])) {
|
||||
case ATH_TM_CMD_WMI:
|
||||
return ath12k_tm_cmd_wmi(ar, tb);
|
||||
case ATH_TM_CMD_TESTMODE_START:
|
||||
return ath12k_tm_cmd_testmode_start(ar, tb);
|
||||
case ATH_TM_CMD_GET_VERSION:
|
||||
return ath12k_tm_cmd_get_version(ar, tb);
|
||||
case ATH_TM_CMD_WMI_FTM:
|
||||
set_bit(ATH12K_FLAG_FTM_SEGMENTED, &ab->dev_flags);
|
||||
return ath12k_tm_cmd_process_ftm(ar, tb);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
40
drivers/net/wireless/ath/ath12k/testmode.h
Normal file
40
drivers/net/wireless/ath/ath12k/testmode.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "hif.h"
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
|
||||
void ath12k_tm_wmi_event_unsegmented(struct ath12k_base *ab, u32 cmd_id,
|
||||
struct sk_buff *skb);
|
||||
void ath12k_tm_process_event(struct ath12k_base *ab, u32 cmd_id,
|
||||
const struct ath12k_wmi_ftm_event *ftm_msg,
|
||||
u16 length);
|
||||
int ath12k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
void *data, int len);
|
||||
|
||||
#else
|
||||
|
||||
static inline void ath12k_tm_wmi_event_unsegmented(struct ath12k_base *ab, u32 cmd_id,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath12k_tm_process_event(struct ath12k_base *ab, u32 cmd_id,
|
||||
const struct ath12k_wmi_ftm_event *msg,
|
||||
u16 length)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath12k_tm_cmd(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void *data, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_WMI_H
|
||||
@@ -25,6 +25,7 @@
|
||||
struct ath12k_base;
|
||||
struct ath12k;
|
||||
struct ath12k_link_vif;
|
||||
struct ath12k_fw_stats;
|
||||
|
||||
/* There is no signed version of __le32, so for a temporary solution come
|
||||
* up with our own version. The idea is from fs/ntfs/endian.h.
|
||||
@@ -516,6 +517,9 @@ enum wmi_tlv_cmd_id {
|
||||
WMI_REQUEST_RCPI_CMDID,
|
||||
WMI_REQUEST_PEER_STATS_INFO_CMDID,
|
||||
WMI_REQUEST_RADIO_CHAN_STATS_CMDID,
|
||||
WMI_REQUEST_WLM_STATS_CMDID,
|
||||
WMI_REQUEST_CTRL_PATH_STATS_CMDID,
|
||||
WMI_REQUEST_HALPHY_CTRL_PATH_STATS_CMDID = WMI_REQUEST_CTRL_PATH_STATS_CMDID + 3,
|
||||
WMI_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_GRP_ARP_NS_OFL),
|
||||
WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
|
||||
WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
|
||||
@@ -785,6 +789,9 @@ enum wmi_tlv_event_id {
|
||||
WMI_UPDATE_RCPI_EVENTID,
|
||||
WMI_PEER_STATS_INFO_EVENTID,
|
||||
WMI_RADIO_CHAN_STATS_EVENTID,
|
||||
WMI_WLM_STATS_EVENTID,
|
||||
WMI_CTRL_PATH_STATS_EVENTID,
|
||||
WMI_HALPHY_STATS_CTRL_PATH_EVENTID,
|
||||
WMI_NLO_MATCH_EVENTID = WMI_TLV_CMD(WMI_GRP_NLO_OFL),
|
||||
WMI_NLO_SCAN_COMPLETE_EVENTID,
|
||||
WMI_APFIND_EVENTID,
|
||||
@@ -1191,6 +1198,7 @@ enum wmi_tlv_tag {
|
||||
WMI_TAG_ARRAY_BYTE,
|
||||
WMI_TAG_ARRAY_STRUCT,
|
||||
WMI_TAG_ARRAY_FIXED_STRUCT,
|
||||
WMI_TAG_ARRAY_INT16,
|
||||
WMI_TAG_LAST_ARRAY_ENUM = 31,
|
||||
WMI_TAG_SERVICE_READY_EVENT,
|
||||
WMI_TAG_HAL_REG_CAPABILITIES,
|
||||
@@ -1941,6 +1949,12 @@ enum wmi_tlv_tag {
|
||||
WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
|
||||
WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
|
||||
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
|
||||
WMI_TAG_TPC_STATS_GET_CMD = 0x38B,
|
||||
WMI_TAG_TPC_STATS_EVENT_FIXED_PARAM,
|
||||
WMI_TAG_TPC_STATS_CONFIG_EVENT,
|
||||
WMI_TAG_TPC_STATS_REG_PWR_ALLOWED,
|
||||
WMI_TAG_TPC_STATS_RATES_ARRAY,
|
||||
WMI_TAG_TPC_STATS_CTL_PWR_TABLE_EVENT,
|
||||
WMI_TAG_EHT_RATE_SET = 0x3C4,
|
||||
WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
|
||||
WMI_TAG_MLO_TX_SEND_PARAMS,
|
||||
@@ -1958,6 +1972,8 @@ enum wmi_tlv_tag {
|
||||
WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
|
||||
WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD = 0x3D9,
|
||||
WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD = 0x3FB,
|
||||
WMI_TAG_HALPHY_CTRL_PATH_CMD_FIXED_PARAM = 0x442,
|
||||
WMI_TAG_HALPHY_CTRL_PATH_EVENT_FIXED_PARAM,
|
||||
WMI_TAG_MAX
|
||||
};
|
||||
|
||||
@@ -3624,6 +3640,26 @@ struct ath12k_wmi_p2p_noa_info {
|
||||
struct ath12k_wmi_p2p_noa_descriptor descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS];
|
||||
} __packed;
|
||||
|
||||
#define MAX_WMI_UTF_LEN 252
|
||||
|
||||
struct ath12k_wmi_ftm_seg_hdr_params {
|
||||
__le32 len;
|
||||
__le32 msgref;
|
||||
__le32 segmentinfo;
|
||||
__le32 pdev_id;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_ftm_cmd {
|
||||
__le32 tlv_header;
|
||||
struct ath12k_wmi_ftm_seg_hdr_params seg_hdr;
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_ftm_event {
|
||||
struct ath12k_wmi_ftm_seg_hdr_params seg_hdr;
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
#define WMI_BEACON_TX_BUFFER_SIZE 512
|
||||
|
||||
#define WMI_EMA_BEACON_CNT GENMASK(7, 0)
|
||||
@@ -4604,6 +4640,7 @@ enum wmi_rate_preamble {
|
||||
WMI_RATE_PREAMBLE_HT,
|
||||
WMI_RATE_PREAMBLE_VHT,
|
||||
WMI_RATE_PREAMBLE_HE,
|
||||
WMI_RATE_PREAMBLE_EHT,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -5628,6 +5665,245 @@ enum wmi_sta_keepalive_method {
|
||||
#define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30
|
||||
#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
|
||||
|
||||
struct wmi_stats_event {
|
||||
__le32 stats_id;
|
||||
__le32 num_pdev_stats;
|
||||
__le32 num_vdev_stats;
|
||||
__le32 num_peer_stats;
|
||||
__le32 num_bcnflt_stats;
|
||||
__le32 num_chan_stats;
|
||||
__le32 num_mib_stats;
|
||||
__le32 pdev_id;
|
||||
__le32 num_bcn_stats;
|
||||
__le32 num_peer_extd_stats;
|
||||
__le32 num_peer_extd2_stats;
|
||||
} __packed;
|
||||
|
||||
enum wmi_stats_id {
|
||||
WMI_REQUEST_PDEV_STAT = BIT(2),
|
||||
WMI_REQUEST_VDEV_STAT = BIT(3),
|
||||
WMI_REQUEST_BCN_STAT = BIT(11),
|
||||
};
|
||||
|
||||
struct wmi_request_stats_cmd {
|
||||
__le32 tlv_header;
|
||||
__le32 stats_id;
|
||||
__le32 vdev_id;
|
||||
struct ath12k_wmi_mac_addr_params peer_macaddr;
|
||||
__le32 pdev_id;
|
||||
} __packed;
|
||||
|
||||
#define WLAN_MAX_AC 4
|
||||
#define MAX_TX_RATE_VALUES 10
|
||||
|
||||
struct wmi_vdev_stats_params {
|
||||
__le32 vdev_id;
|
||||
__le32 beacon_snr;
|
||||
__le32 data_snr;
|
||||
__le32 num_tx_frames[WLAN_MAX_AC];
|
||||
__le32 num_rx_frames;
|
||||
__le32 num_tx_frames_retries[WLAN_MAX_AC];
|
||||
__le32 num_tx_frames_failures[WLAN_MAX_AC];
|
||||
__le32 num_rts_fail;
|
||||
__le32 num_rts_success;
|
||||
__le32 num_rx_err;
|
||||
__le32 num_rx_discard;
|
||||
__le32 num_tx_not_acked;
|
||||
__le32 tx_rate_history[MAX_TX_RATE_VALUES];
|
||||
__le32 beacon_rssi_history[MAX_TX_RATE_VALUES];
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_bcn_stats_params {
|
||||
__le32 vdev_id;
|
||||
__le32 tx_bcn_succ_cnt;
|
||||
__le32 tx_bcn_outage_cnt;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_pdev_base_stats_params {
|
||||
a_sle32 chan_nf;
|
||||
__le32 tx_frame_count; /* Cycles spent transmitting frames */
|
||||
__le32 rx_frame_count; /* Cycles spent receiving frames */
|
||||
__le32 rx_clear_count; /* Total channel busy time, evidently */
|
||||
__le32 cycle_count; /* Total on-channel time */
|
||||
__le32 phy_err_count;
|
||||
__le32 chan_tx_pwr;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_pdev_tx_stats_params {
|
||||
a_sle32 comp_queued;
|
||||
a_sle32 comp_delivered;
|
||||
a_sle32 msdu_enqued;
|
||||
a_sle32 mpdu_enqued;
|
||||
a_sle32 wmm_drop;
|
||||
a_sle32 local_enqued;
|
||||
a_sle32 local_freed;
|
||||
a_sle32 hw_queued;
|
||||
a_sle32 hw_reaped;
|
||||
a_sle32 underrun;
|
||||
a_sle32 tx_abort;
|
||||
a_sle32 mpdus_requed;
|
||||
__le32 tx_ko;
|
||||
__le32 data_rc;
|
||||
__le32 self_triggers;
|
||||
__le32 sw_retry_failure;
|
||||
__le32 illgl_rate_phy_err;
|
||||
__le32 pdev_cont_xretry;
|
||||
__le32 pdev_tx_timeout;
|
||||
__le32 pdev_resets;
|
||||
__le32 stateless_tid_alloc_failure;
|
||||
__le32 phy_underrun;
|
||||
__le32 txop_ovf;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_pdev_rx_stats_params {
|
||||
a_sle32 mid_ppdu_route_change;
|
||||
a_sle32 status_rcvd;
|
||||
a_sle32 r0_frags;
|
||||
a_sle32 r1_frags;
|
||||
a_sle32 r2_frags;
|
||||
a_sle32 r3_frags;
|
||||
a_sle32 htt_msdus;
|
||||
a_sle32 htt_mpdus;
|
||||
a_sle32 loc_msdus;
|
||||
a_sle32 loc_mpdus;
|
||||
a_sle32 oversize_amsdu;
|
||||
a_sle32 phy_errs;
|
||||
a_sle32 phy_err_drop;
|
||||
a_sle32 mpdu_errs;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_pdev_stats_params {
|
||||
struct ath12k_wmi_pdev_base_stats_params base;
|
||||
struct ath12k_wmi_pdev_tx_stats_params tx;
|
||||
struct ath12k_wmi_pdev_rx_stats_params rx;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_fw_stats_req_params {
|
||||
u32 stats_id;
|
||||
u32 vdev_id;
|
||||
u32 pdev_id;
|
||||
};
|
||||
|
||||
#define WMI_REQ_CTRL_PATH_PDEV_TX_STAT 1
|
||||
#define WMI_REQUEST_CTRL_PATH_STAT_GET 1
|
||||
|
||||
#define WMI_TPC_CONFIG BIT(1)
|
||||
#define WMI_TPC_REG_PWR_ALLOWED BIT(2)
|
||||
#define WMI_TPC_RATES_ARRAY1 BIT(3)
|
||||
#define WMI_TPC_RATES_ARRAY2 BIT(4)
|
||||
#define WMI_TPC_RATES_DL_OFDMA_ARRAY BIT(5)
|
||||
#define WMI_TPC_CTL_PWR_ARRAY BIT(6)
|
||||
#define WMI_TPC_CONFIG_PARAM 0x1
|
||||
#define ATH12K_TPC_RATE_ARRAY_MU GENMASK(15, 8)
|
||||
#define ATH12K_TPC_RATE_ARRAY_SU GENMASK(7, 0)
|
||||
#define TPC_STATS_REG_PWR_ALLOWED_TYPE 0
|
||||
|
||||
enum wmi_halphy_ctrl_path_stats_id {
|
||||
WMI_HALPHY_PDEV_TX_SU_STATS = 0,
|
||||
WMI_HALPHY_PDEV_TX_SUTXBF_STATS,
|
||||
WMI_HALPHY_PDEV_TX_MU_STATS,
|
||||
WMI_HALPHY_PDEV_TX_MUTXBF_STATS,
|
||||
WMI_HALPHY_PDEV_TX_STATS_MAX,
|
||||
};
|
||||
|
||||
enum ath12k_wmi_tpc_stats_rates_array {
|
||||
ATH12K_TPC_STATS_RATES_ARRAY1,
|
||||
ATH12K_TPC_STATS_RATES_ARRAY2,
|
||||
};
|
||||
|
||||
enum ath12k_wmi_tpc_stats_ctl_array {
|
||||
ATH12K_TPC_STATS_CTL_ARRAY,
|
||||
ATH12K_TPC_STATS_CTL_160ARRAY,
|
||||
};
|
||||
|
||||
enum ath12k_wmi_tpc_stats_events {
|
||||
ATH12K_TPC_STATS_CONFIG_REG_PWR_EVENT,
|
||||
ATH12K_TPC_STATS_RATES_EVENT1,
|
||||
ATH12K_TPC_STATS_RATES_EVENT2,
|
||||
ATH12K_TPC_STATS_CTL_TABLE_EVENT
|
||||
};
|
||||
|
||||
struct wmi_request_halphy_ctrl_path_stats_cmd_fixed_params {
|
||||
__le32 tlv_header;
|
||||
__le32 stats_id_mask;
|
||||
__le32 request_id;
|
||||
__le32 action;
|
||||
__le32 subid;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_pdev_tpc_stats_event_fixed_params {
|
||||
__le32 pdev_id;
|
||||
__le32 end_of_event;
|
||||
__le32 event_count;
|
||||
} __packed;
|
||||
|
||||
struct wmi_tpc_config_params {
|
||||
__le32 reg_domain;
|
||||
__le32 chan_freq;
|
||||
__le32 phy_mode;
|
||||
__le32 twice_antenna_reduction;
|
||||
__le32 twice_max_reg_power;
|
||||
__le32 twice_antenna_gain;
|
||||
__le32 power_limit;
|
||||
__le32 rate_max;
|
||||
__le32 num_tx_chain;
|
||||
__le32 ctl;
|
||||
__le32 flags;
|
||||
__le32 caps;
|
||||
} __packed;
|
||||
|
||||
struct wmi_max_reg_power_fixed_params {
|
||||
__le32 reg_power_type;
|
||||
__le32 reg_array_len;
|
||||
__le32 d1;
|
||||
__le32 d2;
|
||||
__le32 d3;
|
||||
__le32 d4;
|
||||
} __packed;
|
||||
|
||||
struct wmi_max_reg_power_allowed_arg {
|
||||
struct wmi_max_reg_power_fixed_params tpc_reg_pwr;
|
||||
s16 *reg_pwr_array;
|
||||
};
|
||||
|
||||
struct wmi_tpc_rates_array_fixed_params {
|
||||
__le32 rate_array_type;
|
||||
__le32 rate_array_len;
|
||||
} __packed;
|
||||
|
||||
struct wmi_tpc_rates_array_arg {
|
||||
struct wmi_tpc_rates_array_fixed_params tpc_rates_array;
|
||||
s16 *rate_array;
|
||||
};
|
||||
|
||||
struct wmi_tpc_ctl_pwr_fixed_params {
|
||||
__le32 ctl_array_type;
|
||||
__le32 ctl_array_len;
|
||||
__le32 end_of_ctl_pwr;
|
||||
__le32 ctl_pwr_count;
|
||||
__le32 d1;
|
||||
__le32 d2;
|
||||
__le32 d3;
|
||||
__le32 d4;
|
||||
} __packed;
|
||||
|
||||
struct wmi_tpc_ctl_pwr_table_arg {
|
||||
struct wmi_tpc_ctl_pwr_fixed_params tpc_ctl_pwr;
|
||||
s8 *ctl_pwr_table;
|
||||
};
|
||||
|
||||
struct wmi_tpc_stats_arg {
|
||||
u32 pdev_id;
|
||||
u32 event_count;
|
||||
u32 end_of_event;
|
||||
u32 tlvs_rcvd;
|
||||
struct wmi_max_reg_power_allowed_arg max_reg_allowed_power;
|
||||
struct wmi_tpc_rates_array_arg rates_array1;
|
||||
struct wmi_tpc_rates_array_arg rates_array2;
|
||||
struct wmi_tpc_config_params tpc_config;
|
||||
struct wmi_tpc_ctl_pwr_table_arg ctl_array;
|
||||
};
|
||||
|
||||
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
|
||||
struct ath12k_wmi_resource_config_arg *config);
|
||||
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
|
||||
@@ -5639,7 +5915,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id,
|
||||
struct sk_buff *frame);
|
||||
int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id,
|
||||
const u8 *p2p_ie);
|
||||
int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id,
|
||||
int ath12k_wmi_bcn_tmpl(struct ath12k_link_vif *arvif,
|
||||
struct ieee80211_mutable_offsets *offs,
|
||||
struct sk_buff *bcn,
|
||||
struct ath12k_wmi_bcn_tmpl_ema_arg *ema_args);
|
||||
@@ -5753,6 +6029,13 @@ int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id,
|
||||
const u8 *buf, size_t buf_len);
|
||||
int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table);
|
||||
int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table);
|
||||
int ath12k_wmi_send_stats_request_cmd(struct ath12k *ar, u32 stats_id,
|
||||
u32 vdev_id, u32 pdev_id);
|
||||
__le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len);
|
||||
|
||||
int ath12k_wmi_send_tpc_stats_request(struct ath12k *ar,
|
||||
enum wmi_halphy_ctrl_path_stats_id tpc_stats_type);
|
||||
void ath12k_wmi_free_tpc_stats_mem(struct ath12k *ar);
|
||||
|
||||
static inline u32
|
||||
ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param)
|
||||
@@ -5806,5 +6089,8 @@ int ath12k_wmi_sta_keepalive(struct ath12k *ar,
|
||||
int ath12k_wmi_mlo_setup(struct ath12k *ar, struct wmi_mlo_setup_arg *mlo_params);
|
||||
int ath12k_wmi_mlo_ready(struct ath12k *ar);
|
||||
int ath12k_wmi_mlo_teardown(struct ath12k *ar);
|
||||
void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *fw_stats, u32 stats_id,
|
||||
char *buf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
@@ -990,6 +990,7 @@ exit:
|
||||
case ATH12K_HW_STATE_RESTARTING:
|
||||
case ATH12K_HW_STATE_RESTARTED:
|
||||
case ATH12K_HW_STATE_WEDGED:
|
||||
case ATH12K_HW_STATE_TM:
|
||||
ath12k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n",
|
||||
ah->state);
|
||||
ret = -EIO;
|
||||
|
||||
@@ -274,7 +274,6 @@ struct ath_node {
|
||||
|
||||
struct ath_tx_control {
|
||||
struct ath_txq *txq;
|
||||
struct ath_node *an;
|
||||
struct ieee80211_sta *sta;
|
||||
u8 paprd;
|
||||
};
|
||||
@@ -1018,7 +1017,7 @@ struct ath_softc {
|
||||
|
||||
u8 gtt_cnt;
|
||||
u32 intrstatus;
|
||||
u32 rx_active_check_time;
|
||||
unsigned long rx_active_check_time;
|
||||
u32 rx_active_count;
|
||||
u16 ps_flags; /* PS_* */
|
||||
bool ps_enabled;
|
||||
|
||||
@@ -628,12 +628,12 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
|
||||
else
|
||||
RX_STAT_INC(sc, rx_spectral_sample_err);
|
||||
|
||||
memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
|
||||
|
||||
/* Mix the received bins to the /dev/random
|
||||
* pool
|
||||
*/
|
||||
add_device_randomness(sample_buf, num_bins);
|
||||
|
||||
memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
|
||||
}
|
||||
|
||||
/* Process a normal frame */
|
||||
|
||||
@@ -647,7 +647,9 @@ static int ath9k_of_init(struct ath_softc *sc)
|
||||
ah->ah_flags |= AH_NO_EEP_SWAP;
|
||||
}
|
||||
|
||||
of_get_mac_address(np, common->macaddr);
|
||||
ret = of_get_mac_address(np, common->macaddr);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2291,19 +2291,10 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sta *sta = txctl->sta;
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct ath_vif *avp;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
int frmlen = skb->len + FCS_LEN;
|
||||
int padpos, padsize;
|
||||
|
||||
/* NOTE: sta can be NULL according to net/mac80211.h */
|
||||
if (sta)
|
||||
txctl->an = (struct ath_node *)sta->drv_priv;
|
||||
else if (vif && ieee80211_is_data(hdr->frame_control)) {
|
||||
avp = (void *)vif->drv_priv;
|
||||
txctl->an = &avp->mcast_node;
|
||||
}
|
||||
|
||||
if (info->control.hw_key)
|
||||
frmlen += info->control.hw_key->icv_len;
|
||||
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/* "API" level of the ath11k testmode interface. Bump it after every
|
||||
/* "API" level of the ath testmode interface. Bump it after every
|
||||
* incompatible interface change.
|
||||
*/
|
||||
#define ATH11K_TESTMODE_VERSION_MAJOR 1
|
||||
#define ATH_TESTMODE_VERSION_MAJOR 1
|
||||
|
||||
/* Bump this after every _compatible_ interface change, for example
|
||||
* addition of a new command or an attribute.
|
||||
*/
|
||||
#define ATH11K_TESTMODE_VERSION_MINOR 1
|
||||
#define ATH_TESTMODE_VERSION_MINOR 1
|
||||
|
||||
#define ATH11K_TM_DATA_MAX_LEN 5000
|
||||
#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048
|
||||
#define ATH_TM_DATA_MAX_LEN 5000
|
||||
#define ATH_FTM_EVENT_MAX_BUF_LENGTH 2048
|
||||
|
||||
enum ath11k_tm_attr {
|
||||
__ATH11K_TM_ATTR_INVALID = 0,
|
||||
ATH11K_TM_ATTR_CMD = 1,
|
||||
ATH11K_TM_ATTR_DATA = 2,
|
||||
ATH11K_TM_ATTR_WMI_CMDID = 3,
|
||||
ATH11K_TM_ATTR_VERSION_MAJOR = 4,
|
||||
ATH11K_TM_ATTR_VERSION_MINOR = 5,
|
||||
ATH11K_TM_ATTR_WMI_OP_VERSION = 6,
|
||||
enum ath_tm_attr {
|
||||
__ATH_TM_ATTR_INVALID = 0,
|
||||
ATH_TM_ATTR_CMD = 1,
|
||||
ATH_TM_ATTR_DATA = 2,
|
||||
ATH_TM_ATTR_WMI_CMDID = 3,
|
||||
ATH_TM_ATTR_VERSION_MAJOR = 4,
|
||||
ATH_TM_ATTR_VERSION_MINOR = 5,
|
||||
ATH_TM_ATTR_WMI_OP_VERSION = 6,
|
||||
|
||||
/* keep last */
|
||||
__ATH11K_TM_ATTR_AFTER_LAST,
|
||||
ATH11K_TM_ATTR_MAX = __ATH11K_TM_ATTR_AFTER_LAST - 1,
|
||||
__ATH_TM_ATTR_AFTER_LAST,
|
||||
ATH_TM_ATTR_MAX = __ATH_TM_ATTR_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/* All ath11k testmode interface commands specified in
|
||||
* ATH11K_TM_ATTR_CMD
|
||||
/* All ath testmode interface commands specified in
|
||||
* ATH_TM_ATTR_CMD
|
||||
*/
|
||||
enum ath11k_tm_cmd {
|
||||
/* Returns the supported ath11k testmode interface version in
|
||||
* ATH11K_TM_ATTR_VERSION. Always guaranteed to work. User space
|
||||
enum ath_tm_cmd {
|
||||
/* Returns the supported ath testmode interface version in
|
||||
* ATH_TM_ATTR_VERSION. Always guaranteed to work. User space
|
||||
* uses this to verify it's using the correct version of the
|
||||
* testmode interface
|
||||
*/
|
||||
ATH11K_TM_CMD_GET_VERSION = 0,
|
||||
ATH_TM_CMD_GET_VERSION = 0,
|
||||
|
||||
/* The command used to transmit a WMI command to the firmware and
|
||||
* the event to receive WMI events from the firmware. Without
|
||||
* struct wmi_cmd_hdr header, only the WMI payload. Command id is
|
||||
* provided with ATH11K_TM_ATTR_WMI_CMDID and payload in
|
||||
* ATH11K_TM_ATTR_DATA.
|
||||
* provided with ATH_TM_ATTR_WMI_CMDID and payload in
|
||||
* ATH_TM_ATTR_DATA.
|
||||
*/
|
||||
ATH11K_TM_CMD_WMI = 1,
|
||||
ATH_TM_CMD_WMI = 1,
|
||||
|
||||
/* Boots the UTF firmware, the netdev interface must be down at the
|
||||
* time.
|
||||
*/
|
||||
ATH11K_TM_CMD_TESTMODE_START = 2,
|
||||
ATH_TM_CMD_TESTMODE_START = 2,
|
||||
|
||||
/* The command used to transmit a FTM WMI command to the firmware
|
||||
* and the event to receive WMI events from the firmware. The data
|
||||
@@ -62,5 +62,5 @@ enum ath11k_tm_cmd {
|
||||
* The data payload size could be large and the driver needs to
|
||||
* send segmented data to firmware.
|
||||
*/
|
||||
ATH11K_TM_CMD_WMI_FTM = 3,
|
||||
ATH_TM_CMD_WMI_FTM = 3,
|
||||
};
|
||||
@@ -2495,6 +2495,9 @@ il4965_rs_dbgfs_set_mcs(struct il_lq_sta *lq_sta, u32 * rate_n_flags, int idx)
|
||||
u8 valid_tx_ant;
|
||||
u8 ant_sel_tx;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_MAC80211_DEBUGFS))
|
||||
return;
|
||||
|
||||
il = lq_sta->drv;
|
||||
valid_tx_ant = il->hw_params.valid_tx_ant;
|
||||
if (lq_sta->dbg_fixed_rate) {
|
||||
|
||||
@@ -81,14 +81,25 @@ config IWLMVM
|
||||
of the devices that use this firmware is available here:
|
||||
https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
|
||||
|
||||
config IWLMLD
|
||||
tristate "Intel Wireless WiFi MLD Firmware support"
|
||||
select WANT_DEV_COREDUMP
|
||||
depends on MAC80211
|
||||
depends on PTP_1588_CLOCK_OPTIONAL
|
||||
help
|
||||
This is the driver that supports firmwares of MLD capable devices.
|
||||
The list of the devices that use this firmware is available here:
|
||||
https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
|
||||
|
||||
# don't call it _MODULE -- will confuse Kconfig/fixdep/...
|
||||
config IWLWIFI_OPMODE_MODULAR
|
||||
bool
|
||||
default y if IWLDVM=m
|
||||
default y if IWLMVM=m
|
||||
default y if IWLMLD=m
|
||||
|
||||
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
|
||||
depends on IWLDVM=n && IWLMVM=n
|
||||
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM or IWLMLD"
|
||||
depends on IWLDVM=n && IWLMVM=n && IWLMLD=n
|
||||
|
||||
menu "Debugging Options"
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-gen3.o
|
||||
iwlwifi-objs += pcie/trans-gen2.o pcie/tx-gen2.o
|
||||
iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/22000.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += cfg/ax210.o cfg/bz.o cfg/sc.o cfg/dr.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += cfg/ax210.o
|
||||
iwlwifi-$(CONFIG_IWLMLD) += cfg/bz.o cfg/sc.o cfg/dr.o
|
||||
iwlwifi-objs += iwl-dbg-tlv.o
|
||||
iwlwifi-objs += iwl-trans.o
|
||||
|
||||
@@ -20,6 +21,7 @@ iwlwifi-objs += fw/img.o fw/notif-wait.o fw/rs.o
|
||||
iwlwifi-objs += fw/dbg.o fw/pnvm.o fw/dump.o
|
||||
iwlwifi-objs += fw/regulatory.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o
|
||||
iwlwifi-$(CONFIG_IWLMLD) += fw/smem.o fw/init.o
|
||||
iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
|
||||
iwlwifi-$(CONFIG_EFI) += fw/uefi.o
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o
|
||||
@@ -33,6 +35,7 @@ ccflags-y += -I$(src)
|
||||
obj-$(CONFIG_IWLDVM) += dvm/
|
||||
obj-$(CONFIG_IWLMVM) += mvm/
|
||||
obj-$(CONFIG_IWLMEI) += mei/
|
||||
obj-$(CONFIG_IWLMLD) += mld/
|
||||
|
||||
obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += tests/
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
@@ -10,10 +10,10 @@
|
||||
#include "fw/api/txq.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL_BZ_UCODE_API_MAX 96
|
||||
#define IWL_BZ_UCODE_API_MAX 98
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_BZ_UCODE_API_MIN 92
|
||||
#define IWL_BZ_UCODE_API_MIN 93
|
||||
|
||||
/* NVM versions */
|
||||
#define IWL_BZ_NVM_VERSION 0x0a1d
|
||||
@@ -38,6 +38,11 @@
|
||||
#define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \
|
||||
IWL_BZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
|
||||
|
||||
#if !IS_ENABLED(CONFIG_IWLMVM)
|
||||
const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz";
|
||||
const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz";
|
||||
#endif
|
||||
|
||||
static const struct iwl_base_params iwl_bz_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_32K,
|
||||
.num_of_queues = 512,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "fw/api/txq.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL_DR_UCODE_API_MAX 96
|
||||
#define IWL_DR_UCODE_API_MAX 98
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_DR_UCODE_API_MIN 96
|
||||
@@ -148,11 +148,9 @@ const struct iwl_cfg_trans_params iwl_br_trans_cfg = {
|
||||
.mq_rx_supported = true,
|
||||
.rf_id = true,
|
||||
.gen2 = true,
|
||||
.integrated = true,
|
||||
.umac_prph_offset = 0x300000,
|
||||
.xtal_latency = 12000,
|
||||
.low_latency_xtal = true,
|
||||
.ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US,
|
||||
};
|
||||
|
||||
const char iwl_br_name[] = "Intel(R) TBD Br device";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
@@ -10,10 +10,10 @@
|
||||
#include "fw/api/txq.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL_SC_UCODE_API_MAX 96
|
||||
#define IWL_SC_UCODE_API_MAX 98
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_SC_UCODE_API_MIN 92
|
||||
#define IWL_SC_UCODE_API_MIN 93
|
||||
|
||||
/* NVM versions */
|
||||
#define IWL_SC_NVM_VERSION 0x0a1d
|
||||
@@ -142,6 +142,8 @@ const struct iwl_cfg_trans_params iwl_sc_trans_cfg = {
|
||||
.ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US,
|
||||
};
|
||||
|
||||
const char iwl_sp_name[] = "Intel(R) Wi-Fi 7 BE213 160MHz";
|
||||
|
||||
const struct iwl_cfg iwl_cfg_sc = {
|
||||
.fw_name_mac = "sc",
|
||||
IWL_DEVICE_SC,
|
||||
|
||||
@@ -1180,85 +1180,87 @@ struct iwl_dram_scratch {
|
||||
} __packed;
|
||||
|
||||
struct iwl_tx_cmd {
|
||||
/*
|
||||
* MPDU byte count:
|
||||
* MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
|
||||
* + 8 byte IV for CCM or TKIP (not used for WEP)
|
||||
* + Data payload
|
||||
* + 8-byte MIC (not used for CCM/WEP)
|
||||
* NOTE: Does not include Tx command bytes, post-MAC pad bytes,
|
||||
* MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
|
||||
* Range: 14-2342 bytes.
|
||||
*/
|
||||
__le16 len;
|
||||
/* New members MUST be added within the __struct_group() macro below. */
|
||||
__struct_group(iwl_tx_cmd_hdr, __hdr, __packed,
|
||||
/*
|
||||
* MPDU byte count:
|
||||
* MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
|
||||
* + 8 byte IV for CCM or TKIP (not used for WEP)
|
||||
* + Data payload
|
||||
* + 8-byte MIC (not used for CCM/WEP)
|
||||
* NOTE: Does not include Tx command bytes, post-MAC pad bytes,
|
||||
* MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
|
||||
* Range: 14-2342 bytes.
|
||||
*/
|
||||
__le16 len;
|
||||
|
||||
/*
|
||||
* MPDU or MSDU byte count for next frame.
|
||||
* Used for fragmentation and bursting, but not 11n aggregation.
|
||||
* Same as "len", but for next frame. Set to 0 if not applicable.
|
||||
*/
|
||||
__le16 next_frame_len;
|
||||
/*
|
||||
* MPDU or MSDU byte count for next frame.
|
||||
* Used for fragmentation and bursting, but not 11n aggregation.
|
||||
* Same as "len", but for next frame. Set to 0 if not applicable.
|
||||
*/
|
||||
__le16 next_frame_len;
|
||||
|
||||
__le32 tx_flags; /* TX_CMD_FLG_* */
|
||||
__le32 tx_flags; /* TX_CMD_FLG_* */
|
||||
|
||||
/* uCode may modify this field of the Tx command (in host DRAM!).
|
||||
* Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
|
||||
struct iwl_dram_scratch scratch;
|
||||
/* uCode may modify this field of the Tx command (in host DRAM!).
|
||||
* Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
|
||||
struct iwl_dram_scratch scratch;
|
||||
|
||||
/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
|
||||
__le32 rate_n_flags; /* RATE_MCS_* */
|
||||
/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
|
||||
__le32 rate_n_flags; /* RATE_MCS_* */
|
||||
|
||||
/* Index of destination station in uCode's station table */
|
||||
u8 sta_id;
|
||||
/* Index of destination station in uCode's station table */
|
||||
u8 sta_id;
|
||||
|
||||
/* Type of security encryption: CCM or TKIP */
|
||||
u8 sec_ctl; /* TX_CMD_SEC_* */
|
||||
/* Type of security encryption: CCM or TKIP */
|
||||
u8 sec_ctl; /* TX_CMD_SEC_* */
|
||||
|
||||
/*
|
||||
* Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
|
||||
* Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set. Normally "0" for
|
||||
* data frames, this field may be used to selectively reduce initial
|
||||
* rate (via non-0 value) for special frames (e.g. management), while
|
||||
* still supporting rate scaling for all frames.
|
||||
*/
|
||||
u8 initial_rate_index;
|
||||
u8 reserved;
|
||||
u8 key[16];
|
||||
__le16 next_frame_flags;
|
||||
__le16 reserved2;
|
||||
union {
|
||||
__le32 life_time;
|
||||
__le32 attempt;
|
||||
} stop_time;
|
||||
/*
|
||||
* Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
|
||||
* Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set. Normally "0" for
|
||||
* data frames, this field may be used to selectively reduce initial
|
||||
* rate (via non-0 value) for special frames (e.g. management), while
|
||||
* still supporting rate scaling for all frames.
|
||||
*/
|
||||
u8 initial_rate_index;
|
||||
u8 reserved;
|
||||
u8 key[16];
|
||||
__le16 next_frame_flags;
|
||||
__le16 reserved2;
|
||||
union {
|
||||
__le32 life_time;
|
||||
__le32 attempt;
|
||||
} stop_time;
|
||||
|
||||
/* Host DRAM physical address pointer to "scratch" in this command.
|
||||
* Must be dword aligned. "0" in dram_lsb_ptr disables usage. */
|
||||
__le32 dram_lsb_ptr;
|
||||
u8 dram_msb_ptr;
|
||||
/* Host DRAM physical address pointer to "scratch" in this command.
|
||||
* Must be dword aligned. "0" in dram_lsb_ptr disables usage. */
|
||||
__le32 dram_lsb_ptr;
|
||||
u8 dram_msb_ptr;
|
||||
|
||||
u8 rts_retry_limit; /*byte 50 */
|
||||
u8 data_retry_limit; /*byte 51 */
|
||||
u8 tid_tspec;
|
||||
union {
|
||||
__le16 pm_frame_timeout;
|
||||
__le16 attempt_duration;
|
||||
} timeout;
|
||||
u8 rts_retry_limit; /*byte 50 */
|
||||
u8 data_retry_limit; /*byte 51 */
|
||||
u8 tid_tspec;
|
||||
union {
|
||||
__le16 pm_frame_timeout;
|
||||
__le16 attempt_duration;
|
||||
} timeout;
|
||||
|
||||
/*
|
||||
* Duration of EDCA burst Tx Opportunity, in 32-usec units.
|
||||
* Set this if txop time is not specified by HCCA protocol (e.g. by AP).
|
||||
*/
|
||||
__le16 driver_txop;
|
||||
/*
|
||||
* Duration of EDCA burst Tx Opportunity, in 32-usec units.
|
||||
* Set this if txop time is not specified by HCCA protocol (e.g. by AP).
|
||||
*/
|
||||
__le16 driver_txop;
|
||||
|
||||
);
|
||||
/*
|
||||
* MAC header goes here, followed by 2 bytes padding if MAC header
|
||||
* length is 26 or 30 bytes, followed by payload data
|
||||
*/
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(u8, payload);
|
||||
DECLARE_FLEX_ARRAY(struct ieee80211_hdr, hdr);
|
||||
};
|
||||
struct ieee80211_hdr hdr[];
|
||||
} __packed;
|
||||
static_assert(offsetof(struct iwl_tx_cmd, hdr) == sizeof(struct iwl_tx_cmd_hdr),
|
||||
"struct member likely outside of __struct_group()");
|
||||
|
||||
/*
|
||||
* TX command response is sent after *agn* transmission attempts.
|
||||
@@ -2312,7 +2314,7 @@ struct iwl_scan_cmd {
|
||||
|
||||
/* For active scans (set to all-0s for passive scans).
|
||||
* Does not include payload. Must specify Tx rate; no rate scaling. */
|
||||
struct iwl_tx_cmd tx_cmd;
|
||||
struct iwl_tx_cmd_hdr tx_cmd;
|
||||
|
||||
/* For directed active scans (set to all-0s otherwise) */
|
||||
struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
|
||||
@@ -2423,7 +2425,7 @@ struct iwlagn_beacon_notif {
|
||||
*/
|
||||
|
||||
struct iwl_tx_beacon_cmd {
|
||||
struct iwl_tx_cmd tx;
|
||||
struct iwl_tx_cmd_hdr tx;
|
||||
__le16 tim_idx;
|
||||
u8 tim_size;
|
||||
u8 reserved1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2005-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2005-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
@@ -51,7 +51,7 @@ enum iwl_debug_cmds {
|
||||
/**
|
||||
* @GET_TAS_STATUS:
|
||||
* sends command to fw to get TAS status
|
||||
* the response is &struct iwl_mvm_tas_status_resp
|
||||
* the response is &struct iwl_tas_status_resp
|
||||
*/
|
||||
GET_TAS_STATUS = 0xA,
|
||||
/**
|
||||
@@ -439,25 +439,20 @@ struct iwl_dbg_dump_complete_cmd {
|
||||
__le32 tp_data;
|
||||
} __packed; /* FW_DUMP_COMPLETE_CMD_API_S_VER_1 */
|
||||
|
||||
#define TAS_LMAC_BAND_HB 0
|
||||
#define TAS_LMAC_BAND_LB 1
|
||||
#define TAS_LMAC_BAND_UHB 2
|
||||
#define TAS_LMAC_BAND_INVALID 3
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_tas_status_per_mac - tas status per lmac
|
||||
* struct iwl_tas_status_per_mac - tas status per lmac
|
||||
* @static_status: tas statically enabled or disabled per lmac - TRUE/FALSE
|
||||
* @static_dis_reason: TAS static disable reason, uses
|
||||
* &enum iwl_mvm_tas_statically_disabled_reason
|
||||
* &enum iwl_tas_statically_disabled_reason
|
||||
* @dynamic_status: Current TAS status. uses
|
||||
* &enum iwl_mvm_tas_dyna_status
|
||||
* &enum iwl_tas_dyna_status
|
||||
* @near_disconnection: is TAS currently near disconnection per lmac? - TRUE/FALSE
|
||||
* @max_reg_pwr_limit: Regulatory power limits in dBm
|
||||
* @sar_limit: SAR limits per lmac in dBm
|
||||
* @band: Band per lmac
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_mvm_tas_status_per_mac {
|
||||
struct iwl_tas_status_per_mac {
|
||||
u8 static_status;
|
||||
u8 static_dis_reason;
|
||||
u8 dynamic_status;
|
||||
@@ -466,35 +461,35 @@ struct iwl_mvm_tas_status_per_mac {
|
||||
__le16 sar_limit;
|
||||
u8 band;
|
||||
u8 reserved[3];
|
||||
} __packed; /*DEBUG_GET_TAS_STATUS_PER_MAC_S_VER_1*/
|
||||
} __packed; /* DEBUG_GET_TAS_STATUS_PER_MAC_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_tas_status_resp - Response to GET_TAS_STATUS
|
||||
* struct iwl_tas_status_resp - Response to GET_TAS_STATUS
|
||||
* @tas_fw_version: TAS FW version
|
||||
* @is_uhb_for_usa_enable: is UHB enabled in USA? - TRUE/FALSE
|
||||
* @curr_mcc: current mcc
|
||||
* @block_list: country block list
|
||||
* @tas_status_mac: TAS status per lmac, uses
|
||||
* &struct iwl_mvm_tas_status_per_mac
|
||||
* &struct iwl_tas_status_per_mac
|
||||
* @in_dual_radio: is TAS in dual radio? - TRUE/FALSE
|
||||
* @uhb_allowed_flags: see &enum iwl_tas_uhb_allowed_flags.
|
||||
* This member is valid only when fw has
|
||||
* %IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT capability.
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_mvm_tas_status_resp {
|
||||
struct iwl_tas_status_resp {
|
||||
u8 tas_fw_version;
|
||||
u8 is_uhb_for_usa_enable;
|
||||
__le16 curr_mcc;
|
||||
__le16 block_list[16];
|
||||
struct iwl_mvm_tas_status_per_mac tas_status_mac[2];
|
||||
struct iwl_tas_status_per_mac tas_status_mac[2];
|
||||
u8 in_dual_radio;
|
||||
u8 uhb_allowed_flags;
|
||||
u8 reserved[2];
|
||||
} __packed; /*DEBUG_GET_TAS_STATUS_RSP_API_S_VER_3*/
|
||||
} __packed; /* DEBUG_GET_TAS_STATUS_RSP_API_S_VER_3 */
|
||||
|
||||
/**
|
||||
* enum iwl_mvm_tas_dyna_status - TAS current running status
|
||||
* enum iwl_tas_dyna_status - TAS current running status
|
||||
* @TAS_DYNA_INACTIVE: TAS status is inactive
|
||||
* @TAS_DYNA_INACTIVE_MVM_MODE: TAS is disabled due because FW is in MVM mode
|
||||
* or is in softap mode.
|
||||
@@ -507,7 +502,7 @@ struct iwl_mvm_tas_status_resp {
|
||||
* @TAS_DYNA_ACTIVE: TAS is currently active
|
||||
* @TAS_DYNA_STATUS_MAX: TAS status max value
|
||||
*/
|
||||
enum iwl_mvm_tas_dyna_status {
|
||||
enum iwl_tas_dyna_status {
|
||||
TAS_DYNA_INACTIVE,
|
||||
TAS_DYNA_INACTIVE_MVM_MODE,
|
||||
TAS_DYNA_INACTIVE_TRIGGER_MODE,
|
||||
@@ -516,19 +511,22 @@ enum iwl_mvm_tas_dyna_status {
|
||||
TAS_DYNA_ACTIVE,
|
||||
|
||||
TAS_DYNA_STATUS_MAX,
|
||||
}; /*_TAS_DYNA_STATUS_E*/
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_mvm_tas_statically_disabled_reason - TAS statically disabled reason
|
||||
* enum iwl_tas_statically_disabled_reason - TAS statically disabled reason
|
||||
* @TAS_DISABLED_DUE_TO_BIOS: TAS is disabled because TAS is disabled in BIOS
|
||||
* @TAS_DISABLED_DUE_TO_SAR_6DBM: TAS is disabled because SAR limit is less than 6 Dbm
|
||||
* @TAS_DISABLED_REASON_INVALID: TAS disable reason is invalid
|
||||
* @TAS_DISABLED_DUE_TO_TABLE_SOURCE_INVALID: TAS is disabled due to
|
||||
* table source invalid
|
||||
* @TAS_DISABLED_REASON_MAX: TAS disable reason max value
|
||||
*/
|
||||
enum iwl_mvm_tas_statically_disabled_reason {
|
||||
enum iwl_tas_statically_disabled_reason {
|
||||
TAS_DISABLED_DUE_TO_BIOS,
|
||||
TAS_DISABLED_DUE_TO_SAR_6DBM,
|
||||
TAS_DISABLED_REASON_INVALID,
|
||||
TAS_DISABLED_DUE_TO_TABLE_SOURCE_INVALID,
|
||||
|
||||
TAS_DISABLED_REASON_MAX,
|
||||
}; /*_TAS_STATICALLY_DISABLED_REASON_E*/
|
||||
|
||||
@@ -15,6 +15,19 @@ enum iwl_dhc_table_id {
|
||||
* @DHC_TABLE_INTEGRATION: select the integration table
|
||||
*/
|
||||
DHC_TABLE_INTEGRATION = 2 << DHC_TABLE_MASK_POS,
|
||||
/**
|
||||
* @DHC_TABLE_TOOLS: select the tools table
|
||||
*/
|
||||
DHC_TABLE_TOOLS = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_dhc_umac_tools_table - tools operations
|
||||
* @DHC_TOOLS_UMAC_GET_TAS_STATUS: Get TAS status.
|
||||
* See @struct iwl_dhc_tas_status_resp
|
||||
*/
|
||||
enum iwl_dhc_umac_tools_table {
|
||||
DHC_TOOLS_UMAC_GET_TAS_STATUS = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -58,6 +71,90 @@ struct iwl_dhc_cmd {
|
||||
__le32 data[];
|
||||
} __packed; /* DHC_CMD_API_S */
|
||||
|
||||
/**
|
||||
* struct iwl_dhc_payload_hdr - DHC payload header
|
||||
* @version: a version of a payload
|
||||
* @reserved: reserved for alignment
|
||||
*/
|
||||
struct iwl_dhc_payload_hdr {
|
||||
u8 version;
|
||||
u8 reserved[3];
|
||||
} __packed; /* DHC_PAYLOAD_HDR_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_dhc_tas_status_per_radio - TAS status per radio
|
||||
* @band: &PHY_BAND_5 for high band, PHY_BAND_24 for low band and
|
||||
* &PHY_BAND_6 for ultra high band.
|
||||
* @static_status: TAS statically enabled or disabled
|
||||
* @static_disable_reason: TAS static disable reason, uses
|
||||
* &enum iwl_tas_statically_disabled_reason
|
||||
* @near_disconnection: is TAS currently near disconnection per radio
|
||||
* @dynamic_status_ant_a: Antenna A current TAS status.
|
||||
* uses &enum iwl_tas_dyna_status
|
||||
* @dynamic_status_ant_b: Antenna B current TAS status.
|
||||
* uses &enum iwl_tas_dyna_status
|
||||
* @max_reg_pwr_limit_ant_a: Antenna A regulatory power limits in dBm
|
||||
* @max_reg_pwr_limit_ant_b: Antenna B regulatory power limits in dBm
|
||||
* @sar_limit_ant_a: Antenna A SAR limit per radio in dBm
|
||||
* @sar_limit_ant_b: Antenna B SAR limit per radio in dBm
|
||||
* @reserved: reserved for alignment
|
||||
*/
|
||||
struct iwl_dhc_tas_status_per_radio {
|
||||
u8 band;
|
||||
u8 static_status;
|
||||
u8 static_disable_reason;
|
||||
u8 near_disconnection;
|
||||
u8 dynamic_status_ant_a;
|
||||
u8 dynamic_status_ant_b;
|
||||
__le16 max_reg_pwr_limit_ant_a;
|
||||
__le16 max_reg_pwr_limit_ant_b;
|
||||
__le16 sar_limit_ant_a;
|
||||
__le16 sar_limit_ant_b;
|
||||
u8 reserved[2];
|
||||
} __packed; /* DHC_TAS_STATUS_PER_RADIO_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_dhc_tas_status_resp - Response to DHC_TOOLS_UMAC_GET_TAS_STATUS
|
||||
* @header: DHC payload header, uses &struct iwl_dhc_payload_hdr
|
||||
* @tas_config_info: see @struct bios_value_u32
|
||||
* @mcc_block_list: block listed country codes
|
||||
* @tas_status_radio: TAS status, uses &struct iwl_dhc_tas_status_per_radio
|
||||
* @curr_mcc: current mcc
|
||||
* @valid_radio_mask: represent entry in tas_status_per_radio is valid.
|
||||
* @reserved: reserved for alignment
|
||||
*/
|
||||
struct iwl_dhc_tas_status_resp {
|
||||
struct iwl_dhc_payload_hdr header;
|
||||
struct bios_value_u32 tas_config_info;
|
||||
__le16 mcc_block_list[IWL_WTAS_BLACK_LIST_MAX];
|
||||
struct iwl_dhc_tas_status_per_radio tas_status_radio[2];
|
||||
__le16 curr_mcc;
|
||||
u8 valid_radio_mask;
|
||||
u8 reserved;
|
||||
} __packed; /* DHC_TAS_STATUS_RSP_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_dhc_cmd_resp_v1 - debug host command response
|
||||
* @status: status of the command
|
||||
* @data: the response data
|
||||
*/
|
||||
struct iwl_dhc_cmd_resp_v1 {
|
||||
__le32 status;
|
||||
__le32 data[];
|
||||
} __packed; /* DHC_RESP_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_dhc_cmd_resp - debug host command response
|
||||
* @status: status of the command
|
||||
* @descriptor: command descriptor (index_and_mask) returned
|
||||
* @data: the response data
|
||||
*/
|
||||
struct iwl_dhc_cmd_resp {
|
||||
__le32 status;
|
||||
__le32 descriptor;
|
||||
__le32 data[];
|
||||
} __packed; /* DHC_RESP_API_S_VER_2 and DHC_RESP_API_S_VER_3 */
|
||||
|
||||
/**
|
||||
* enum iwl_dhc_twt_operation_type - describes the TWT operation type
|
||||
*
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2019-2022, 2024 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2019-2022, 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
#ifndef __iwl_fw_api_phy_h__
|
||||
#define __iwl_fw_api_phy_h__
|
||||
#include <linux/types.h>
|
||||
#include <linux/bits.h>
|
||||
|
||||
/**
|
||||
* enum iwl_phy_ops_subcmd_ids - PHY group commands
|
||||
|
||||
75
drivers/net/wireless/intel/iwlwifi/fw/dhc-utils.h
Normal file
75
drivers/net/wireless/intel/iwlwifi/fw/dhc-utils.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2021, 2025 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_dhc_utils_h__
|
||||
#define __iwl_fw_dhc_utils_h__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "fw/img.h"
|
||||
#include "api/commands.h"
|
||||
#include "api/dhc.h"
|
||||
|
||||
/**
|
||||
* iwl_dhc_resp_status - return status of DHC response
|
||||
* @fw: firwmware image information
|
||||
* @pkt: response packet, must not be %NULL
|
||||
*
|
||||
* Returns: the status value of the DHC command or (u32)-1 if the
|
||||
* response was too short.
|
||||
*/
|
||||
static inline u32 iwl_dhc_resp_status(const struct iwl_fw *fw,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
if (iwl_fw_lookup_notif_ver(fw, IWL_ALWAYS_LONG_GROUP,
|
||||
DEBUG_HOST_COMMAND, 1) >= 2) {
|
||||
struct iwl_dhc_cmd_resp *resp = (void *)pkt->data;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) < sizeof(*resp))
|
||||
return (u32)-1;
|
||||
|
||||
return le32_to_cpu(resp->status);
|
||||
} else {
|
||||
struct iwl_dhc_cmd_resp_v1 *resp = (void *)pkt->data;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) < sizeof(*resp))
|
||||
return (u32)-1;
|
||||
|
||||
return le32_to_cpu(resp->status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_dhc_resp_data - return data pointer of DHC response
|
||||
* @fw: firwmware image information
|
||||
* @pkt: response packet, must not be %NULL
|
||||
* @len: where to store the length
|
||||
*
|
||||
* Returns: The data pointer, or an ERR_PTR() if the data was
|
||||
* not valid (too short).
|
||||
*/
|
||||
static inline void *iwl_dhc_resp_data(const struct iwl_fw *fw,
|
||||
struct iwl_rx_packet *pkt,
|
||||
unsigned int *len)
|
||||
{
|
||||
if (iwl_fw_lookup_notif_ver(fw, IWL_ALWAYS_LONG_GROUP,
|
||||
DEBUG_HOST_COMMAND, 1) >= 2) {
|
||||
struct iwl_dhc_cmd_resp *resp = (void *)pkt->data;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) < sizeof(*resp))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
*len = iwl_rx_packet_payload_len(pkt) - sizeof(*resp);
|
||||
return (void *)&resp->data;
|
||||
} else {
|
||||
struct iwl_dhc_cmd_resp_v1 *resp = (void *)pkt->data;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) < sizeof(*resp))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
*len = iwl_rx_packet_payload_len(pkt) - sizeof(*resp);
|
||||
return (void *)&resp->data;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __iwl_fw_dhc_utils_h__ */
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright(c) 2021-2024 Intel Corporation
|
||||
* Copyright(c) 2021-2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "iwl-drv.h"
|
||||
@@ -681,14 +681,16 @@ int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
|
||||
struct uefi_cnv_var_eckv *data;
|
||||
int ret = 0;
|
||||
|
||||
data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_ECKV_NAME,
|
||||
"ECKV", sizeof(*data), NULL);
|
||||
data = iwl_uefi_get_verified_variable_guid(fwrt->trans,
|
||||
&IWL_EFI_WIFI_BT_GUID,
|
||||
IWL_UEFI_ECKV_NAME,
|
||||
"ECKV", sizeof(*data), NULL);
|
||||
if (IS_ERR(data))
|
||||
return -EINVAL;
|
||||
|
||||
if (data->revision != IWL_UEFI_ECKV_REVISION) {
|
||||
ret = -EINVAL;
|
||||
IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n",
|
||||
IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI ECKV revision:%d\n",
|
||||
data->revision);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright(c) 2021-2024 Intel Corporation
|
||||
* Copyright(c) 2021-2025 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_uefi__
|
||||
#define __iwl_fw_uefi__
|
||||
@@ -19,7 +19,7 @@
|
||||
#define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS"
|
||||
#define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC"
|
||||
#define IWL_UEFI_WRDD_NAME L"UefiCnvWlanWRDD"
|
||||
#define IWL_UEFI_ECKV_NAME L"UefiCnvWlanECKV"
|
||||
#define IWL_UEFI_ECKV_NAME L"UefiCnvCommonECKV"
|
||||
#define IWL_UEFI_DSM_NAME L"UefiCnvWlanGeneralCfg"
|
||||
#define IWL_UEFI_WBEM_NAME L"UefiCnvWlanWBEM"
|
||||
#define IWL_UEFI_PUNCTURING_NAME L"UefiCnvWlanPuncturing"
|
||||
|
||||
@@ -550,6 +550,7 @@ extern const char iwl_ax231_name[];
|
||||
extern const char iwl_ax411_name[];
|
||||
extern const char iwl_fm_name[];
|
||||
extern const char iwl_wh_name[];
|
||||
extern const char iwl_sp_name[];
|
||||
extern const char iwl_gl_name[];
|
||||
extern const char iwl_mtp_name[];
|
||||
extern const char iwl_dr_name[];
|
||||
@@ -653,6 +654,10 @@ extern const struct iwl_cfg iwl_cfg_ma;
|
||||
|
||||
extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
#if IS_ENABLED(CONFIG_IWLMLD)
|
||||
extern const struct iwl_ht_params iwl_bz_ht_params;
|
||||
|
||||
extern const struct iwl_ht_params iwl_bz_ht_params;
|
||||
|
||||
@@ -664,6 +669,6 @@ extern const struct iwl_cfg iwl_cfg_sc2;
|
||||
extern const struct iwl_cfg iwl_cfg_sc2f;
|
||||
extern const struct iwl_cfg iwl_cfg_dr;
|
||||
extern const struct iwl_cfg iwl_cfg_br;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
#endif /* CONFIG_IWLMLD */
|
||||
|
||||
#endif /* __IWL_CONFIG_H__ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/firmware.h>
|
||||
#include "iwl-drv.h"
|
||||
@@ -1372,15 +1372,15 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
|
||||
switch (tp_id) {
|
||||
case IWL_FW_INI_TIME_POINT_EARLY:
|
||||
iwl_dbg_tlv_init_cfg(fwrt);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
iwl_dbg_tlv_update_drams(fwrt);
|
||||
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
break;
|
||||
case IWL_FW_INI_TIME_POINT_AFTER_ALIVE:
|
||||
iwl_dbg_tlv_apply_buffers(fwrt);
|
||||
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
break;
|
||||
case IWL_FW_INI_TIME_POINT_PERIODIC:
|
||||
iwl_dbg_tlv_set_periodic_trigs(fwrt);
|
||||
@@ -1390,14 +1390,14 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
|
||||
case IWL_FW_INI_TIME_POINT_MISSED_BEACONS:
|
||||
case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION:
|
||||
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data,
|
||||
iwl_dbg_tlv_check_fw_pkt);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
break;
|
||||
default:
|
||||
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
|
||||
iwl_dbg_tlv_apply_config(fwrt, conf_list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2005-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2005-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
@@ -75,6 +75,9 @@ struct iwl_drv {
|
||||
enum {
|
||||
DVM_OP_MODE,
|
||||
MVM_OP_MODE,
|
||||
#if IS_ENABLED(CONFIG_IWLMLD)
|
||||
MLD_OP_MODE,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Protects the table contents, i.e. the ops pointer & drv list */
|
||||
@@ -86,6 +89,9 @@ static struct iwlwifi_opmode_table {
|
||||
} iwlwifi_opmode_table[] = { /* ops set when driver is initialized */
|
||||
[DVM_OP_MODE] = { .name = "iwldvm", .ops = NULL },
|
||||
[MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL },
|
||||
#if IS_ENABLED(CONFIG_IWLMLD)
|
||||
[MLD_OP_MODE] = { .name = "iwlmld", .ops = NULL },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define IWL_DEFAULT_SCAN_CHANNELS 40
|
||||
@@ -168,6 +174,11 @@ static inline char iwl_drv_get_step(int step)
|
||||
return 'a' + step;
|
||||
}
|
||||
|
||||
static bool iwl_drv_is_wifi7_supported(struct iwl_trans *trans)
|
||||
{
|
||||
return CSR_HW_RFID_TYPE(trans->hw_rf_id) >= IWL_CFG_RF_TYPE_FM;
|
||||
}
|
||||
|
||||
const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf)
|
||||
{
|
||||
char mac_step, rf_step;
|
||||
@@ -316,6 +327,7 @@ struct iwl_firmware_pieces {
|
||||
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
||||
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
|
||||
size_t n_mem_tlv;
|
||||
u32 major;
|
||||
};
|
||||
|
||||
static void alloc_sec_data(struct iwl_firmware_pieces *pieces,
|
||||
@@ -957,19 +969,19 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
break;
|
||||
case IWL_UCODE_TLV_FW_VERSION: {
|
||||
const __le32 *ptr = (const void *)tlv_data;
|
||||
u32 major, minor;
|
||||
u32 minor;
|
||||
u8 local_comp;
|
||||
|
||||
if (tlv_len != sizeof(u32) * 3)
|
||||
goto invalid_tlv_len;
|
||||
|
||||
major = le32_to_cpup(ptr++);
|
||||
pieces->major = le32_to_cpup(ptr++);
|
||||
minor = le32_to_cpup(ptr++);
|
||||
local_comp = le32_to_cpup(ptr);
|
||||
|
||||
snprintf(drv->fw.fw_version,
|
||||
sizeof(drv->fw.fw_version),
|
||||
"%u.%08x.%u %s", major, minor,
|
||||
"%u.%08x.%u %s", pieces->major, minor,
|
||||
local_comp, iwl_reduced_fw_name(drv));
|
||||
break;
|
||||
}
|
||||
@@ -1468,6 +1480,8 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv)
|
||||
}
|
||||
}
|
||||
|
||||
#define IWL_MLD_SUPPORTED_FW_VERSION 97
|
||||
|
||||
/*
|
||||
* iwl_req_fw_callback - callback when firmware was loaded
|
||||
*
|
||||
@@ -1720,6 +1734,20 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
break;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IWLMLD)
|
||||
if (pieces->major >= IWL_MLD_SUPPORTED_FW_VERSION &&
|
||||
iwl_drv_is_wifi7_supported(drv->trans))
|
||||
op = &iwlwifi_opmode_table[MLD_OP_MODE];
|
||||
#else
|
||||
if (pieces->major >= IWL_MLD_SUPPORTED_FW_VERSION &&
|
||||
iwl_drv_is_wifi7_supported(drv->trans)) {
|
||||
IWL_ERR(drv,
|
||||
"IWLMLD needs to be compiled to support this firmware\n");
|
||||
mutex_unlock(&iwlwifi_opmode_table_mtx);
|
||||
goto out_unbind;
|
||||
}
|
||||
#endif
|
||||
|
||||
IWL_INFO(drv, "loaded firmware version %s op_mode %s\n",
|
||||
drv->fw.fw_version, op->name);
|
||||
|
||||
|
||||
@@ -944,7 +944,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
|
||||
IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK);
|
||||
break;
|
||||
case NL80211_BAND_6GHZ:
|
||||
if (!trans->reduced_cap_sku) {
|
||||
if (!trans->reduced_cap_sku &&
|
||||
trans->bw_limit >= 320) {
|
||||
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[0] |=
|
||||
IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
|
||||
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[1] |=
|
||||
@@ -1098,15 +1099,18 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
|
||||
iftype_data->he_cap.he_cap_elem.phy_cap_info[0] &=
|
||||
~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
|
||||
|
||||
if (trans->reduced_cap_sku) {
|
||||
if (trans->bw_limit < 320 || trans->reduced_cap_sku) {
|
||||
memset(&iftype_data->eht_cap.eht_mcs_nss_supp.bw._320, 0,
|
||||
sizeof(iftype_data->eht_cap.eht_mcs_nss_supp.bw._320));
|
||||
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] &=
|
||||
~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK;
|
||||
}
|
||||
|
||||
if (trans->reduced_cap_sku) {
|
||||
iftype_data->eht_cap.eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss = 0;
|
||||
iftype_data->eht_cap.eht_mcs_nss_supp.bw._160.rx_tx_mcs13_max_nss = 0;
|
||||
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[8] &=
|
||||
~IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA;
|
||||
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] &=
|
||||
~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2019-2021, 2023-2024 Intel Corporation
|
||||
* Copyright (C) 2019-2021, 2023-2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bsearch.h>
|
||||
@@ -641,6 +641,9 @@ IWL_EXPORT_SYMBOL(iwl_trans_tx);
|
||||
void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn,
|
||||
struct sk_buff_head *skbs, bool is_flush)
|
||||
{
|
||||
if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
|
||||
return;
|
||||
|
||||
if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
|
||||
"bad state = %d\n", trans->state))
|
||||
return;
|
||||
|
||||
16
drivers/net/wireless/intel/iwlwifi/mld/Makefile
Normal file
16
drivers/net/wireless/intel/iwlwifi/mld/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
obj-$(CONFIG_IWLMLD) += iwlmld.o
|
||||
obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += tests/
|
||||
|
||||
iwlmld-y += mld.o notif.o mac80211.o fw.o power.o iface.o link.o rx.o mcc.o session-protect.o phy.o
|
||||
iwlmld-y += scan.o sta.o tx.o coex.o tlc.o agg.o key.o regulatory.o ap.o thermal.o roc.o stats.o
|
||||
iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o
|
||||
iwlmld-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
|
||||
iwlmld-$(CONFIG_IWLWIFI_LEDS) += led.o
|
||||
iwlmld-$(CONFIG_PM_SLEEP) += d3.o
|
||||
|
||||
# non-upstream things
|
||||
iwlmld-$(CONFIG_IWL_VENDOR_CMDS) += vendor-cmd.o
|
||||
iwlmld-$(CONFIG_IWLMVM_AX_SOFTAP_TESTMODE) += ax-softap-testmode.o
|
||||
|
||||
subdir-ccflags-y += -I$(src)/../
|
||||
670
drivers/net/wireless/intel/iwlwifi/mld/agg.c
Normal file
670
drivers/net/wireless/intel/iwlwifi/mld/agg.c
Normal file
@@ -0,0 +1,670 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#include "agg.h"
|
||||
#include "sta.h"
|
||||
#include "hcmd.h"
|
||||
|
||||
static void
|
||||
iwl_mld_reorder_release_frames(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_mld_baid_data *baid_data,
|
||||
struct iwl_mld_reorder_buffer *reorder_buf,
|
||||
u16 nssn)
|
||||
{
|
||||
struct iwl_mld_reorder_buf_entry *entries =
|
||||
&baid_data->entries[reorder_buf->queue *
|
||||
baid_data->entries_per_queue];
|
||||
u16 ssn = reorder_buf->head_sn;
|
||||
|
||||
while (ieee80211_sn_less(ssn, nssn)) {
|
||||
int index = ssn % baid_data->buf_size;
|
||||
struct sk_buff_head *skb_list = &entries[index].frames;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ssn = ieee80211_sn_inc(ssn);
|
||||
|
||||
/* Empty the list. Will have more than one frame for A-MSDU.
|
||||
* Empty list is valid as well since nssn indicates frames were
|
||||
* received.
|
||||
*/
|
||||
while ((skb = __skb_dequeue(skb_list))) {
|
||||
iwl_mld_pass_packet_to_mac80211(mld, napi, skb,
|
||||
reorder_buf->queue,
|
||||
sta);
|
||||
reorder_buf->num_stored--;
|
||||
}
|
||||
}
|
||||
reorder_buf->head_sn = nssn;
|
||||
}
|
||||
|
||||
static void iwl_mld_release_frames_from_notif(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
u8 baid, u16 nssn, int queue)
|
||||
{
|
||||
struct iwl_mld_reorder_buffer *reorder_buf;
|
||||
struct iwl_mld_baid_data *ba_data;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u32 sta_id;
|
||||
|
||||
IWL_DEBUG_HT(mld, "Frame release notification for BAID %u, NSSN %d\n",
|
||||
baid, nssn);
|
||||
|
||||
if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID ||
|
||||
baid >= ARRAY_SIZE(mld->fw_id_to_ba)))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ba_data = rcu_dereference(mld->fw_id_to_ba[baid]);
|
||||
if (!ba_data) {
|
||||
IWL_DEBUG_HT(mld, "BAID %d not found in map\n", baid);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* pick any STA ID to find the pointer */
|
||||
sta_id = ffs(ba_data->sta_mask) - 1;
|
||||
link_sta = rcu_dereference(mld->fw_id_to_link_sta[sta_id]);
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(link_sta) || !link_sta->sta))
|
||||
goto out_unlock;
|
||||
|
||||
reorder_buf = &ba_data->reorder_buf[queue];
|
||||
|
||||
iwl_mld_reorder_release_frames(mld, link_sta->sta, napi, ba_data,
|
||||
reorder_buf, nssn);
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mld_handle_frame_release_notif(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_rx_packet *pkt, int queue)
|
||||
{
|
||||
struct iwl_frame_release *release = (void *)pkt->data;
|
||||
u32 pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
|
||||
if (IWL_FW_CHECK(mld, pkt_len < sizeof(*release),
|
||||
"Unexpected frame release notif size %u (expected %zu)\n",
|
||||
pkt_len, sizeof(*release)))
|
||||
return;
|
||||
|
||||
iwl_mld_release_frames_from_notif(mld, napi, release->baid,
|
||||
le16_to_cpu(release->nssn),
|
||||
queue);
|
||||
}
|
||||
|
||||
void iwl_mld_handle_bar_frame_release_notif(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_rx_packet *pkt,
|
||||
int queue)
|
||||
{
|
||||
struct iwl_bar_frame_release *release = (void *)pkt->data;
|
||||
struct iwl_mld_baid_data *baid_data;
|
||||
unsigned int baid, nssn, sta_id, tid;
|
||||
u32 pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
|
||||
if (IWL_FW_CHECK(mld, pkt_len < sizeof(*release),
|
||||
"Unexpected frame release notif size %u (expected %zu)\n",
|
||||
pkt_len, sizeof(*release)))
|
||||
return;
|
||||
|
||||
baid = le32_get_bits(release->ba_info,
|
||||
IWL_BAR_FRAME_RELEASE_BAID_MASK);
|
||||
nssn = le32_get_bits(release->ba_info,
|
||||
IWL_BAR_FRAME_RELEASE_NSSN_MASK);
|
||||
sta_id = le32_get_bits(release->sta_tid,
|
||||
IWL_BAR_FRAME_RELEASE_STA_MASK);
|
||||
tid = le32_get_bits(release->sta_tid,
|
||||
IWL_BAR_FRAME_RELEASE_TID_MASK);
|
||||
|
||||
if (IWL_FW_CHECK(mld, baid >= ARRAY_SIZE(mld->fw_id_to_ba),
|
||||
"BAR release: invalid BAID (%x)\n", baid))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
baid_data = rcu_dereference(mld->fw_id_to_ba[baid]);
|
||||
if (!IWL_FW_CHECK(mld, !baid_data,
|
||||
"Got valid BAID %d but not allocated, invalid BAR release!\n",
|
||||
baid))
|
||||
goto out_unlock;
|
||||
|
||||
if (IWL_FW_CHECK(mld, tid != baid_data->tid ||
|
||||
sta_id > mld->fw->ucode_capa.num_stations ||
|
||||
!(baid_data->sta_mask & BIT(sta_id)),
|
||||
"BAID 0x%x is mapped to sta_mask:0x%x tid:%d, but BAR release received for sta:%d tid:%d\n",
|
||||
baid, baid_data->sta_mask, baid_data->tid, sta_id,
|
||||
tid))
|
||||
goto out_unlock;
|
||||
|
||||
IWL_DEBUG_DROP(mld, "Received a BAR, expect packet loss: nssn %d\n",
|
||||
nssn);
|
||||
|
||||
iwl_mld_release_frames_from_notif(mld, napi, baid, nssn, queue);
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mld_del_ba(struct iwl_mld *mld, int queue,
|
||||
struct iwl_mld_delba_data *data)
|
||||
{
|
||||
struct iwl_mld_baid_data *ba_data;
|
||||
struct iwl_mld_reorder_buffer *reorder_buf;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 baid = data->baid;
|
||||
u32 sta_id;
|
||||
|
||||
if (WARN_ONCE(baid >= IWL_MAX_BAID, "invalid BAID: %x\n", baid))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ba_data = rcu_dereference(mld->fw_id_to_ba[baid]);
|
||||
if (WARN_ON_ONCE(!ba_data))
|
||||
goto out_unlock;
|
||||
|
||||
/* pick any STA ID to find the pointer */
|
||||
sta_id = ffs(ba_data->sta_mask) - 1;
|
||||
link_sta = rcu_dereference(mld->fw_id_to_link_sta[sta_id]);
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(link_sta) || !link_sta->sta))
|
||||
goto out_unlock;
|
||||
|
||||
reorder_buf = &ba_data->reorder_buf[queue];
|
||||
|
||||
/* release all frames that are in the reorder buffer to the stack */
|
||||
iwl_mld_reorder_release_frames(mld, link_sta->sta, NULL,
|
||||
ba_data, reorder_buf,
|
||||
ieee80211_sn_add(reorder_buf->head_sn,
|
||||
ba_data->buf_size));
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* Returns true if the MPDU was buffered\dropped, false if it should be passed
|
||||
* to upper layer.
|
||||
*/
|
||||
enum iwl_mld_reorder_result
|
||||
iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
||||
int queue, struct ieee80211_sta *sta,
|
||||
struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);
|
||||
struct iwl_mld_baid_data *baid_data;
|
||||
struct iwl_mld_reorder_buffer *buffer;
|
||||
struct iwl_mld_reorder_buf_entry *entries;
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
struct iwl_mld_link_sta *mld_link_sta;
|
||||
u32 reorder = le32_to_cpu(desc->reorder_data);
|
||||
bool amsdu, last_subframe, is_old_sn, is_dup;
|
||||
u8 tid = ieee80211_get_tid(hdr);
|
||||
u8 baid;
|
||||
u16 nssn, sn;
|
||||
u32 sta_mask = 0;
|
||||
int index;
|
||||
u8 link_id;
|
||||
|
||||
baid = u32_get_bits(reorder, IWL_RX_MPDU_REORDER_BAID_MASK);
|
||||
|
||||
/* This also covers the case of receiving a Block Ack Request
|
||||
* outside a BA session; we'll pass it to mac80211 and that
|
||||
* then sends a delBA action frame.
|
||||
* This also covers pure monitor mode, in which case we won't
|
||||
* have any BA sessions.
|
||||
*/
|
||||
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
/* no sta yet */
|
||||
if (WARN_ONCE(!sta,
|
||||
"Got valid BAID without a valid station assigned\n"))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
/* not a data packet */
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
is_multicast_ether_addr(hdr->addr1))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
baid_data = rcu_dereference(mld->fw_id_to_ba[baid]);
|
||||
if (!baid_data) {
|
||||
IWL_DEBUG_HT(mld,
|
||||
"Got valid BAID but no baid allocated, bypass re-ordering (BAID=%d reorder=0x%x)\n",
|
||||
baid, reorder);
|
||||
return IWL_MLD_PASS_SKB;
|
||||
}
|
||||
|
||||
for_each_mld_link_sta(mld_sta, mld_link_sta, link_id)
|
||||
sta_mask |= BIT(mld_link_sta->fw_id);
|
||||
|
||||
/* verify the BAID is correctly mapped to the sta and tid */
|
||||
if (IWL_FW_CHECK(mld,
|
||||
tid != baid_data->tid ||
|
||||
!(sta_mask & baid_data->sta_mask),
|
||||
"BAID 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n",
|
||||
baid, baid_data->sta_mask, baid_data->tid,
|
||||
sta_mask, tid))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
buffer = &baid_data->reorder_buf[queue];
|
||||
entries = &baid_data->entries[queue * baid_data->entries_per_queue];
|
||||
|
||||
is_old_sn = !!(reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN);
|
||||
|
||||
if (!buffer->valid && is_old_sn)
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
buffer->valid = true;
|
||||
|
||||
is_dup = !!(desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_DUPLICATE));
|
||||
|
||||
/* drop any duplicated or outdated packets */
|
||||
if (is_dup || is_old_sn)
|
||||
return IWL_MLD_DROP_SKB;
|
||||
|
||||
sn = u32_get_bits(reorder, IWL_RX_MPDU_REORDER_SN_MASK);
|
||||
nssn = u32_get_bits(reorder, IWL_RX_MPDU_REORDER_NSSN_MASK);
|
||||
amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
|
||||
last_subframe = desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
|
||||
|
||||
/* release immediately if allowed by nssn and no stored frames */
|
||||
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
|
||||
if (!amsdu || last_subframe)
|
||||
buffer->head_sn = nssn;
|
||||
return IWL_MLD_PASS_SKB;
|
||||
}
|
||||
|
||||
/* release immediately if there are no stored frames, and the sn is
|
||||
* equal to the head.
|
||||
* This can happen due to reorder timer, where NSSN is behind head_sn.
|
||||
* When we released everything, and we got the next frame in the
|
||||
* sequence, according to the NSSN we can't release immediately,
|
||||
* while technically there is no hole and we can move forward.
|
||||
*/
|
||||
if (!buffer->num_stored && sn == buffer->head_sn) {
|
||||
if (!amsdu || last_subframe)
|
||||
buffer->head_sn = ieee80211_sn_inc(buffer->head_sn);
|
||||
return IWL_MLD_PASS_SKB;
|
||||
}
|
||||
|
||||
/* put in reorder buffer */
|
||||
index = sn % baid_data->buf_size;
|
||||
__skb_queue_tail(&entries[index].frames, skb);
|
||||
buffer->num_stored++;
|
||||
|
||||
/* We cannot trust NSSN for AMSDU sub-frames that are not the last. The
|
||||
* reason is that NSSN advances on the first sub-frame, and may cause
|
||||
* the reorder buffer to advance before all the sub-frames arrive.
|
||||
*
|
||||
* Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with
|
||||
* SN 1. NSSN for first sub frame will be 3 with the result of driver
|
||||
* releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is
|
||||
* already ahead and it will be dropped.
|
||||
* If the last sub-frame is not on this queue - we will get frame
|
||||
* release notification with up to date NSSN.
|
||||
*/
|
||||
if (!amsdu || last_subframe)
|
||||
iwl_mld_reorder_release_frames(mld, sta, napi, baid_data,
|
||||
buffer, nssn);
|
||||
|
||||
return IWL_MLD_BUFFERED_SKB;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_reorder);
|
||||
|
||||
static void iwl_mld_rx_agg_session_expired(struct timer_list *t)
|
||||
{
|
||||
struct iwl_mld_baid_data *data =
|
||||
from_timer(data, t, session_timer);
|
||||
struct iwl_mld_baid_data __rcu **rcu_ptr = data->rcu_ptr;
|
||||
struct iwl_mld_baid_data *ba_data;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct iwl_mld_sta *mld_sta;
|
||||
unsigned long timeout;
|
||||
unsigned int sta_id;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ba_data = rcu_dereference(*rcu_ptr);
|
||||
if (WARN_ON(!ba_data))
|
||||
goto unlock;
|
||||
|
||||
if (WARN_ON(!ba_data->timeout))
|
||||
goto unlock;
|
||||
|
||||
timeout = ba_data->last_rx_timestamp +
|
||||
TU_TO_JIFFIES(ba_data->timeout * 2);
|
||||
if (time_is_after_jiffies(timeout)) {
|
||||
mod_timer(&ba_data->session_timer, timeout);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* timer expired, pick any STA ID to find the pointer */
|
||||
sta_id = ffs(ba_data->sta_mask) - 1;
|
||||
link_sta = rcu_dereference(ba_data->mld->fw_id_to_link_sta[sta_id]);
|
||||
|
||||
/* sta should be valid unless the following happens:
|
||||
* The firmware asserts which triggers a reconfig flow, but
|
||||
* the reconfig fails before we set the pointer to sta into
|
||||
* the fw_id_to_link_sta pointer table. mac80211 can't stop
|
||||
* A-MPDU and hence the timer continues to run. Then, the
|
||||
* timer expires and sta is NULL.
|
||||
*/
|
||||
if (IS_ERR_OR_NULL(link_sta) || WARN_ON(!link_sta->sta))
|
||||
goto unlock;
|
||||
|
||||
mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
ieee80211_rx_ba_timer_expired(mld_sta->vif, link_sta->sta->addr,
|
||||
ba_data->tid);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mld_stop_ba_in_fw(struct iwl_mld *mld, struct ieee80211_sta *sta, int tid)
|
||||
{
|
||||
struct iwl_rx_baid_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(IWL_RX_BAID_ACTION_REMOVE),
|
||||
.remove.sta_id_mask =
|
||||
cpu_to_le32(iwl_mld_fw_sta_id_mask(mld, sta)),
|
||||
.remove.tid = cpu_to_le32(tid),
|
||||
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(DATA_PATH_GROUP,
|
||||
RX_BAID_ALLOCATION_CONFIG_CMD),
|
||||
&cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
IWL_DEBUG_HT(mld, "RX BA Session stopped in fw\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mld_start_ba_in_fw(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn, u16 buf_size)
|
||||
{
|
||||
struct iwl_rx_baid_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(IWL_RX_BAID_ACTION_ADD),
|
||||
.alloc.sta_id_mask =
|
||||
cpu_to_le32(iwl_mld_fw_sta_id_mask(mld, sta)),
|
||||
.alloc.tid = tid,
|
||||
.alloc.ssn = cpu_to_le16(ssn),
|
||||
.alloc.win_size = cpu_to_le16(buf_size),
|
||||
};
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD),
|
||||
.flags = CMD_WANT_SKB,
|
||||
.len[0] = sizeof(cmd),
|
||||
.data[0] = &cmd,
|
||||
};
|
||||
struct iwl_rx_baid_cfg_resp *resp;
|
||||
struct iwl_rx_packet *pkt;
|
||||
u32 resp_len;
|
||||
int ret, baid;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*resp) != sizeof(baid));
|
||||
|
||||
ret = iwl_mld_send_cmd(mld, &hcmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pkt = hcmd.resp_pkt;
|
||||
|
||||
resp_len = iwl_rx_packet_payload_len(pkt);
|
||||
if (IWL_FW_CHECK(mld, resp_len != sizeof(*resp),
|
||||
"BAID_ALLOC_CMD: unexpected response length %d\n",
|
||||
resp_len)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
IWL_DEBUG_HT(mld, "RX BA Session started in fw\n");
|
||||
|
||||
resp = (void *)pkt->data;
|
||||
baid = le32_to_cpu(resp->baid);
|
||||
|
||||
if (IWL_FW_CHECK(mld, baid < 0 || baid >= ARRAY_SIZE(mld->fw_id_to_ba),
|
||||
"BAID_ALLOC_CMD: invalid BAID response %d\n", baid)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = baid;
|
||||
out:
|
||||
iwl_free_resp(&hcmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mld_init_reorder_buffer(struct iwl_mld *mld,
|
||||
struct iwl_mld_baid_data *data,
|
||||
u16 ssn)
|
||||
{
|
||||
for (int i = 0; i < mld->trans->num_rx_queues; i++) {
|
||||
struct iwl_mld_reorder_buffer *reorder_buf =
|
||||
&data->reorder_buf[i];
|
||||
struct iwl_mld_reorder_buf_entry *entries =
|
||||
&data->entries[i * data->entries_per_queue];
|
||||
|
||||
reorder_buf->head_sn = ssn;
|
||||
reorder_buf->queue = i;
|
||||
|
||||
for (int j = 0; j < data->buf_size; j++)
|
||||
__skb_queue_head_init(&entries[j].frames);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mld_free_reorder_buffer(struct iwl_mld *mld,
|
||||
struct iwl_mld_baid_data *data)
|
||||
{
|
||||
struct iwl_mld_delba_data delba_data = {
|
||||
.baid = data->baid,
|
||||
};
|
||||
|
||||
iwl_mld_sync_rx_queues(mld, IWL_MLD_RXQ_NOTIF_DEL_BA,
|
||||
&delba_data, sizeof(delba_data));
|
||||
|
||||
for (int i = 0; i < mld->trans->num_rx_queues; i++) {
|
||||
struct iwl_mld_reorder_buffer *reorder_buf =
|
||||
&data->reorder_buf[i];
|
||||
struct iwl_mld_reorder_buf_entry *entries =
|
||||
&data->entries[i * data->entries_per_queue];
|
||||
|
||||
if (likely(!reorder_buf->num_stored))
|
||||
continue;
|
||||
|
||||
/* This shouldn't happen in regular DELBA since the RX queues
|
||||
* sync internal DELBA notification should trigger a release
|
||||
* of all frames in the reorder buffer.
|
||||
*/
|
||||
WARN_ON(1);
|
||||
|
||||
for (int j = 0; j < data->buf_size; j++)
|
||||
__skb_queue_purge(&entries[j].frames);
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mld_ampdu_rx_start(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn, u16 buf_size, u16 timeout)
|
||||
{
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
struct iwl_mld_baid_data *baid_data = NULL;
|
||||
u32 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]);
|
||||
int ret, baid;
|
||||
u32 sta_mask;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
if (mld->num_rx_ba_sessions >= IWL_MAX_BAID) {
|
||||
IWL_DEBUG_HT(mld,
|
||||
"Max num of RX BA sessions reached; blocking new session\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
sta_mask = iwl_mld_fw_sta_id_mask(mld, sta);
|
||||
if (WARN_ON(!sta_mask))
|
||||
return -EINVAL;
|
||||
|
||||
/* sparse doesn't like the __align() so don't check */
|
||||
#ifndef __CHECKER__
|
||||
/* The division below will be OK if either the cache line size
|
||||
* can be divided by the entry size (ALIGN will round up) or if
|
||||
* the entry size can be divided by the cache line size, in which
|
||||
* case the ALIGN() will do nothing.
|
||||
*/
|
||||
BUILD_BUG_ON(SMP_CACHE_BYTES % sizeof(baid_data->entries[0]) &&
|
||||
sizeof(baid_data->entries[0]) % SMP_CACHE_BYTES);
|
||||
#endif
|
||||
|
||||
/* Upward align the reorder buffer size to fill an entire cache
|
||||
* line for each queue, to avoid sharing cache lines between
|
||||
* different queues.
|
||||
*/
|
||||
reorder_buf_size = ALIGN(reorder_buf_size, SMP_CACHE_BYTES);
|
||||
|
||||
/* Allocate here so if allocation fails we can bail out early
|
||||
* before starting the BA session in the firmware
|
||||
*/
|
||||
baid_data = kzalloc(sizeof(*baid_data) +
|
||||
mld->trans->num_rx_queues * reorder_buf_size,
|
||||
GFP_KERNEL);
|
||||
if (!baid_data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* This division is why we need the above BUILD_BUG_ON(),
|
||||
* if that doesn't hold then this will not be right.
|
||||
*/
|
||||
baid_data->entries_per_queue =
|
||||
reorder_buf_size / sizeof(baid_data->entries[0]);
|
||||
|
||||
baid = iwl_mld_start_ba_in_fw(mld, sta, tid, ssn, buf_size);
|
||||
if (baid < 0) {
|
||||
ret = baid;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mld->num_rx_ba_sessions++;
|
||||
mld_sta->tid_to_baid[tid] = baid;
|
||||
|
||||
baid_data->baid = baid;
|
||||
baid_data->mld = mld;
|
||||
baid_data->tid = tid;
|
||||
baid_data->buf_size = buf_size;
|
||||
baid_data->sta_mask = sta_mask;
|
||||
baid_data->timeout = timeout;
|
||||
baid_data->last_rx_timestamp = jiffies;
|
||||
baid_data->rcu_ptr = &mld->fw_id_to_ba[baid];
|
||||
|
||||
iwl_mld_init_reorder_buffer(mld, baid_data, ssn);
|
||||
|
||||
timer_setup(&baid_data->session_timer, iwl_mld_rx_agg_session_expired,
|
||||
0);
|
||||
if (timeout)
|
||||
mod_timer(&baid_data->session_timer,
|
||||
TU_TO_EXP_TIME(timeout * 2));
|
||||
|
||||
IWL_DEBUG_HT(mld, "STA mask=0x%x (tid=%d) is assigned to BAID %d\n",
|
||||
baid_data->sta_mask, tid, baid);
|
||||
|
||||
/* protect the BA data with RCU to cover a case where our
|
||||
* internal RX sync mechanism will timeout (not that it's
|
||||
* supposed to happen) and we will free the session data while
|
||||
* RX is being processed in parallel
|
||||
*/
|
||||
WARN_ON(rcu_access_pointer(mld->fw_id_to_ba[baid]));
|
||||
rcu_assign_pointer(mld->fw_id_to_ba[baid], baid_data);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
kfree(baid_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mld_ampdu_rx_stop(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
int tid)
|
||||
{
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
int baid = mld_sta->tid_to_baid[tid];
|
||||
struct iwl_mld_baid_data *baid_data;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
/* during firmware restart, do not send the command as the firmware no
|
||||
* longer recognizes the session. instead, only clear the driver BA
|
||||
* session data.
|
||||
*/
|
||||
if (!mld->fw_status.in_hw_restart) {
|
||||
ret = iwl_mld_stop_ba_in_fw(mld, sta, tid);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!WARN_ON(mld->num_rx_ba_sessions == 0))
|
||||
mld->num_rx_ba_sessions--;
|
||||
|
||||
baid_data = wiphy_dereference(mld->wiphy, mld->fw_id_to_ba[baid]);
|
||||
if (WARN_ON(!baid_data))
|
||||
return -EINVAL;
|
||||
|
||||
if (timer_pending(&baid_data->session_timer))
|
||||
timer_shutdown_sync(&baid_data->session_timer);
|
||||
|
||||
iwl_mld_free_reorder_buffer(mld, baid_data);
|
||||
|
||||
RCU_INIT_POINTER(mld->fw_id_to_ba[baid], NULL);
|
||||
kfree_rcu(baid_data, rcu_head);
|
||||
|
||||
IWL_DEBUG_HT(mld, "BAID %d is free\n", baid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mld_update_sta_baids(struct iwl_mld *mld,
|
||||
u32 old_sta_mask,
|
||||
u32 new_sta_mask)
|
||||
{
|
||||
struct iwl_rx_baid_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(IWL_RX_BAID_ACTION_MODIFY),
|
||||
.modify.old_sta_id_mask = cpu_to_le32(old_sta_mask),
|
||||
.modify.new_sta_id_mask = cpu_to_le32(new_sta_mask),
|
||||
};
|
||||
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD);
|
||||
int baid;
|
||||
|
||||
/* mac80211 will remove sessions later, but we ignore all that */
|
||||
if (mld->fw_status.in_hw_restart)
|
||||
return 0;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid));
|
||||
|
||||
for (baid = 0; baid < ARRAY_SIZE(mld->fw_id_to_ba); baid++) {
|
||||
struct iwl_mld_baid_data *data;
|
||||
int ret;
|
||||
|
||||
data = wiphy_dereference(mld->wiphy, mld->fw_id_to_ba[baid]);
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
if (!(data->sta_mask & old_sta_mask))
|
||||
continue;
|
||||
|
||||
WARN_ONCE(data->sta_mask != old_sta_mask,
|
||||
"BAID data for %d corrupted - expected 0x%x found 0x%x\n",
|
||||
baid, old_sta_mask, data->sta_mask);
|
||||
|
||||
cmd.modify.tid = cpu_to_le32(data->tid);
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->sta_mask = new_sta_mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
127
drivers/net/wireless/intel/iwlwifi/mld/agg.h
Normal file
127
drivers/net/wireless/intel/iwlwifi/mld/agg.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_agg_h__
|
||||
#define __iwl_agg_h__
|
||||
|
||||
#include "mld.h"
|
||||
#include "fw/api/rx.h"
|
||||
|
||||
/**
|
||||
* struct iwl_mld_reorder_buffer - per ra/tid/queue reorder buffer
|
||||
* @head_sn: reorder window head sequence number
|
||||
* @num_stored: number of MPDUs stored in the buffer
|
||||
* @queue: queue of this reorder buffer
|
||||
* @valid: true if reordering is valid for this queue
|
||||
*/
|
||||
struct iwl_mld_reorder_buffer {
|
||||
u16 head_sn;
|
||||
u16 num_stored;
|
||||
int queue;
|
||||
bool valid;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
/**
|
||||
* struct iwl_mld_reorder_buf_entry - reorder buffer entry per-queue/per-seqno
|
||||
* @frames: list of skbs stored. a list is necessary because in an A-MSDU,
|
||||
* all sub-frames share the same sequence number, so they are stored
|
||||
* together in the same list.
|
||||
*/
|
||||
struct iwl_mld_reorder_buf_entry {
|
||||
struct sk_buff_head frames;
|
||||
}
|
||||
#ifndef __CHECKER__
|
||||
/* sparse doesn't like this construct: "bad integer constant expression" */
|
||||
__aligned(roundup_pow_of_two(sizeof(struct sk_buff_head)))
|
||||
#endif
|
||||
;
|
||||
|
||||
/**
|
||||
* struct iwl_mld_baid_data - Block Ack session data
|
||||
* @rcu_head: RCU head for freeing this data
|
||||
* @sta_mask: station mask for the BAID
|
||||
* @tid: tid of the session
|
||||
* @baid: baid of the session
|
||||
* @buf_size: the reorder buffer size as set by the last ADDBA request
|
||||
* @entries_per_queue: number of buffers per queue, this actually gets
|
||||
* aligned up to avoid cache line sharing between queues
|
||||
* @timeout: the timeout value specified in the ADDBA request.
|
||||
* @last_rx_timestamp: timestamp of the last received packet (in jiffies). This
|
||||
* value is updated only when the configured @timeout has passed since
|
||||
* the last update to minimize cache bouncing between RX queues.
|
||||
* @session_timer: timer is set to expire after 2 * @timeout (since we want
|
||||
* to minimize the cache bouncing by updating @last_rx_timestamp only once
|
||||
* after @timeout has passed). If no packets are received within this
|
||||
* period, it informs mac80211 to initiate delBA flow, terminating the
|
||||
* BA session.
|
||||
* @rcu_ptr: BA data RCU protected access
|
||||
* @mld: mld pointer, needed for timer context
|
||||
* @reorder_buf: reorder buffer, allocated per queue
|
||||
* @entries: data
|
||||
*/
|
||||
struct iwl_mld_baid_data {
|
||||
struct rcu_head rcu_head;
|
||||
u32 sta_mask;
|
||||
u8 tid;
|
||||
u8 baid;
|
||||
u16 buf_size;
|
||||
u16 entries_per_queue;
|
||||
u16 timeout;
|
||||
struct timer_list session_timer;
|
||||
unsigned long last_rx_timestamp;
|
||||
struct iwl_mld_baid_data __rcu **rcu_ptr;
|
||||
struct iwl_mld *mld;
|
||||
struct iwl_mld_reorder_buffer reorder_buf[IWL_MAX_RX_HW_QUEUES];
|
||||
struct iwl_mld_reorder_buf_entry entries[] ____cacheline_aligned_in_smp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mld_delba_data - RX queue sync data for %IWL_MLD_RXQ_NOTIF_DEL_BA
|
||||
*
|
||||
* @baid: Block Ack id, used to identify the BA session to be removed
|
||||
*/
|
||||
struct iwl_mld_delba_data {
|
||||
u32 baid;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum iwl_mld_reorder_result - Possible return values for iwl_mld_reorder()
|
||||
* indicating how the caller should handle the skb based on the result.
|
||||
*
|
||||
* @IWL_MLD_PASS_SKB: skb should be passed to upper layer.
|
||||
* @IWL_MLD_BUFFERED_SKB: skb has been buffered, don't pass it to upper layer.
|
||||
* @IWL_MLD_DROP_SKB: skb should be dropped and freed by the caller.
|
||||
*/
|
||||
enum iwl_mld_reorder_result {
|
||||
IWL_MLD_PASS_SKB,
|
||||
IWL_MLD_BUFFERED_SKB,
|
||||
IWL_MLD_DROP_SKB
|
||||
};
|
||||
|
||||
int iwl_mld_ampdu_rx_start(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn, u16 buf_size, u16 timeout);
|
||||
int iwl_mld_ampdu_rx_stop(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
int tid);
|
||||
|
||||
enum iwl_mld_reorder_result
|
||||
iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
||||
int queue, struct ieee80211_sta *sta,
|
||||
struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc);
|
||||
|
||||
void iwl_mld_handle_frame_release_notif(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_rx_packet *pkt, int queue);
|
||||
void iwl_mld_handle_bar_frame_release_notif(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_rx_packet *pkt,
|
||||
int queue);
|
||||
|
||||
void iwl_mld_del_ba(struct iwl_mld *mld, int queue,
|
||||
struct iwl_mld_delba_data *data);
|
||||
|
||||
int iwl_mld_update_sta_baids(struct iwl_mld *mld,
|
||||
u32 old_sta_mask,
|
||||
u32 new_sta_mask);
|
||||
|
||||
#endif /* __iwl_agg_h__ */
|
||||
344
drivers/net/wireless/intel/iwlwifi/mld/ap.c
Normal file
344
drivers/net/wireless/intel/iwlwifi/mld/ap.c
Normal file
@@ -0,0 +1,344 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*/
|
||||
#include <linux/crc32.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "ap.h"
|
||||
#include "hcmd.h"
|
||||
#include "tx.h"
|
||||
#include "power.h"
|
||||
#include "key.h"
|
||||
#include "iwl-utils.h"
|
||||
|
||||
#include "fw/api/sta.h"
|
||||
|
||||
void iwl_mld_set_tim_idx(struct iwl_mld *mld, __le32 *tim_index,
|
||||
u8 *beacon, u32 frame_size)
|
||||
{
|
||||
u32 tim_idx;
|
||||
struct ieee80211_mgmt *mgmt = (void *)beacon;
|
||||
|
||||
/* The index is relative to frame start but we start looking at the
|
||||
* variable-length part of the beacon.
|
||||
*/
|
||||
tim_idx = mgmt->u.beacon.variable - beacon;
|
||||
|
||||
/* Parse variable-length elements of beacon to find WLAN_EID_TIM */
|
||||
while ((tim_idx < (frame_size - 2)) &&
|
||||
(beacon[tim_idx] != WLAN_EID_TIM))
|
||||
tim_idx += beacon[tim_idx + 1] + 2;
|
||||
|
||||
/* If TIM field was found, set variables */
|
||||
if ((tim_idx < (frame_size - 1)) && beacon[tim_idx] == WLAN_EID_TIM)
|
||||
*tim_index = cpu_to_le32(tim_idx);
|
||||
else
|
||||
IWL_WARN(mld, "Unable to find TIM Element in beacon\n");
|
||||
}
|
||||
|
||||
u8 iwl_mld_get_rate_flags(struct iwl_mld *mld,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
u32 legacy = link->beacon_tx_rate.control[band].legacy;
|
||||
u32 rate_idx, rate_flags = 0, fw_rate;
|
||||
|
||||
/* if beacon rate was configured try using it */
|
||||
if (hweight32(legacy) == 1) {
|
||||
u32 rate = ffs(legacy) - 1;
|
||||
struct ieee80211_supported_band *sband =
|
||||
mld->hw->wiphy->bands[band];
|
||||
|
||||
rate_idx = sband->bitrates[rate].hw_value;
|
||||
} else {
|
||||
rate_idx = iwl_mld_get_lowest_rate(mld, info, vif);
|
||||
}
|
||||
|
||||
if (rate_idx <= IWL_LAST_CCK_RATE)
|
||||
rate_flags = IWL_MAC_BEACON_CCK;
|
||||
|
||||
/* Legacy rates are indexed as follows:
|
||||
* 0 - 3 for CCK and 0 - 7 for OFDM.
|
||||
*/
|
||||
fw_rate = (rate_idx >= IWL_FIRST_OFDM_RATE ?
|
||||
rate_idx - IWL_FIRST_OFDM_RATE : rate_idx);
|
||||
|
||||
return fw_rate | rate_flags;
|
||||
}
|
||||
|
||||
int iwl_mld_send_beacon_template_cmd(struct iwl_mld *mld,
|
||||
struct sk_buff *beacon,
|
||||
struct iwl_mac_beacon_cmd *cmd)
|
||||
{
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = BEACON_TEMPLATE_CMD,
|
||||
};
|
||||
|
||||
hcmd.len[0] = sizeof(*cmd);
|
||||
hcmd.data[0] = cmd;
|
||||
|
||||
hcmd.len[1] = beacon->len;
|
||||
hcmd.data[1] = beacon->data;
|
||||
hcmd.dataflags[1] = IWL_HCMD_DFL_DUP;
|
||||
|
||||
return iwl_mld_send_cmd(mld, &hcmd);
|
||||
}
|
||||
|
||||
static int iwl_mld_fill_beacon_template_cmd(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct sk_buff *beacon,
|
||||
struct iwl_mac_beacon_cmd *cmd,
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(beacon);
|
||||
struct ieee80211_chanctx_conf *ctx;
|
||||
bool enable_fils;
|
||||
u16 flags = 0;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
if (WARN_ON(!mld_link))
|
||||
return -EINVAL;
|
||||
|
||||
cmd->link_id = cpu_to_le32(mld_link->fw_id);
|
||||
|
||||
ctx = wiphy_dereference(mld->wiphy, link->chanctx_conf);
|
||||
if (WARN_ON(!ctx || !ctx->def.chan))
|
||||
return -EINVAL;
|
||||
|
||||
enable_fils = cfg80211_channel_is_psc(ctx->def.chan) ||
|
||||
(ctx->def.chan->band == NL80211_BAND_6GHZ &&
|
||||
ctx->def.width >= NL80211_CHAN_WIDTH_80);
|
||||
|
||||
if (enable_fils) {
|
||||
flags |= IWL_MAC_BEACON_FILS;
|
||||
cmd->short_ssid = cpu_to_le32(~crc32_le(~0, vif->cfg.ssid,
|
||||
vif->cfg.ssid_len));
|
||||
}
|
||||
|
||||
cmd->byte_cnt = cpu_to_le16((u16)beacon->len);
|
||||
|
||||
flags |= iwl_mld_get_rate_flags(mld, info, vif, link,
|
||||
ctx->def.chan->band);
|
||||
|
||||
cmd->flags = cpu_to_le16(flags);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
iwl_mld_set_tim_idx(mld, &cmd->tim_idx,
|
||||
beacon->data, beacon->len);
|
||||
|
||||
cmd->btwt_offset =
|
||||
cpu_to_le32(iwl_find_ie_offset(beacon->data,
|
||||
WLAN_EID_S1G_TWT,
|
||||
beacon->len));
|
||||
}
|
||||
|
||||
cmd->csa_offset =
|
||||
cpu_to_le32(iwl_find_ie_offset(beacon->data,
|
||||
WLAN_EID_CHANNEL_SWITCH,
|
||||
beacon->len));
|
||||
cmd->ecsa_offset =
|
||||
cpu_to_le32(iwl_find_ie_offset(beacon->data,
|
||||
WLAN_EID_EXT_CHANSWITCH_ANN,
|
||||
beacon->len));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The beacon template for the AP/GO/IBSS has changed and needs update */
|
||||
int iwl_mld_update_beacon_template(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf)
|
||||
{
|
||||
struct iwl_mac_beacon_cmd cmd = {};
|
||||
struct sk_buff *beacon;
|
||||
int ret;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
#endif
|
||||
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_AP &&
|
||||
vif->type != NL80211_IFTYPE_ADHOC);
|
||||
|
||||
if (IWL_MLD_NON_TRANSMITTING_AP)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (mld_vif->beacon_inject_active) {
|
||||
IWL_DEBUG_INFO(mld,
|
||||
"Can't update template, beacon injection's active\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
#endif
|
||||
beacon = ieee80211_beacon_get_template(mld->hw, vif, NULL,
|
||||
link_conf->link_id);
|
||||
if (!beacon)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = iwl_mld_fill_beacon_template_cmd(mld, vif, beacon, &cmd,
|
||||
link_conf);
|
||||
|
||||
if (!ret)
|
||||
ret = iwl_mld_send_beacon_template_cmd(mld, beacon, &cmd);
|
||||
|
||||
dev_kfree_skb(beacon);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_mld_free_ap_early_key(struct iwl_mld *mld,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct iwl_mld_vif *mld_vif)
|
||||
{
|
||||
struct iwl_mld_link *link;
|
||||
|
||||
if (WARN_ON(key->link_id < 0))
|
||||
return;
|
||||
|
||||
link = iwl_mld_link_dereference_check(mld_vif, key->link_id);
|
||||
if (WARN_ON(!link))
|
||||
return;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(link->ap_early_keys); i++) {
|
||||
if (link->ap_early_keys[i] != key)
|
||||
continue;
|
||||
/* Those weren't sent to FW, so should be marked as INVALID */
|
||||
if (WARN_ON(key->hw_key_idx != STA_KEY_IDX_INVALID))
|
||||
key->hw_key_idx = STA_KEY_IDX_INVALID;
|
||||
link->ap_early_keys[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mld_store_ap_early_key(struct iwl_mld *mld,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct iwl_mld_vif *mld_vif)
|
||||
{
|
||||
struct iwl_mld_link *link;
|
||||
|
||||
if (WARN_ON(key->link_id < 0))
|
||||
return -EINVAL;
|
||||
|
||||
link = iwl_mld_link_dereference_check(mld_vif, key->link_id);
|
||||
if (WARN_ON(!link))
|
||||
return -EINVAL;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(link->ap_early_keys); i++) {
|
||||
if (!link->ap_early_keys[i]) {
|
||||
link->ap_early_keys[i] = key;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static int iwl_mld_send_ap_early_keys(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(!link))
|
||||
return -EINVAL;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(mld_link->ap_early_keys); i++) {
|
||||
struct ieee80211_key_conf *key = mld_link->ap_early_keys[i];
|
||||
|
||||
if (!key)
|
||||
continue;
|
||||
|
||||
mld_link->ap_early_keys[i] = NULL;
|
||||
|
||||
ret = iwl_mld_add_key(mld, vif, NULL, key);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
iwl_mld_send_ap_tx_power_constraint_cmd(mld, vif, link);
|
||||
|
||||
ret = iwl_mld_update_beacon_template(mld, vif, link);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* the link should be already activated when assigning chan context,
|
||||
* and LINK_CONTEXT_MODIFY_EHT_PARAMS is deprecated
|
||||
*/
|
||||
ret = iwl_mld_change_link_in_fw(mld, link,
|
||||
LINK_CONTEXT_MODIFY_ALL &
|
||||
~(LINK_CONTEXT_MODIFY_ACTIVE |
|
||||
LINK_CONTEXT_MODIFY_EHT_PARAMS));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iwl_mld_add_mcast_sta(mld, vif, link);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iwl_mld_add_bcast_sta(mld, vif, link);
|
||||
if (ret)
|
||||
goto rm_mcast;
|
||||
|
||||
/* Those keys were configured by the upper layers before starting the
|
||||
* AP. Now that it is started and the bcast and mcast sta were added to
|
||||
* the FW, we can add the keys too.
|
||||
*/
|
||||
ret = iwl_mld_send_ap_early_keys(mld, vif, link);
|
||||
if (ret)
|
||||
goto rm_bcast;
|
||||
|
||||
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP)
|
||||
iwl_mld_vif_update_low_latency(mld, vif, true,
|
||||
LOW_LATENCY_VIF_TYPE);
|
||||
|
||||
mld_vif->ap_ibss_active = true;
|
||||
|
||||
if (vif->p2p && mld->p2p_device_vif)
|
||||
return iwl_mld_mac_fw_action(mld, mld->p2p_device_vif,
|
||||
FW_CTXT_ACTION_MODIFY);
|
||||
|
||||
return 0;
|
||||
rm_bcast:
|
||||
iwl_mld_remove_bcast_sta(mld, vif, link);
|
||||
rm_mcast:
|
||||
iwl_mld_remove_mcast_sta(mld, vif, link);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_mld_stop_ap_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
|
||||
mld_vif->ap_ibss_active = false;
|
||||
|
||||
if (vif->p2p && mld->p2p_device_vif)
|
||||
iwl_mld_mac_fw_action(mld, mld->p2p_device_vif,
|
||||
FW_CTXT_ACTION_MODIFY);
|
||||
|
||||
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP)
|
||||
iwl_mld_vif_update_low_latency(mld, vif, false,
|
||||
LOW_LATENCY_VIF_TYPE);
|
||||
|
||||
iwl_mld_remove_bcast_sta(mld, vif, link);
|
||||
|
||||
iwl_mld_remove_mcast_sta(mld, vif, link);
|
||||
}
|
||||
45
drivers/net/wireless/intel/iwlwifi/mld/ap.h
Normal file
45
drivers/net/wireless/intel/iwlwifi/mld/ap.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_ap_h__
|
||||
#define __iwl_ap_h__
|
||||
|
||||
#include "mld.h"
|
||||
#include "iface.h"
|
||||
|
||||
#include "fw/api/tx.h"
|
||||
|
||||
int iwl_mld_update_beacon_template(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf);
|
||||
|
||||
int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link);
|
||||
|
||||
void iwl_mld_stop_ap_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link);
|
||||
|
||||
int iwl_mld_store_ap_early_key(struct iwl_mld *mld,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct iwl_mld_vif *mld_vif);
|
||||
|
||||
void iwl_mld_free_ap_early_key(struct iwl_mld *mld,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct iwl_mld_vif *mld_vif);
|
||||
|
||||
u8 iwl_mld_get_rate_flags(struct iwl_mld *mld,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link,
|
||||
enum nl80211_band band);
|
||||
|
||||
void iwl_mld_set_tim_idx(struct iwl_mld *mld, __le32 *tim_index,
|
||||
u8 *beacon, u32 frame_size);
|
||||
|
||||
int iwl_mld_send_beacon_template_cmd(struct iwl_mld *mld,
|
||||
struct sk_buff *beacon,
|
||||
struct iwl_mac_beacon_cmd *cmd);
|
||||
|
||||
#endif /* __iwl_ap_h__ */
|
||||
40
drivers/net/wireless/intel/iwlwifi/mld/coex.c
Normal file
40
drivers/net/wireless/intel/iwlwifi/mld/coex.c
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "fw/api/coex.h"
|
||||
|
||||
#include "coex.h"
|
||||
#include "mld.h"
|
||||
#include "hcmd.h"
|
||||
#include "mlo.h"
|
||||
|
||||
int iwl_mld_send_bt_init_conf(struct iwl_mld *mld)
|
||||
{
|
||||
struct iwl_bt_coex_cmd cmd = {
|
||||
.mode = cpu_to_le32(BT_COEX_NW),
|
||||
.enabled_modules = cpu_to_le32(BT_COEX_MPLUT_ENABLED |
|
||||
BT_COEX_HIGH_BAND_RET),
|
||||
};
|
||||
|
||||
return iwl_mld_send_cmd_pdu(mld, BT_CONFIG, &cmd);
|
||||
}
|
||||
|
||||
void iwl_mld_handle_bt_coex_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
const struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
|
||||
const struct iwl_bt_coex_profile_notif zero_notif = {};
|
||||
/* zeroed structure means that BT is OFF */
|
||||
bool bt_is_active = memcmp(notif, &zero_notif, sizeof(*notif));
|
||||
|
||||
if (bt_is_active == mld->bt_is_active)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_INFO(mld, "BT was turned %s\n", bt_is_active ? "ON" : "OFF");
|
||||
|
||||
mld->bt_is_active = bt_is_active;
|
||||
|
||||
iwl_mld_emlsr_check_bt(mld);
|
||||
}
|
||||
15
drivers/net/wireless/intel/iwlwifi/mld/coex.h
Normal file
15
drivers/net/wireless/intel/iwlwifi/mld/coex.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_coex_h__
|
||||
#define __iwl_mld_coex_h__
|
||||
|
||||
#include "mld.h"
|
||||
|
||||
int iwl_mld_send_bt_init_conf(struct iwl_mld *mld);
|
||||
|
||||
void iwl_mld_handle_bt_coex_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
#endif /* __iwl_mld_coex_h__ */
|
||||
88
drivers/net/wireless/intel/iwlwifi/mld/constants.h
Normal file
88
drivers/net/wireless/intel/iwlwifi/mld/constants.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_constants_h__
|
||||
#define __iwl_mld_constants_h__
|
||||
|
||||
#define IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD 4
|
||||
#define IWL_MLD_MISSED_BEACONS_THRESHOLD 8
|
||||
#define IWL_MLD_MISSED_BEACONS_THRESHOLD_LONG 19
|
||||
#define IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5
|
||||
#define IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH 15
|
||||
#define IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED 11
|
||||
#define IWL_MLD_LOW_RSSI_MLO_SCAN_THRESH -72
|
||||
|
||||
#define IWL_MLD_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
|
||||
#define IWL_MLD_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
|
||||
#define IWL_MLD_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
|
||||
#define IWL_MLD_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
|
||||
#define IWL_MLD_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */
|
||||
#define IWL_MLD_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */
|
||||
|
||||
#define IWL_MLD_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
|
||||
#define IWL_MLD_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
|
||||
|
||||
#define IWL_MLD_PS_SNOOZE_INTERVAL 25
|
||||
#define IWL_MLD_PS_SNOOZE_INTERVAL 25
|
||||
#define IWL_MLD_PS_SNOOZE_WINDOW 50
|
||||
|
||||
#define IWL_MLD_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30
|
||||
#define IWL_MLD_PS_SNOOZE_HEAVY_RX_THLD_PACKETS 20
|
||||
|
||||
#define IWL_MLD_PS_HEAVY_TX_THLD_PERCENT 50
|
||||
#define IWL_MLD_PS_HEAVY_RX_THLD_PERCENT 50
|
||||
#define IWL_MLD_PS_HEAVY_TX_THLD_PACKETS 20
|
||||
#define IWL_MLD_PS_HEAVY_RX_THLD_PACKETS 8
|
||||
|
||||
#define IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC 30
|
||||
#define IWL_MLD_SCAN_EXPIRE_TIME_SEC 20
|
||||
|
||||
#define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ)
|
||||
|
||||
/* OMI reduced BW thresholds (channel load percentage) */
|
||||
#define IWL_MLD_OMI_ENTER_CHAN_LOAD 10
|
||||
#define IWL_MLD_OMI_EXIT_CHAN_LOAD_160 20
|
||||
#define IWL_MLD_OMI_EXIT_CHAN_LOAD_320 30
|
||||
/* time (in milliseconds) to let AP "settle" the OMI */
|
||||
#define IWL_MLD_OMI_AP_SETTLE_DELAY 27
|
||||
/* time (in milliseconds) to not enter OMI reduced BW after leaving */
|
||||
#define IWL_MLD_OMI_EXIT_PROTECTION 5000
|
||||
|
||||
#define IWL_MLD_DIS_RANDOM_FW_ID false
|
||||
#define IWL_MLD_D3_DEBUG false
|
||||
#define IWL_MLD_NON_TRANSMITTING_AP false
|
||||
#define IWL_MLD_6GHZ_PASSIVE_SCAN_TIMEOUT 3000 /* in seconds */
|
||||
#define IWL_MLD_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT 60 /* in seconds */
|
||||
#define IWL_MLD_CONN_LISTEN_INTERVAL 10
|
||||
#define IWL_MLD_ADAPTIVE_DWELL_NUM_APS_OVERRIDE 0
|
||||
#define IWL_MLD_AUTO_EML_ENABLE true
|
||||
|
||||
#define IWL_MLD_HIGH_RSSI_THRESH_20MHZ -67
|
||||
#define IWL_MLD_LOW_RSSI_THRESH_20MHZ -72
|
||||
#define IWL_MLD_HIGH_RSSI_THRESH_40MHZ -64
|
||||
#define IWL_MLD_LOW_RSSI_THRESH_40MHZ -72
|
||||
#define IWL_MLD_HIGH_RSSI_THRESH_80MHZ -61
|
||||
#define IWL_MLD_LOW_RSSI_THRESH_80MHZ -72
|
||||
#define IWL_MLD_HIGH_RSSI_THRESH_160MHZ -58
|
||||
#define IWL_MLD_LOW_RSSI_THRESH_160MHZ -72
|
||||
|
||||
#define IWL_MLD_ENTER_EMLSR_TPT_THRESH 400
|
||||
#define IWL_MLD_EXIT_EMLSR_CHAN_LOAD 2 /* in percentage */
|
||||
|
||||
#define IWL_MLD_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE
|
||||
#define IWL_MLD_FTM_INITIATOR_DYNACK true
|
||||
#define IWL_MLD_FTM_LMR_FEEDBACK_TERMINATE false
|
||||
#define IWL_MLD_FTM_TEST_INCORRECT_SAC false
|
||||
#define IWL_MLD_FTM_R2I_MAX_REP 7
|
||||
#define IWL_MLD_FTM_I2R_MAX_REP 7
|
||||
#define IWL_MLD_FTM_R2I_MAX_STS 1
|
||||
#define IWL_MLD_FTM_I2R_MAX_STS 1
|
||||
#define IWL_MLD_FTM_R2I_MAX_TOTAL_LTF 3
|
||||
#define IWL_MLD_FTM_I2R_MAX_TOTAL_LTF 3
|
||||
#define IWL_MLD_FTM_RESP_NDP_SUPPORT true
|
||||
#define IWL_MLD_FTM_RESP_LMR_FEEDBACK_SUPPORT true
|
||||
#define IWL_MLD_FTM_NON_TB_MIN_TIME_BETWEEN_MSR 7
|
||||
#define IWL_MLD_FTM_NON_TB_MAX_TIME_BETWEEN_MSR 1000
|
||||
|
||||
#endif /* __iwl_mld_constants_h__ */
|
||||
1998
drivers/net/wireless/intel/iwlwifi/mld/d3.c
Normal file
1998
drivers/net/wireless/intel/iwlwifi/mld/d3.c
Normal file
File diff suppressed because it is too large
Load Diff
51
drivers/net/wireless/intel/iwlwifi/mld/d3.h
Normal file
51
drivers/net/wireless/intel/iwlwifi/mld/d3.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_d3_h__
|
||||
#define __iwl_mld_d3_h__
|
||||
|
||||
#include "fw/api/d3.h"
|
||||
|
||||
struct iwl_mld_rekey_data {
|
||||
bool valid;
|
||||
u8 kck[NL80211_KCK_EXT_LEN];
|
||||
u8 kek[NL80211_KEK_EXT_LEN];
|
||||
size_t kck_len;
|
||||
size_t kek_len;
|
||||
__le64 replay_ctr;
|
||||
u32 akm;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mld_wowlan_data - data used by the wowlan suspend flow
|
||||
*
|
||||
* @target_ipv6_addrs: IPv6 addresses on this interface for offload
|
||||
* @tentative_addrs: bitmap of tentative IPv6 addresses in @target_ipv6_addrs
|
||||
* @num_target_ipv6_addrs: number of @target_ipv6_addrs
|
||||
* @rekey_data: security key data used for rekeying during D3
|
||||
*/
|
||||
struct iwl_mld_wowlan_data {
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX];
|
||||
unsigned long tentative_addrs[BITS_TO_LONGS(IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX)];
|
||||
int num_target_ipv6_addrs;
|
||||
#endif
|
||||
struct iwl_mld_rekey_data rekey_data;
|
||||
};
|
||||
|
||||
int iwl_mld_no_wowlan_resume(struct iwl_mld *mld);
|
||||
int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld);
|
||||
int iwl_mld_wowlan_suspend(struct iwl_mld *mld,
|
||||
struct cfg80211_wowlan *wowlan);
|
||||
int iwl_mld_wowlan_resume(struct iwl_mld *mld);
|
||||
void iwl_mld_set_rekey_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *data);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
void iwl_mld_ipv6_addr_change(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct inet6_dev *idev);
|
||||
#endif
|
||||
|
||||
#endif /* __iwl_mld_d3_h__ */
|
||||
1082
drivers/net/wireless/intel/iwlwifi/mld/debugfs.c
Normal file
1082
drivers/net/wireless/intel/iwlwifi/mld/debugfs.c
Normal file
File diff suppressed because it is too large
Load Diff
244
drivers/net/wireless/intel/iwlwifi/mld/debugfs.h
Normal file
244
drivers/net/wireless/intel/iwlwifi/mld/debugfs.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#include "iface.h"
|
||||
#include "sta.h"
|
||||
|
||||
#define MLD_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \
|
||||
struct dbgfs_##name##_data { \
|
||||
argtype *arg; \
|
||||
bool read_done; \
|
||||
ssize_t rlen; \
|
||||
char buf[buflen]; \
|
||||
}; \
|
||||
static int _iwl_dbgfs_##name##_open(struct inode *inode, \
|
||||
struct file *file) \
|
||||
{ \
|
||||
struct dbgfs_##name##_data *data; \
|
||||
\
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDWR) \
|
||||
return -EOPNOTSUPP; \
|
||||
\
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL); \
|
||||
if (!data) \
|
||||
return -ENOMEM; \
|
||||
\
|
||||
data->read_done = false; \
|
||||
data->arg = inode->i_private; \
|
||||
file->private_data = data; \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define MLD_DEBUGFS_READ_WRAPPER(name) \
|
||||
static ssize_t _iwl_dbgfs_##name##_read(struct file *file, \
|
||||
char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct dbgfs_##name##_data *data = file->private_data; \
|
||||
\
|
||||
if (!data->read_done) { \
|
||||
data->read_done = true; \
|
||||
data->rlen = iwl_dbgfs_##name##_read(data->arg, \
|
||||
sizeof(data->buf),\
|
||||
data->buf); \
|
||||
} \
|
||||
\
|
||||
if (data->rlen < 0) \
|
||||
return data->rlen; \
|
||||
return simple_read_from_buffer(user_buf, count, ppos, \
|
||||
data->buf, data->rlen); \
|
||||
}
|
||||
|
||||
static int _iwl_dbgfs_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
kfree(file->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define _MLD_DEBUGFS_READ_FILE_OPS(name, buflen, argtype) \
|
||||
MLD_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \
|
||||
MLD_DEBUGFS_READ_WRAPPER(name) \
|
||||
static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
||||
.read = _iwl_dbgfs_##name##_read, \
|
||||
.open = _iwl_dbgfs_##name##_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
.release = _iwl_dbgfs_release, \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \
|
||||
static ssize_t iwl_dbgfs_##name##_write_handler(struct wiphy *wiphy, \
|
||||
struct file *file, char *buf, \
|
||||
size_t count, void *data) \
|
||||
{ \
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \
|
||||
return iwl_dbgfs_##name##_write(mld, buf, count, data); \
|
||||
}
|
||||
|
||||
static inline struct iwl_mld *
|
||||
iwl_mld_from_link_sta(struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
struct ieee80211_vif *vif =
|
||||
iwl_mld_sta_from_mac80211(link_sta->sta)->vif;
|
||||
return iwl_mld_vif_from_mac80211(vif)->mld;
|
||||
}
|
||||
|
||||
static inline struct iwl_mld *
|
||||
iwl_mld_from_bss_conf(struct ieee80211_bss_conf *link)
|
||||
{
|
||||
return iwl_mld_vif_from_mac80211(link->vif)->mld;
|
||||
}
|
||||
|
||||
static inline struct iwl_mld *iwl_mld_from_vif(struct ieee80211_vif *vif)
|
||||
{
|
||||
return iwl_mld_vif_from_mac80211(vif)->mld;
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_WRAPPER(name, bufsz, objtype) \
|
||||
WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \
|
||||
static ssize_t __iwl_dbgfs_##name##_write(struct file *file, \
|
||||
const char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct ieee80211_##objtype *arg = file->private_data; \
|
||||
struct iwl_mld *mld = iwl_mld_from_##objtype(arg); \
|
||||
char buf[bufsz] = {}; \
|
||||
\
|
||||
return wiphy_locked_debugfs_write(mld->wiphy, file, \
|
||||
buf, sizeof(buf), \
|
||||
user_buf, count, \
|
||||
iwl_dbgfs_##name##_write_handler, \
|
||||
arg); \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_FILE_OPS(name, bufsz, objtype) \
|
||||
WIPHY_DEBUGFS_WRITE_WRAPPER(name, bufsz, objtype) \
|
||||
static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
||||
.write = __iwl_dbgfs_##name##_write, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_READ_HANDLER_WRAPPER_MLD(name) \
|
||||
static ssize_t iwl_dbgfs_##name##_read_handler(struct wiphy *wiphy, \
|
||||
struct file *file, char *buf, \
|
||||
size_t count, void *data) \
|
||||
{ \
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \
|
||||
return iwl_dbgfs_##name##_read(mld, buf, count); \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER_MLD(name) \
|
||||
static ssize_t iwl_dbgfs_##name##_write_handler(struct wiphy *wiphy, \
|
||||
struct file *file, char *buf, \
|
||||
size_t count, void *data) \
|
||||
{ \
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \
|
||||
return iwl_dbgfs_##name##_write(mld, buf, count); \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \
|
||||
WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER_MLD(name) \
|
||||
static ssize_t __iwl_dbgfs_##name##_write(struct file *file, \
|
||||
const char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct dbgfs_##name##_data *data = file->private_data; \
|
||||
struct iwl_mld *mld = data->arg; \
|
||||
\
|
||||
return wiphy_locked_debugfs_write(mld->wiphy, file, \
|
||||
data->buf, sizeof(data->buf), \
|
||||
user_buf, count, \
|
||||
iwl_dbgfs_##name##_write_handler, \
|
||||
NULL); \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \
|
||||
WIPHY_DEBUGFS_READ_HANDLER_WRAPPER_MLD(name) \
|
||||
static ssize_t __iwl_dbgfs_##name##_read(struct file *file, \
|
||||
char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct dbgfs_##name##_data *data = file->private_data; \
|
||||
struct iwl_mld *mld = data->arg; \
|
||||
\
|
||||
if (!data->read_done) { \
|
||||
data->read_done = true; \
|
||||
data->rlen = wiphy_locked_debugfs_read(mld->wiphy, \
|
||||
file, data->buf, sizeof(data->buf), \
|
||||
user_buf, count, ppos, \
|
||||
iwl_dbgfs_##name##_read_handler, NULL); \
|
||||
return data->rlen; \
|
||||
} \
|
||||
\
|
||||
if (data->rlen < 0) \
|
||||
return data->rlen; \
|
||||
return simple_read_from_buffer(user_buf, count, ppos, \
|
||||
data->buf, data->rlen); \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_READ_FILE_OPS_MLD(name, bufsz) \
|
||||
MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \
|
||||
WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \
|
||||
static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
||||
.read = __iwl_dbgfs_##name##_read, \
|
||||
.open = _iwl_dbgfs_##name##_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
.release = _iwl_dbgfs_release, \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(name, bufsz) \
|
||||
MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \
|
||||
WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \
|
||||
static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
||||
.write = __iwl_dbgfs_##name##_write, \
|
||||
.open = _iwl_dbgfs_##name##_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
.release = _iwl_dbgfs_release, \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_READ_WRITE_FILE_OPS_MLD(name, bufsz) \
|
||||
MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \
|
||||
WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \
|
||||
WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \
|
||||
static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
||||
.write = __iwl_dbgfs_##name##_write, \
|
||||
.read = __iwl_dbgfs_##name##_read, \
|
||||
.open = _iwl_dbgfs_##name##_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
.release = _iwl_dbgfs_release, \
|
||||
}
|
||||
|
||||
#define WIPHY_DEBUGFS_WRITE_WRAPPER_IEEE80211(name, bufsz, objtype) \
|
||||
WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \
|
||||
static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \
|
||||
const char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct dbgfs_##name##_data *data = file->private_data; \
|
||||
struct ieee80211_##objtype *arg = data->arg; \
|
||||
struct iwl_mld *mld = iwl_mld_from_##objtype(arg); \
|
||||
char buf[bufsz] = {}; \
|
||||
\
|
||||
return wiphy_locked_debugfs_write(mld->wiphy, file, \
|
||||
buf, sizeof(buf), \
|
||||
user_buf, count, \
|
||||
iwl_dbgfs_##name##_write_handler, \
|
||||
arg); \
|
||||
}
|
||||
|
||||
#define IEEE80211_WIPHY_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, objtype) \
|
||||
MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct ieee80211_##objtype) \
|
||||
WIPHY_DEBUGFS_WRITE_WRAPPER_IEEE80211(name, bufsz, objtype) \
|
||||
MLD_DEBUGFS_READ_WRAPPER(name) \
|
||||
static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
||||
.write = _iwl_dbgfs_##name##_write, \
|
||||
.read = _iwl_dbgfs_##name##_read, \
|
||||
.open = _iwl_dbgfs_##name##_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
.release = _iwl_dbgfs_release, \
|
||||
}
|
||||
451
drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c
Normal file
451
drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c
Normal file
@@ -0,0 +1,451 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/math64.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "mld.h"
|
||||
#include "iface.h"
|
||||
#include "phy.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "constants.h"
|
||||
#include "fw/api/location.h"
|
||||
#include "ftm-initiator.h"
|
||||
|
||||
static void iwl_mld_ftm_cmd_common(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_tof_range_req_cmd *cmd,
|
||||
struct cfg80211_pmsr_request *req)
|
||||
{
|
||||
int i;
|
||||
|
||||
cmd->initiator_flags =
|
||||
cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM |
|
||||
IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT);
|
||||
cmd->request_id = req->cookie;
|
||||
cmd->num_of_ap = req->n_peers;
|
||||
|
||||
/* Use a large value for "no timeout". Don't use the maximum value
|
||||
* because of fw limitations.
|
||||
*/
|
||||
if (req->timeout)
|
||||
cmd->req_timeout_ms = cpu_to_le32(min(req->timeout, 0xfffff));
|
||||
else
|
||||
cmd->req_timeout_ms = cpu_to_le32(0xfffff);
|
||||
|
||||
memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
|
||||
|
||||
if (vif->cfg.assoc) {
|
||||
memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
|
||||
/* AP's TSF is only relevant if associated */
|
||||
for (i = 0; i < req->n_peers; i++) {
|
||||
if (req->peers[i].report_ap_tsf) {
|
||||
struct iwl_mld_vif *mld_vif =
|
||||
iwl_mld_vif_from_mac80211(vif);
|
||||
|
||||
cmd->tsf_mac_id = cpu_to_le32(mld_vif->fw_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eth_broadcast_addr(cmd->range_req_bssid);
|
||||
}
|
||||
|
||||
/* Don't report AP's TSF */
|
||||
cmd->tsf_mac_id = cpu_to_le32(0xff);
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mld_ftm_set_target_chandef(struct iwl_mld *mld,
|
||||
struct cfg80211_pmsr_request_peer *peer,
|
||||
struct iwl_tof_range_req_ap_entry *target)
|
||||
{
|
||||
u32 freq = peer->chandef.chan->center_freq;
|
||||
|
||||
target->channel_num = ieee80211_frequency_to_channel(freq);
|
||||
|
||||
switch (peer->chandef.width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
target->format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY;
|
||||
target->format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
target->format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
|
||||
target->format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
target->format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
|
||||
target->format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
target->format_bw = IWL_LOCATION_FRAME_FORMAT_VHT;
|
||||
target->format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
target->format_bw = IWL_LOCATION_FRAME_FORMAT_HE;
|
||||
target->format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS;
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(mld, "Unsupported BW in FTM request (%d)\n",
|
||||
peer->chandef.width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* non EDCA based measurement must use HE preamble */
|
||||
if (peer->ftm.trigger_based || peer->ftm.non_trigger_based)
|
||||
target->format_bw |= IWL_LOCATION_FRAME_FORMAT_HE;
|
||||
|
||||
target->ctrl_ch_position =
|
||||
(peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
|
||||
iwl_mld_get_fw_ctrl_pos(&peer->chandef) : 0;
|
||||
|
||||
target->band = iwl_mld_nl80211_band_to_fw(peer->chandef.chan->band);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FTM_SET_FLAG(flag) (target->initiator_ap_flags |= \
|
||||
cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
|
||||
|
||||
static void
|
||||
iwl_mld_ftm_set_target_flags(struct iwl_mld *mld,
|
||||
struct cfg80211_pmsr_request_peer *peer,
|
||||
struct iwl_tof_range_req_ap_entry *target)
|
||||
{
|
||||
target->initiator_ap_flags = cpu_to_le32(0);
|
||||
|
||||
if (peer->ftm.asap)
|
||||
FTM_SET_FLAG(ASAP);
|
||||
|
||||
if (peer->ftm.request_lci)
|
||||
FTM_SET_FLAG(LCI_REQUEST);
|
||||
|
||||
if (peer->ftm.request_civicloc)
|
||||
FTM_SET_FLAG(CIVIC_REQUEST);
|
||||
|
||||
if (IWL_MLD_FTM_INITIATOR_DYNACK)
|
||||
FTM_SET_FLAG(DYN_ACK);
|
||||
|
||||
if (IWL_MLD_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG)
|
||||
FTM_SET_FLAG(ALGO_LR);
|
||||
else if (IWL_MLD_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT)
|
||||
FTM_SET_FLAG(ALGO_FFT);
|
||||
|
||||
if (peer->ftm.trigger_based)
|
||||
FTM_SET_FLAG(TB);
|
||||
else if (peer->ftm.non_trigger_based)
|
||||
FTM_SET_FLAG(NON_TB);
|
||||
|
||||
if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) &&
|
||||
peer->ftm.lmr_feedback)
|
||||
FTM_SET_FLAG(LMR_FEEDBACK);
|
||||
}
|
||||
|
||||
static void iwl_mld_ftm_set_sta(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
struct cfg80211_pmsr_request_peer *peer,
|
||||
struct iwl_tof_range_req_ap_entry *target)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
u32 sta_id_mask;
|
||||
|
||||
target->sta_id = IWL_INVALID_STA;
|
||||
|
||||
/* TODO: add ftm_unprotected debugfs support */
|
||||
|
||||
if (!vif->cfg.assoc || !mld_vif->ap_sta)
|
||||
return;
|
||||
|
||||
sta_id_mask = iwl_mld_fw_sta_id_mask(mld, mld_vif->ap_sta);
|
||||
if (WARN_ON(hweight32(sta_id_mask) != 1))
|
||||
return;
|
||||
|
||||
target->sta_id = __ffs(sta_id_mask);
|
||||
|
||||
if (mld_vif->ap_sta->mfp &&
|
||||
(peer->ftm.trigger_based || peer->ftm.non_trigger_based))
|
||||
FTM_SET_FLAG(PMF);
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mld_ftm_set_target(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
struct cfg80211_pmsr_request_peer *peer,
|
||||
struct iwl_tof_range_req_ap_entry *target)
|
||||
{
|
||||
u32 i2r_max_sts;
|
||||
int ret;
|
||||
|
||||
ret = iwl_mld_ftm_set_target_chandef(mld, peer, target);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(target->bssid, peer->addr, ETH_ALEN);
|
||||
target->burst_period = cpu_to_le16(peer->ftm.burst_period);
|
||||
target->samples_per_burst = peer->ftm.ftms_per_burst;
|
||||
target->num_of_bursts = peer->ftm.num_bursts_exp;
|
||||
iwl_mld_ftm_set_target_flags(mld, peer, target);
|
||||
iwl_mld_ftm_set_sta(mld, vif, peer, target);
|
||||
|
||||
/* TODO: add secured ranging support */
|
||||
|
||||
i2r_max_sts = IWL_MLD_FTM_I2R_MAX_STS > 1 ? 1 :
|
||||
IWL_MLD_FTM_I2R_MAX_STS;
|
||||
|
||||
target->r2i_ndp_params = IWL_MLD_FTM_R2I_MAX_REP |
|
||||
(IWL_MLD_FTM_R2I_MAX_STS << IWL_LOCATION_MAX_STS_POS) |
|
||||
(IWL_MLD_FTM_R2I_MAX_TOTAL_LTF << IWL_LOCATION_TOTAL_LTF_POS);
|
||||
target->i2r_ndp_params = IWL_MLD_FTM_I2R_MAX_REP |
|
||||
(i2r_max_sts << IWL_LOCATION_MAX_STS_POS) |
|
||||
(IWL_MLD_FTM_I2R_MAX_TOTAL_LTF << IWL_LOCATION_TOTAL_LTF_POS);
|
||||
|
||||
if (peer->ftm.non_trigger_based) {
|
||||
target->min_time_between_msr =
|
||||
cpu_to_le16(IWL_MLD_FTM_NON_TB_MIN_TIME_BETWEEN_MSR);
|
||||
target->burst_period =
|
||||
cpu_to_le16(IWL_MLD_FTM_NON_TB_MAX_TIME_BETWEEN_MSR);
|
||||
} else {
|
||||
target->min_time_between_msr = cpu_to_le16(0);
|
||||
}
|
||||
|
||||
/* TODO: Beacon interval is currently unknown, so use the common value
|
||||
* of 100 TUs.
|
||||
*/
|
||||
target->beacon_interval = cpu_to_le16(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mld_ftm_start(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
struct cfg80211_pmsr_request *req)
|
||||
{
|
||||
struct iwl_tof_range_req_cmd cmd;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),
|
||||
.dataflags[0] = IWL_HCMD_DFL_DUP,
|
||||
.data[0] = &cmd,
|
||||
.len[0] = sizeof(cmd),
|
||||
};
|
||||
u8 i;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
if (mld->ftm_initiator.req)
|
||||
return -EBUSY;
|
||||
|
||||
if (req->n_peers > ARRAY_SIZE(cmd.ap))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
iwl_mld_ftm_cmd_common(mld, vif, (void *)&cmd, req);
|
||||
|
||||
for (i = 0; i < cmd.num_of_ap; i++) {
|
||||
struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
|
||||
struct iwl_tof_range_req_ap_entry *target = &cmd.ap[i];
|
||||
|
||||
ret = iwl_mld_ftm_set_target(mld, vif, peer, target);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: get the status from the response*/
|
||||
ret = iwl_mld_send_cmd(mld, &hcmd);
|
||||
if (!ret) {
|
||||
mld->ftm_initiator.req = req;
|
||||
mld->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mld_ftm_reset(struct iwl_mld *mld)
|
||||
{
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
mld->ftm_initiator.req = NULL;
|
||||
mld->ftm_initiator.req_wdev = NULL;
|
||||
memset(mld->ftm_initiator.responses, 0,
|
||||
sizeof(mld->ftm_initiator.responses));
|
||||
}
|
||||
|
||||
static int iwl_mld_ftm_range_resp_valid(struct iwl_mld *mld, u8 request_id,
|
||||
u8 num_of_aps)
|
||||
{
|
||||
if (IWL_FW_CHECK(mld, request_id != (u8)mld->ftm_initiator.req->cookie,
|
||||
"Request ID mismatch, got %u, active %u\n",
|
||||
request_id, (u8)mld->ftm_initiator.req->cookie))
|
||||
return -EINVAL;
|
||||
|
||||
if (IWL_FW_CHECK(mld, num_of_aps > mld->ftm_initiator.req->n_peers ||
|
||||
num_of_aps > IWL_TOF_MAX_APS,
|
||||
"FTM range response: invalid num of APs (%u)\n",
|
||||
num_of_aps))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_mld_ftm_find_peer(struct cfg80211_pmsr_request *req,
|
||||
const u8 *addr)
|
||||
{
|
||||
for (int i = 0; i < req->n_peers; i++) {
|
||||
struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
|
||||
|
||||
if (ether_addr_equal_unaligned(peer->addr, addr))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void iwl_mld_debug_range_resp(struct iwl_mld *mld, u8 index,
|
||||
struct cfg80211_pmsr_result *res)
|
||||
{
|
||||
s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666);
|
||||
|
||||
IWL_DEBUG_INFO(mld, "entry %d\n", index);
|
||||
IWL_DEBUG_INFO(mld, "\tstatus: %d\n", res->status);
|
||||
IWL_DEBUG_INFO(mld, "\tBSSID: %pM\n", res->addr);
|
||||
IWL_DEBUG_INFO(mld, "\thost time: %llu\n", res->host_time);
|
||||
IWL_DEBUG_INFO(mld, "\tburst index: %d\n", res->ftm.burst_index);
|
||||
IWL_DEBUG_INFO(mld, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes);
|
||||
IWL_DEBUG_INFO(mld, "\trssi: %d\n", res->ftm.rssi_avg);
|
||||
IWL_DEBUG_INFO(mld, "\trssi spread: %d\n", res->ftm.rssi_spread);
|
||||
IWL_DEBUG_INFO(mld, "\trtt: %lld\n", res->ftm.rtt_avg);
|
||||
IWL_DEBUG_INFO(mld, "\trtt var: %llu\n", res->ftm.rtt_variance);
|
||||
IWL_DEBUG_INFO(mld, "\trtt spread: %llu\n", res->ftm.rtt_spread);
|
||||
IWL_DEBUG_INFO(mld, "\tdistance: %lld\n", rtt_avg);
|
||||
}
|
||||
|
||||
void iwl_mld_handle_ftm_resp_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data;
|
||||
u8 num_of_aps, last_in_batch;
|
||||
|
||||
if (IWL_FW_CHECK(mld, !mld->ftm_initiator.req,
|
||||
"FTM response without a pending request\n"))
|
||||
return;
|
||||
|
||||
if (iwl_mld_ftm_range_resp_valid(mld, fw_resp->request_id,
|
||||
fw_resp->num_of_aps))
|
||||
return;
|
||||
|
||||
num_of_aps = fw_resp->num_of_aps;
|
||||
last_in_batch = fw_resp->last_report;
|
||||
|
||||
IWL_DEBUG_INFO(mld, "Range response received\n");
|
||||
IWL_DEBUG_INFO(mld, "request id: %llu, num of entries: %u\n",
|
||||
mld->ftm_initiator.req->cookie, num_of_aps);
|
||||
|
||||
for (int i = 0; i < num_of_aps; i++) {
|
||||
struct cfg80211_pmsr_result result = {};
|
||||
struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap;
|
||||
int peer_idx;
|
||||
|
||||
fw_ap = &fw_resp->ap[i];
|
||||
result.final = fw_ap->last_burst;
|
||||
result.ap_tsf = le32_to_cpu(fw_ap->start_tsf);
|
||||
result.ap_tsf_valid = 1;
|
||||
|
||||
peer_idx = iwl_mld_ftm_find_peer(mld->ftm_initiator.req,
|
||||
fw_ap->bssid);
|
||||
if (peer_idx < 0) {
|
||||
IWL_WARN(mld,
|
||||
"Unknown address (%pM, target #%d) in FTM response\n",
|
||||
fw_ap->bssid, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (fw_ap->measure_status) {
|
||||
case IWL_TOF_ENTRY_SUCCESS:
|
||||
result.status = NL80211_PMSR_STATUS_SUCCESS;
|
||||
break;
|
||||
case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT:
|
||||
result.status = NL80211_PMSR_STATUS_TIMEOUT;
|
||||
break;
|
||||
case IWL_TOF_ENTRY_NO_RESPONSE:
|
||||
result.status = NL80211_PMSR_STATUS_FAILURE;
|
||||
result.ftm.failure_reason =
|
||||
NL80211_PMSR_FTM_FAILURE_NO_RESPONSE;
|
||||
break;
|
||||
case IWL_TOF_ENTRY_REQUEST_REJECTED:
|
||||
result.status = NL80211_PMSR_STATUS_FAILURE;
|
||||
result.ftm.failure_reason =
|
||||
NL80211_PMSR_FTM_FAILURE_PEER_BUSY;
|
||||
result.ftm.busy_retry_time = fw_ap->refusal_period;
|
||||
break;
|
||||
default:
|
||||
result.status = NL80211_PMSR_STATUS_FAILURE;
|
||||
result.ftm.failure_reason =
|
||||
NL80211_PMSR_FTM_FAILURE_UNSPECIFIED;
|
||||
break;
|
||||
}
|
||||
memcpy(result.addr, fw_ap->bssid, ETH_ALEN);
|
||||
|
||||
/* TODO: convert the timestamp from the result to systime */
|
||||
result.host_time = ktime_get_boottime_ns();
|
||||
|
||||
result.type = NL80211_PMSR_TYPE_FTM;
|
||||
result.ftm.burst_index = mld->ftm_initiator.responses[peer_idx];
|
||||
mld->ftm_initiator.responses[peer_idx]++;
|
||||
result.ftm.rssi_avg = fw_ap->rssi;
|
||||
result.ftm.rssi_avg_valid = 1;
|
||||
result.ftm.rssi_spread = fw_ap->rssi_spread;
|
||||
result.ftm.rssi_spread_valid = 1;
|
||||
result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt);
|
||||
result.ftm.rtt_avg_valid = 1;
|
||||
result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance);
|
||||
result.ftm.rtt_variance_valid = 1;
|
||||
result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread);
|
||||
result.ftm.rtt_spread_valid = 1;
|
||||
|
||||
cfg80211_pmsr_report(mld->ftm_initiator.req_wdev,
|
||||
mld->ftm_initiator.req,
|
||||
&result, GFP_KERNEL);
|
||||
|
||||
if (fw_has_api(&mld->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_FTM_RTT_ACCURACY))
|
||||
IWL_DEBUG_INFO(mld, "RTT confidence: %u\n",
|
||||
fw_ap->rttConfidence);
|
||||
|
||||
iwl_mld_debug_range_resp(mld, i, &result);
|
||||
}
|
||||
|
||||
if (last_in_batch) {
|
||||
cfg80211_pmsr_complete(mld->ftm_initiator.req_wdev,
|
||||
mld->ftm_initiator.req,
|
||||
GFP_KERNEL);
|
||||
iwl_mld_ftm_reset(mld);
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_mld_ftm_restart_cleanup(struct iwl_mld *mld)
|
||||
{
|
||||
struct cfg80211_pmsr_result result = {
|
||||
.status = NL80211_PMSR_STATUS_FAILURE,
|
||||
.final = 1,
|
||||
.host_time = ktime_get_boottime_ns(),
|
||||
.type = NL80211_PMSR_TYPE_FTM,
|
||||
};
|
||||
|
||||
if (!mld->ftm_initiator.req)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < mld->ftm_initiator.req->n_peers; i++) {
|
||||
memcpy(result.addr, mld->ftm_initiator.req->peers[i].addr,
|
||||
ETH_ALEN);
|
||||
|
||||
cfg80211_pmsr_report(mld->ftm_initiator.req_wdev,
|
||||
mld->ftm_initiator.req,
|
||||
&result, GFP_KERNEL);
|
||||
}
|
||||
|
||||
cfg80211_pmsr_complete(mld->ftm_initiator.req_wdev,
|
||||
mld->ftm_initiator.req, GFP_KERNEL);
|
||||
iwl_mld_ftm_reset(mld);
|
||||
}
|
||||
29
drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h
Normal file
29
drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_ftm_initiator_h__
|
||||
#define __iwl_mld_ftm_initiator_h__
|
||||
|
||||
/**
|
||||
* struct ftm_initiator_data - FTM initiator data
|
||||
*
|
||||
* @req: a pointer to cfg80211 FTM request
|
||||
* @req_wdev: a pointer to the wdev that requested the current FTM request
|
||||
* @responses: the number of responses received for the current FTM session.
|
||||
* Used for tracking the burst index in a periodic request.
|
||||
*/
|
||||
struct ftm_initiator_data {
|
||||
struct cfg80211_pmsr_request *req;
|
||||
struct wireless_dev *req_wdev;
|
||||
int responses[IWL_TOF_MAX_APS];
|
||||
};
|
||||
|
||||
int iwl_mld_ftm_start(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
struct cfg80211_pmsr_request *req);
|
||||
|
||||
void iwl_mld_handle_ftm_resp_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
void iwl_mld_ftm_restart_cleanup(struct iwl_mld *mld);
|
||||
|
||||
#endif /* __iwl_mld_ftm_initiator_h__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user