1
0
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:
Jakub Kicinski
2025-03-25 08:04:12 -07:00
274 changed files with 68265 additions and 2716 deletions

View File

@@ -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.

View File

@@ -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";
};
};
};

View File

@@ -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

View File

@@ -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>;

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View 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);
}

View 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

View File

@@ -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);

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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_ */

View File

@@ -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(&params->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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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(&timestamp);
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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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(&params->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(&params->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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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.
*

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View 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);
}
}

View 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_ */

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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:

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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 */

View 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;
}
}

View 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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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,
};

View File

@@ -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) {

View File

@@ -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"

View File

@@ -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/

View File

@@ -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,

View File

@@ -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";

View File

@@ -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,

View File

@@ -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;

View File

@@ -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*/

View File

@@ -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
*

View File

@@ -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

View 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__ */

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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__ */

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;

View 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)/../

View 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;
}

View 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__ */

View 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);
}

View 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__ */

View 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);
}

View 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__ */

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

File diff suppressed because it is too large Load Diff

View 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, \
}

View 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);
}

View 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