AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/07 14:01 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch modifies the ath11k and ath12k drivers, which are vendor-specific PCIe/AHB Wi-Fi drivers for Qualcomm Atheros hardware. These require physical hardware devices that are not emulated in standard QEMU or GCE environments, making the modified code paths unreachable during fuzzing.",
  "WorthFuzzing": false
}

1/1 2026/08/07 14:01 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit b1ad83a41587a5c407f707038fc3ed9036bebad0\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Aug 7 14:01:47 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c\nindex f389b97acbdd5..2e5978ec2b05b 100644\n--- a/drivers/net/wireless/ath/ath11k/dp.c\n+++ b/drivers/net/wireless/ath/ath11k/dp.c\n@@ -1087,6 +1087,7 @@ int ath11k_dp_alloc(struct ath11k_base *ab)\n \tfor (i = 0; i \u003c ab-\u003ehw_params.hal_params-\u003enum_tx_rings; i++) {\n \t\tidr_init(\u0026dp-\u003etx_ring[i].txbuf_idr);\n \t\tspin_lock_init(\u0026dp-\u003etx_ring[i].tx_idr_lock);\n+\t\tspin_lock_init(\u0026dp-\u003etx_ring[i].wake_tx_lock);\n \t\tdp-\u003etx_ring[i].tcl_data_ring_id = i;\n \n \t\tdp-\u003etx_ring[i].tx_status_head = 0;\ndiff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h\nindex 84f66839f0c6d..6d99501aa269c 100644\n--- a/drivers/net/wireless/ath/ath11k/dp.h\n+++ b/drivers/net/wireless/ath/ath11k/dp.h\n@@ -87,6 +87,8 @@ struct dp_tx_ring {\n \tstruct idr txbuf_idr;\n \t/* Protects txbuf_idr and num_pending */\n \tspinlock_t tx_idr_lock;\n+\t/* Serializes wake_tx_queue operations for this ring */\n+\tspinlock_t wake_tx_lock;\n \tstruct hal_wbm_release_ring *tx_status;\n \tint tx_status_head;\n \tint tx_status_tail;\ndiff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c\nindex cac970c92806a..083aca8ff355b 100644\n--- a/drivers/net/wireless/ath/ath11k/dp_tx.c\n+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c\n@@ -108,7 +108,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,\n \n \tpool_id = skb_get_queue_mapping(skb) \u0026 (ATH11K_HW_MAX_QUEUES - 1);\n \n-\tring_selector = ab-\u003ehw_params.hw_ops-\u003eget_ring_selector(skb);\n+\tring_selector = ab-\u003ehw_params.hw_ops-\u003eget_ring_selector(skb_get_queue_mapping(skb));\n \n tcl_ring_sel:\n \ttcl_ring_retry = false;\ndiff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c\nindex 93f9a03c48dc0..8a28c1d4c17b6 100644\n--- a/drivers/net/wireless/ath/ath11k/hw.c\n+++ b/drivers/net/wireless/ath/ath11k/hw.c\n@@ -876,28 +876,14 @@ static bool ath11k_hw_wcn6855_rx_desc_get_ldpc_support(struct hal_rx_desc *desc)\n \t\t\t __le32_to_cpu(desc-\u003eu.wcn6855.msdu_start.info2));\n }\n \n-static u32 ath11k_hw_ipq8074_get_tcl_ring_selector(struct sk_buff *skb)\n-{\n-\t/* Let the default ring selection be based on current processor\n-\t * number, where one of the 3 tcl rings are selected based on\n-\t * the smp_processor_id(). In case that ring\n-\t * is full/busy, we resort to other available rings.\n-\t * If all rings are full, we drop the packet.\n-\t *\n-\t * TODO: Add throttling logic when all rings are full\n-\t */\n+static u32 ath11k_hw_ipq8074_get_tcl_ring_selector(u8 ac)\n+{\n \treturn smp_processor_id();\n }\n \n-static u32 ath11k_hw_wcn6750_get_tcl_ring_selector(struct sk_buff *skb)\n+static u32 ath11k_hw_wcn6750_get_tcl_ring_selector(u8 ac)\n {\n-\t/* Select the TCL ring based on the flow hash of the SKB instead\n-\t * of CPU ID. Since applications pumping the traffic can be scheduled\n-\t * on multiple CPUs, there is a chance that packets of the same flow\n-\t * could end on different TCL rings, this could sometimes results in\n-\t * an out of order arrival of the packets at the receiver.\n-\t */\n-\treturn skb_get_hash(skb);\n+\treturn ac;\n }\n \n const struct ath11k_hw_ops ipq8074_ops = {\ndiff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h\nindex 4996536fbd14f..b6bc8b72d8120 100644\n--- a/drivers/net/wireless/ath/ath11k/hw.h\n+++ b/drivers/net/wireless/ath/ath11k/hw.h\n@@ -273,7 +273,7 @@ struct ath11k_hw_ops {\n \tu16 (*mpdu_info_get_peerid)(struct hal_rx_mpdu_info *mpdu_info);\n \tbool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc);\n \tu8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc);\n-\tu32 (*get_ring_selector)(struct sk_buff *skb);\n+\tu32 (*get_ring_selector)(u8 ac);\n };\n \n extern const struct ath11k_hw_ops ipq8074_ops;\ndiff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c\nindex 2d55cdc4d165d..9813f7923c34f 100644\n--- a/drivers/net/wireless/ath/ath11k/mac.c\n+++ b/drivers/net/wireless/ath/ath11k/mac.c\n@@ -10065,9 +10065,59 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,\n \treturn ret;\n }\n \n+static void ath11k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,\n+\t\t\t\t\tstruct ieee80211_txq *txq)\n+{\n+\tstruct ieee80211_tx_control control = {\n+\t\t.sta = txq-\u003esta,\n+\t};\n+\tstruct ath11k *ar = hw-\u003epriv;\n+\tstruct dp_tx_ring *tx_ring;\n+\tstruct hal_srng *tcl_ring;\n+\tstruct sk_buff *skb;\n+\tu32 ring_selector;\n+\tint num_free;\n+\tu8 ring_id;\n+\n+\tif (!ar)\n+\t\treturn;\n+\n+\tring_selector = ar-\u003eab-\u003ehw_params.hw_ops-\u003eget_ring_selector(txq-\u003eac);\n+\tring_id = ring_selector % ar-\u003eab-\u003ehw_params.hal_params-\u003enum_tx_rings;\n+\ttx_ring = \u0026ar-\u003eab-\u003edp.tx_ring[ring_id];\n+\ttcl_ring = \u0026ar-\u003eab-\u003ehal.srng_list[tx_ring-\u003etcl_data_ring.ring_id];\n+\n+\twhile (1) {\n+\t\tif (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH,\n+\t\t\t\t      \u0026ar-\u003eab-\u003edev_flags)))\n+\t\t\tbreak;\n+\n+\t\tspin_lock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\n+\t\tspin_lock(\u0026tcl_ring-\u003elock);\n+\t\tnum_free = ath11k_hal_srng_src_num_free(ar-\u003eab, tcl_ring, true);\n+\t\tspin_unlock(\u0026tcl_ring-\u003elock);\n+\n+\t\tif (num_free == 0) {\n+\t\t\tspin_unlock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tskb = ieee80211_tx_dequeue(hw, txq);\n+\t\tif (!skb) {\n+\t\t\tspin_unlock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tath11k_mac_op_tx(hw, \u0026control, skb);\n+\n+\t\tspin_unlock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\t}\n+}\n+\n static const struct ieee80211_ops ath11k_ops = {\n \t.tx\t\t\t\t= ath11k_mac_op_tx,\n-\t.wake_tx_queue\t\t\t= ieee80211_handle_wake_tx_queue,\n+\t.wake_tx_queue\t\t\t= ath11k_mac_op_wake_tx_queue,\n \t.start                          = ath11k_mac_op_start,\n \t.stop                           = ath11k_mac_op_stop,\n \t.reconfig_complete              = ath11k_mac_op_reconfig_complete,\ndiff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c\nindex af5f11fc1d84a..3d46cfbf0a1c3 100644\n--- a/drivers/net/wireless/ath/ath12k/dp.c\n+++ b/drivers/net/wireless/ath/ath12k/dp.c\n@@ -1539,6 +1539,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab)\n \t}\n \n \tfor (i = 0; i \u003c ab-\u003ehw_params-\u003emax_tx_ring; i++) {\n+\t\tspin_lock_init(\u0026dp-\u003etx_ring[i].wake_tx_lock);\n \t\tdp-\u003etx_ring[i].tcl_data_ring_id = i;\n \n \t\tdp-\u003etx_ring[i].tx_status_head = 0;\ndiff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h\nindex f8cfc7bb29dd7..68d2020be9b86 100644\n--- a/drivers/net/wireless/ath/ath12k/dp.h\n+++ b/drivers/net/wireless/ath/ath12k/dp.h\n@@ -58,6 +58,8 @@ struct dp_tx_ring {\n \tu8 tcl_data_ring_id;\n \tstruct dp_srng tcl_data_ring;\n \tstruct dp_srng tcl_comp_ring;\n+\t/* Serializes wake_tx_queue operations for this ring */\n+\tspinlock_t wake_tx_lock;\n \tstruct hal_wbm_completion_ring_tx *tx_status;\n \tint tx_status_head;\n \tint tx_status_tail;\ndiff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c\nindex a164563fff289..071cb5d309310 100644\n--- a/drivers/net/wireless/ath/ath12k/hal.c\n+++ b/drivers/net/wireless/ath/ath12k/hal.c\n@@ -390,6 +390,7 @@ int ath12k_hal_srng_src_num_free(struct ath12k_base *ab, struct hal_srng *srng,\n \telse\n \t\treturn ((srng-\u003ering_size - hp + tp) / srng-\u003eentry_size) - 1;\n }\n+EXPORT_SYMBOL_GPL(ath12k_hal_srng_src_num_free);\n \n void *ath12k_hal_srng_src_next_peek(struct ath12k_base *ab,\n \t\t\t\t    struct hal_srng *srng)\ndiff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h\nindex 86fb8b7196135..65caa7a2349f1 100644\n--- a/drivers/net/wireless/ath/ath12k/hw.h\n+++ b/drivers/net/wireless/ath/ath12k/hw.h\n@@ -243,7 +243,7 @@ struct ath12k_hw_ops {\n \tint (*mac_id_to_pdev_id)(const struct ath12k_hw_params *hw, int mac_id);\n \tint (*mac_id_to_srng_id)(const struct ath12k_hw_params *hw, int mac_id);\n \tint (*rxdma_ring_sel_config)(struct ath12k_base *ab);\n-\tu8 (*get_ring_selector)(struct sk_buff *skb);\n+\tu8 (*get_ring_selector)(u8 ac);\n \tbool (*dp_srng_is_tx_comp_ring)(int ring_num);\n \tbool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,\n \t\t\t\t       struct ieee80211_mgmt *mgmt);\ndiff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c\nindex d2749de445534..74359e8eea471 100644\n--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c\n+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c\n@@ -111,7 +111,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a\n \t * If all rings are full, we drop the packet.\n \t * TODO: Add throttling logic when all rings are full\n \t */\n-\tring_selector = dp-\u003ehw_params-\u003ehw_ops-\u003eget_ring_selector(skb);\n+\tring_selector = dp-\u003ehw_params-\u003ehw_ops-\u003eget_ring_selector(skb_get_queue_mapping(skb));\n \n tcl_ring_sel:\n \ttcl_ring_retry = false;\ndiff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c\nindex d9fdd2fc82986..bedadd482a8e9 100644\n--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c\n+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c\n@@ -49,7 +49,7 @@ ath12k_wifi7_hw_mac_id_to_srng_id_qcn9274(const struct ath12k_hw_params *hw,\n \treturn 0;\n }\n \n-static u8 ath12k_wifi7_hw_get_ring_selector_qcn9274(struct sk_buff *skb)\n+static u8 ath12k_wifi7_hw_get_ring_selector_qcn9274(u8 ac)\n {\n \treturn smp_processor_id();\n }\n@@ -83,9 +83,9 @@ ath12k_wifi7_hw_mac_id_to_srng_id_wcn7850(const struct ath12k_hw_params *hw,\n \treturn mac_id;\n }\n \n-static u8 ath12k_wifi7_hw_get_ring_selector_wcn7850(struct sk_buff *skb)\n+static u8 ath12k_wifi7_hw_get_ring_selector_wcn7850(u8 ac)\n {\n-\treturn skb_get_queue_mapping(skb);\n+\treturn ac;\n }\n \n static bool ath12k_wifi7_dp_srng_is_comp_ring_wcn7850(int ring_num)\n@@ -1100,9 +1100,82 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,\n \t}\n }\n \n+static void ath12k_wifi7_mac_op_wake_tx_queue(struct ieee80211_hw *hw,\n+\t\t\t\t\t      struct ieee80211_txq *txq)\n+{\n+\tstruct ath12k_vif *ahvif = ath12k_vif_to_ahvif(txq-\u003evif);\n+\tstruct ieee80211_tx_control control = {\n+\t\t.sta = txq-\u003esta,\n+\t};\n+\tstruct ieee80211_vif *vif = txq-\u003evif;\n+\tstruct ath12k_link_vif *arvif;\n+\tstruct dp_tx_ring *tx_ring;\n+\tstruct hal_srng *tcl_ring;\n+\tstruct ath12k_sta *ahsta;\n+\tstruct ath12k_dp *dp;\n+\tstruct sk_buff *skb;\n+\tstruct ath12k *ar;\n+\tu8 ring_selector;\n+\tint num_free;\n+\tu8 ring_id;\n+\tu8 link_id;\n+\n+\tif (ieee80211_vif_is_mld(vif) \u0026\u0026 txq-\u003esta) {\n+\t\tahsta = ath12k_sta_to_ahsta(txq-\u003esta);\n+\t\tlink_id = ahsta-\u003eassoc_link_id;\n+\t} else {\n+\t\tlink_id = ahvif-\u003edeflink.link_id;\n+\t}\n+\n+\trcu_read_lock();\n+\n+\tarvif = rcu_dereference(ahvif-\u003elink[link_id]);\n+\tif (!arvif || !arvif-\u003ear) {\n+\t\trcu_read_unlock();\n+\t\treturn;\n+\t}\n+\n+\tar = arvif-\u003ear;\n+\tdp = ar-\u003eab-\u003edp;\n+\n+\tring_selector = dp-\u003ehw_params-\u003ehw_ops-\u003eget_ring_selector(txq-\u003eac);\n+\tring_id = ring_selector % dp-\u003ehw_params-\u003emax_tx_ring;\n+\ttx_ring = \u0026dp-\u003etx_ring[ring_id];\n+\ttcl_ring = \u0026dp-\u003ehal-\u003esrng_list[tx_ring-\u003etcl_data_ring.ring_id];\n+\n+\twhile (1) {\n+\t\tif (unlikely(test_bit(ATH12K_FLAG_CRASH_FLUSH,\n+\t\t\t\t      \u0026ar-\u003eab-\u003edev_flags)))\n+\t\t\tbreak;\n+\n+\t\tspin_lock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\n+\t\tspin_lock(\u0026tcl_ring-\u003elock);\n+\t\tnum_free = ath12k_hal_srng_src_num_free(ar-\u003eab, tcl_ring, true);\n+\t\tspin_unlock(\u0026tcl_ring-\u003elock);\n+\n+\t\tif (num_free == 0) {\n+\t\t\tspin_unlock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tskb = ieee80211_tx_dequeue(hw, txq);\n+\t\tif (!skb) {\n+\t\t\tspin_unlock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tath12k_wifi7_mac_op_tx(hw, \u0026control, skb);\n+\n+\t\tspin_unlock_bh(\u0026tx_ring-\u003ewake_tx_lock);\n+\t}\n+\n+\trcu_read_unlock();\n+}\n+\n static const struct ieee80211_ops ath12k_ops_wifi7 = {\n \t.tx\t\t\t\t= ath12k_wifi7_mac_op_tx,\n-\t.wake_tx_queue\t\t\t= ieee80211_handle_wake_tx_queue,\n+\t.wake_tx_queue\t\t\t= ath12k_wifi7_mac_op_wake_tx_queue,\n \t.start                          = ath12k_mac_op_start,\n \t.stop                           = ath12k_mac_op_stop,\n \t.reconfig_complete              = ath12k_mac_op_reconfig_complete,\n"
}

2/1 2026/08/07 14:01 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the ath11k and ath12k drivers, which are vendor-specific PCIe/AHB Wi-Fi drivers for Qualcomm Atheros hardware. These require physical hardware devices that are not emulated in standard QEMU or GCE environments, making the modified code paths unreachable during fuzzing.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit b1ad83a41587a5c407f707038fc3ed9036bebad0
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Aug 7 14:01:47 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index f389b97acbdd5..2e5978ec2b05b 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -1087,6 +1087,7 @@ int ath11k_dp_alloc(struct ath11k_base *ab)
 	for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) {
 		idr_init(&dp->tx_ring[i].txbuf_idr);
 		spin_lock_init(&dp->tx_ring[i].tx_idr_lock);
+		spin_lock_init(&dp->tx_ring[i].wake_tx_lock);
 		dp->tx_ring[i].tcl_data_ring_id = i;
 
 		dp->tx_ring[i].tx_status_head = 0;
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
index 84f66839f0c6d..6d99501aa269c 100644
--- a/drivers/net/wireless/ath/ath11k/dp.h
+++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -87,6 +87,8 @@ struct dp_tx_ring {
 	struct idr txbuf_idr;
 	/* Protects txbuf_idr and num_pending */
 	spinlock_t tx_idr_lock;
+	/* Serializes wake_tx_queue operations for this ring */
+	spinlock_t wake_tx_lock;
 	struct hal_wbm_release_ring *tx_status;
 	int tx_status_head;
 	int tx_status_tail;
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index cac970c92806a..083aca8ff355b 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -108,7 +108,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
 
 	pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
 
-	ring_selector = ab->hw_params.hw_ops->get_ring_selector(skb);
+	ring_selector = ab->hw_params.hw_ops->get_ring_selector(skb_get_queue_mapping(skb));
 
 tcl_ring_sel:
 	tcl_ring_retry = false;
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index 93f9a03c48dc0..8a28c1d4c17b6 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -876,28 +876,14 @@ static bool ath11k_hw_wcn6855_rx_desc_get_ldpc_support(struct hal_rx_desc *desc)
 			 __le32_to_cpu(desc->u.wcn6855.msdu_start.info2));
 }
 
-static u32 ath11k_hw_ipq8074_get_tcl_ring_selector(struct sk_buff *skb)
-{
-	/* Let the default ring selection be based on current processor
-	 * number, where one of the 3 tcl rings are selected based on
-	 * the smp_processor_id(). In case that ring
-	 * is full/busy, we resort to other available rings.
-	 * If all rings are full, we drop the packet.
-	 *
-	 * TODO: Add throttling logic when all rings are full
-	 */
+static u32 ath11k_hw_ipq8074_get_tcl_ring_selector(u8 ac)
+{
 	return smp_processor_id();
 }
 
-static u32 ath11k_hw_wcn6750_get_tcl_ring_selector(struct sk_buff *skb)
+static u32 ath11k_hw_wcn6750_get_tcl_ring_selector(u8 ac)
 {
-	/* Select the TCL ring based on the flow hash of the SKB instead
-	 * of CPU ID. Since applications pumping the traffic can be scheduled
-	 * on multiple CPUs, there is a chance that packets of the same flow
-	 * could end on different TCL rings, this could sometimes results in
-	 * an out of order arrival of the packets at the receiver.
-	 */
-	return skb_get_hash(skb);
+	return ac;
 }
 
 const struct ath11k_hw_ops ipq8074_ops = {
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 4996536fbd14f..b6bc8b72d8120 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -273,7 +273,7 @@ struct ath11k_hw_ops {
 	u16 (*mpdu_info_get_peerid)(struct hal_rx_mpdu_info *mpdu_info);
 	bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc);
 	u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc);
-	u32 (*get_ring_selector)(struct sk_buff *skb);
+	u32 (*get_ring_selector)(u8 ac);
 };
 
 extern const struct ath11k_hw_ops ipq8074_ops;
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 2d55cdc4d165d..9813f7923c34f 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -10065,9 +10065,59 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
 	return ret;
 }
 
+static void ath11k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
+					struct ieee80211_txq *txq)
+{
+	struct ieee80211_tx_control control = {
+		.sta = txq->sta,
+	};
+	struct ath11k *ar = hw->priv;
+	struct dp_tx_ring *tx_ring;
+	struct hal_srng *tcl_ring;
+	struct sk_buff *skb;
+	u32 ring_selector;
+	int num_free;
+	u8 ring_id;
+
+	if (!ar)
+		return;
+
+	ring_selector = ar->ab->hw_params.hw_ops->get_ring_selector(txq->ac);
+	ring_id = ring_selector % ar->ab->hw_params.hal_params->num_tx_rings;
+	tx_ring = &ar->ab->dp.tx_ring[ring_id];
+	tcl_ring = &ar->ab->hal.srng_list[tx_ring->tcl_data_ring.ring_id];
+
+	while (1) {
+		if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH,
+				      &ar->ab->dev_flags)))
+			break;
+
+		spin_lock_bh(&tx_ring->wake_tx_lock);
+
+		spin_lock(&tcl_ring->lock);
+		num_free = ath11k_hal_srng_src_num_free(ar->ab, tcl_ring, true);
+		spin_unlock(&tcl_ring->lock);
+
+		if (num_free == 0) {
+			spin_unlock_bh(&tx_ring->wake_tx_lock);
+			break;
+		}
+
+		skb = ieee80211_tx_dequeue(hw, txq);
+		if (!skb) {
+			spin_unlock_bh(&tx_ring->wake_tx_lock);
+			break;
+		}
+
+		ath11k_mac_op_tx(hw, &control, skb);
+
+		spin_unlock_bh(&tx_ring->wake_tx_lock);
+	}
+}
+
 static const struct ieee80211_ops ath11k_ops = {
 	.tx				= ath11k_mac_op_tx,
-	.wake_tx_queue			= ieee80211_handle_wake_tx_queue,
+	.wake_tx_queue			= ath11k_mac_op_wake_tx_queue,
 	.start                          = ath11k_mac_op_start,
 	.stop                           = ath11k_mac_op_stop,
 	.reconfig_complete              = ath11k_mac_op_reconfig_complete,
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index af5f11fc1d84a..3d46cfbf0a1c3 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1539,6 +1539,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab)
 	}
 
 	for (i = 0; i < ab->hw_params->max_tx_ring; i++) {
+		spin_lock_init(&dp->tx_ring[i].wake_tx_lock);
 		dp->tx_ring[i].tcl_data_ring_id = i;
 
 		dp->tx_ring[i].tx_status_head = 0;
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index f8cfc7bb29dd7..68d2020be9b86 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -58,6 +58,8 @@ struct dp_tx_ring {
 	u8 tcl_data_ring_id;
 	struct dp_srng tcl_data_ring;
 	struct dp_srng tcl_comp_ring;
+	/* Serializes wake_tx_queue operations for this ring */
+	spinlock_t wake_tx_lock;
 	struct hal_wbm_completion_ring_tx *tx_status;
 	int tx_status_head;
 	int tx_status_tail;
diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c
index a164563fff289..071cb5d309310 100644
--- a/drivers/net/wireless/ath/ath12k/hal.c
+++ b/drivers/net/wireless/ath/ath12k/hal.c
@@ -390,6 +390,7 @@ int ath12k_hal_srng_src_num_free(struct ath12k_base *ab, struct hal_srng *srng,
 	else
 		return ((srng->ring_size - hp + tp) / srng->entry_size) - 1;
 }
+EXPORT_SYMBOL_GPL(ath12k_hal_srng_src_num_free);
 
 void *ath12k_hal_srng_src_next_peek(struct ath12k_base *ab,
 				    struct hal_srng *srng)
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 86fb8b7196135..65caa7a2349f1 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -243,7 +243,7 @@ struct ath12k_hw_ops {
 	int (*mac_id_to_pdev_id)(const struct ath12k_hw_params *hw, int mac_id);
 	int (*mac_id_to_srng_id)(const struct ath12k_hw_params *hw, int mac_id);
 	int (*rxdma_ring_sel_config)(struct ath12k_base *ab);
-	u8 (*get_ring_selector)(struct sk_buff *skb);
+	u8 (*get_ring_selector)(u8 ac);
 	bool (*dp_srng_is_tx_comp_ring)(int ring_num);
 	bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,
 				       struct ieee80211_mgmt *mgmt);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
index d2749de445534..74359e8eea471 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
@@ -111,7 +111,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
 	 * If all rings are full, we drop the packet.
 	 * TODO: Add throttling logic when all rings are full
 	 */
-	ring_selector = dp->hw_params->hw_ops->get_ring_selector(skb);
+	ring_selector = dp->hw_params->hw_ops->get_ring_selector(skb_get_queue_mapping(skb));
 
 tcl_ring_sel:
 	tcl_ring_retry = false;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index d9fdd2fc82986..bedadd482a8e9 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -49,7 +49,7 @@ ath12k_wifi7_hw_mac_id_to_srng_id_qcn9274(const struct ath12k_hw_params *hw,
 	return 0;
 }
 
-static u8 ath12k_wifi7_hw_get_ring_selector_qcn9274(struct sk_buff *skb)
+static u8 ath12k_wifi7_hw_get_ring_selector_qcn9274(u8 ac)
 {
 	return smp_processor_id();
 }
@@ -83,9 +83,9 @@ ath12k_wifi7_hw_mac_id_to_srng_id_wcn7850(const struct ath12k_hw_params *hw,
 	return mac_id;
 }
 
-static u8 ath12k_wifi7_hw_get_ring_selector_wcn7850(struct sk_buff *skb)
+static u8 ath12k_wifi7_hw_get_ring_selector_wcn7850(u8 ac)
 {
-	return skb_get_queue_mapping(skb);
+	return ac;
 }
 
 static bool ath12k_wifi7_dp_srng_is_comp_ring_wcn7850(int ring_num)
@@ -1100,9 +1100,82 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
 	}
 }
 
+static void ath12k_wifi7_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
+					      struct ieee80211_txq *txq)
+{
+	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(txq->vif);
+	struct ieee80211_tx_control control = {
+		.sta = txq->sta,
+	};
+	struct ieee80211_vif *vif = txq->vif;
+	struct ath12k_link_vif *arvif;
+	struct dp_tx_ring *tx_ring;
+	struct hal_srng *tcl_ring;
+	struct ath12k_sta *ahsta;
+	struct ath12k_dp *dp;
+	struct sk_buff *skb;
+	struct ath12k *ar;
+	u8 ring_selector;
+	int num_free;
+	u8 ring_id;
+	u8 link_id;
+
+	if (ieee80211_vif_is_mld(vif) && txq->sta) {
+		ahsta = ath12k_sta_to_ahsta(txq->sta);
+		link_id = ahsta->assoc_link_id;
+	} else {
+		link_id = ahvif->deflink.link_id;
+	}
+
+	rcu_read_lock();
+
+	arvif = rcu_dereference(ahvif->link[link_id]);
+	if (!arvif || !arvif->ar) {
+		rcu_read_unlock();
+		return;
+	}
+
+	ar = arvif->ar;
+	dp = ar->ab->dp;
+
+	ring_selector = dp->hw_params->hw_ops->get_ring_selector(txq->ac);
+	ring_id = ring_selector % dp->hw_params->max_tx_ring;
+	tx_ring = &dp->tx_ring[ring_id];
+	tcl_ring = &dp->hal->srng_list[tx_ring->tcl_data_ring.ring_id];
+
+	while (1) {
+		if (unlikely(test_bit(ATH12K_FLAG_CRASH_FLUSH,
+				      &ar->ab->dev_flags)))
+			break;
+
+		spin_lock_bh(&tx_ring->wake_tx_lock);
+
+		spin_lock(&tcl_ring->lock);
+		num_free = ath12k_hal_srng_src_num_free(ar->ab, tcl_ring, true);
+		spin_unlock(&tcl_ring->lock);
+
+		if (num_free == 0) {
+			spin_unlock_bh(&tx_ring->wake_tx_lock);
+			break;
+		}
+
+		skb = ieee80211_tx_dequeue(hw, txq);
+		if (!skb) {
+			spin_unlock_bh(&tx_ring->wake_tx_lock);
+			break;
+		}
+
+		ath12k_wifi7_mac_op_tx(hw, &control, skb);
+
+		spin_unlock_bh(&tx_ring->wake_tx_lock);
+	}
+
+	rcu_read_unlock();
+}
+
 static const struct ieee80211_ops ath12k_ops_wifi7 = {
 	.tx				= ath12k_wifi7_mac_op_tx,
-	.wake_tx_queue			= ieee80211_handle_wake_tx_queue,
+	.wake_tx_queue			= ath12k_wifi7_mac_op_wake_tx_queue,
 	.start                          = ath12k_mac_op_start,
 	.stop                           = ath12k_mac_op_stop,
 	.reconfig_complete              = ath12k_mac_op_reconfig_complete,

3/2 2026/08/07 14:01 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 7380
							output: 23
							thoughts: 520
						

Thoughts:
**Analyzing the Implications of a Wi-Fi Driver Patch in a Virtualized Context**

Okay, so I'm looking at this patch modifying the `ath11k` and `ath12k` wireless drivers. It introduces a spinlock (`wake_tx_lock`) to the `dp_tx_ring` struct and includes `wake_tx_queue` callbacks for both drivers. The `get_ring_selector` function also changed to accept `u8 ac` instead of `struct sk_buff *skb`. My immediate thought is, can I test this in a virtual environment like QEMU?

Since I'm dealing with `ath11k` and `ath12k`, which are Qualcomm Wi-Fi drivers, I have to consider whether they are PCI or AHB devices. And the answer is, yes, they are, usually physical PCIe or AHB. So, the core question becomes: can I effectively emulate or fuzz these drivers in the absence of the actual hardware?

Generally speaking, when it comes to Wi-Fi, there are some software emulators like `mac80211_hwsim`. But `ath11k` and `ath12k` are designed for hardware. Given the context, the prompt specifically mentions challenges with vendor-specific PCIe switch, SmartNIC, or GPU drivers, which require physical hardware and aren't typically well-emulated in standard QEMU. That hits home. `ath11k` is a vendor-specific PCI/AHB Wi-Fi driver, designed for Qualcomm Atheros 802.11ax/be devices.

So, the real question boils down to: is there a reasonable chance of fuzzing this in QEMU? My experience tells me that these hardware-specific Wi-Fi drivers often require physical hardware. I can think of `mac80211_hwsim`, and possibly `fmac`, but `mac80211_hwsim` is a virtual driver, not an emulator for `ath11k`. While syzkaller has some USB fuzzing capabilities, this isn't USB; it's PCI/AHB.

Ultimately, I need to check whether `ath11k` offers any kind of virtual or emulated support. I'm going to leverage `grepper` to search through the codebase for mentions of `ath11k` and `ath12k` combined with the bus types they use, to see if there is any way this code can be tested.



4/2 2026/08/07 14:01 tool grepper
0m Args:
{
  "Expression": "ath11k_pci_probe"
}

Results:
{
  "Output": "drivers/net/wireless/ath/ath11k/pci.c=940=static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,\n--\ndrivers/net/wireless/ath/ath11k/pci.c-948-\ndrivers/net/wireless/ath/ath11k/pci.c:949:static int ath11k_pci_probe(struct pci_dev *pdev,\ndrivers/net/wireless/ath/ath11k/pci.c-950-\t\t\t    const struct pci_device_id *pci_dev)\n--\ndrivers/net/wireless/ath/ath11k/pci.c=1296=static struct pci_driver ath11k_pci_driver = {\n--\ndrivers/net/wireless/ath/ath11k/pci.c-1298-\t.id_table = ath11k_pci_id_table,\ndrivers/net/wireless/ath/ath11k/pci.c:1299:\t.probe = ath11k_pci_probe,\ndrivers/net/wireless/ath/ath11k/pci.c-1300-\t.remove = ath11k_pci_remove,\n"
}

5/2 2026/08/07 14:02 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 8796
							output: 23
							thoughts: 12
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**PCI Driver Consideration**

Okay, so I'm looking at this... it's a PCI driver. My immediate thought is, "Alright, PCI. That's a good starting point, but let's not get tunnel vision." I immediately start to think about the broader context of the system architecture. We're dealing with hardware, so the data transfer between the CPU and the PCI device, as well as any others, is the important bit. This driver is handling that data transfer.

And that's when it hits me: "What about the AHB?" The PCI bus is the standard here, so that means the AHB bus is the hardware connection to the rest of the board. I need to keep in mind, even though this is a PCI driver, how it interacts with the underlying system-on-chip (SoC) infrastructure. Specifically, how does this driver interface with the Advanced High-performance Bus (AHB), or any other potential interconnect? Is there an intermediary bridge, memory-mapped I/O, direct memory access (DMA), or something else? Understanding that interconnect is crucial to truly understand how this driver is configured and how it will perform.



6/2 2026/08/07 14:02 tool grepper
0m Args:
{
  "Expression": "ath11k_ahb_probe"
}

Results:
{
  "Output": "drivers/net/wireless/ath/ath11k/ahb.c=1073=static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)\n--\ndrivers/net/wireless/ath/ath11k/ahb.c-1107-\ndrivers/net/wireless/ath/ath11k/ahb.c:1108:static int ath11k_ahb_probe(struct platform_device *pdev)\ndrivers/net/wireless/ath/ath11k/ahb.c-1109-{\n--\ndrivers/net/wireless/ath/ath11k/ahb.c=1303=static struct platform_driver ath11k_ahb_driver = {\n--\ndrivers/net/wireless/ath/ath11k/ahb.c-1307-\t},\ndrivers/net/wireless/ath/ath11k/ahb.c:1308:\t.probe = ath11k_ahb_probe,\ndrivers/net/wireless/ath/ath11k/ahb.c-1309-\t.remove = ath11k_ahb_remove,\n"
}

7/2 2026/08/07 14:02 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 9396
							output: 95
							thoughts: 523
						

Thoughts:
**WorthFuzzing Decision for ath11k/ath12k Drivers**

Okay, so I'm looking at this patch for a PCI and AHB driver. The prompt says I need to return `WorthFuzzing=false` if the patch touches code that's unreachable in virtualized environments like GCE or QEMU, or if it's specific to hardware not emulated in those environments. Specifically, the prompt mentions vendor-specific PCIe switches, SmartNICs, and GPUs as examples to flag.

My initial thought is that `ath11k` and `ath12k` are vendor-specific Wi-Fi drivers, developed by Qualcomm Atheros for 802.11ax/be, and they rely on either PCIe or AHB hardware. These are typically not emulated properly in standard QEMU. They require the physical hardware to operate correctly.

I briefly considered if Syzkaller could somehow fuzz this using its PCI injection capabilities. It *does* have PCI fuzzing (`syz_pci_device_add`), but it's pretty limited and generally doesn't dive deep into complex Wi-Fi MAC/PHY logic without specific targeting or hardware emulation. However, the prompt specifically calls out vendor-specific PCIe components that require physical hardware. Wi-Fi drivers, in this scenario, seem to fall into that category of "not emulated."

I took a quick look to see if Syzkaller *does* have any hooks into these drivers directly. It does have `sys/linux/socket_netlink_generic_nl80211.txt`, which fuzzed nl80211, but that usually hits `mac80211_hwsim` or `cfg80211` core and is not likely to hit specific hardware drivers unless the hardware is present in the environment.

Therefore, because the relevant hardware is *not* present in the GCE/QEMU environment, the code paths related to `ath11k_mac_op_wake_tx_queue` will never be executed.

Based on this analysis, I'm confident in returning `WorthFuzzing=false`. The patch modifies vendor-specific PCIe/AHB Wi-Fi drivers (ath11k/ath12k), which necessitates physical hardware that's absent in standard virtualized environments.



8/2 2026/08/07 14:02 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the ath11k and ath12k drivers, which are vendor-specific PCIe/AHB Wi-Fi drivers for Qualcomm Atheros hardware. These require physical hardware devices that are not emulated in standard QEMU or GCE environments, making the modified code paths unreachable during fuzzing.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the ath11k and ath12k drivers, which are vendor-specific PCIe/AHB Wi-Fi drivers for Qualcomm Atheros hardware. These require physical hardware devices that are not emulated in standard QEMU or GCE environments, making the modified code paths unreachable during fuzzing.",
  "WorthFuzzing": false
}

9/1 2026/08/07 14:02 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)