AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Airoha SoC ethernet driver (drivers/net/ethernet/airoha/). This is a hardware-specific platform driver that requires physical Airoha EN7581/AN7583 SoC hardware to probe and function. It cannot be reached or tested in standard virtualized environments like QEMU or GCE used by syzkaller.",
  "WorthFuzzing": false
}

1/1 2026/07/01 13:38 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 834eb22ca40e2b60fa75bd16660649099b8cd14d\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Jul 1 13:38:32 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c\nindex 932b3a3df2e577..609a5ea67fb743 100644\n--- a/drivers/net/ethernet/airoha/airoha_eth.c\n+++ b/drivers/net/ethernet/airoha/airoha_eth.c\n@@ -929,7 +929,7 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)\n \t\t\tif (!dev)\n \t\t\t\tcontinue;\n \n-\t\t\tif (dev-\u003eqdma != qdma)\n+\t\t\tif (rcu_access_pointer(dev-\u003eqdma) != qdma)\n \t\t\t\tcontinue;\n \n \t\t\tnetdev = netdev_from_priv(dev);\n@@ -1837,13 +1837,14 @@ static int airoha_dev_open(struct net_device *netdev)\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n \tstruct airoha_gdm_port *port = dev-\u003eport;\n \tu32 cur_len, pse_port = FE_PSE_PORT_PPE1;\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n+\tstruct airoha_qdma *qdma;\n \n \tnetif_tx_start_all_queues(netdev);\n \terr = airoha_set_vip_for_gdm_port(dev, true);\n \tif (err)\n \t\treturn err;\n \n+\tqdma = airoha_qdma_deref(dev);\n \tif (netdev_uses_dsa(netdev))\n \t\tairoha_fe_set(qdma-\u003eeth, REG_GDM_INGRESS_CFG(port-\u003eid),\n \t\t\t      GDM_STAG_EN_MASK);\n@@ -1903,7 +1904,6 @@ static int airoha_dev_stop(struct net_device *netdev)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n \tstruct airoha_gdm_port *port = dev-\u003eport;\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n \n \tnetif_tx_disable(netdev);\n \tairoha_set_vip_for_gdm_port(dev, false);\n@@ -1911,7 +1911,7 @@ static int airoha_dev_stop(struct net_device *netdev)\n \tif (--port-\u003eusers)\n \t\tairoha_set_port_mtu(dev-\u003eeth, port);\n \telse\n-\t\tairoha_set_gdm_port_fwd_cfg(qdma-\u003eeth,\n+\t\tairoha_set_gdm_port_fwd_cfg(dev-\u003eeth,\n \t\t\t\t\t    REG_GDM_FWD_CFG(port-\u003eid),\n \t\t\t\t\t    FE_PSE_PORT_DROP);\n \treturn 0;\n@@ -1998,6 +1998,53 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)\n \treturn 0;\n }\n \n+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev)\n+{\n+\tstruct airoha_gdm_port *port = dev-\u003eport;\n+\tstruct airoha_eth *eth = dev-\u003eeth;\n+\tint i, src_port;\n+\tu32 pse_port;\n+\n+\tsrc_port = eth-\u003esoc-\u003eops.get_sport(dev-\u003eport, dev-\u003enbq);\n+\tif (src_port \u003c 0)\n+\t\treturn src_port;\n+\n+\tairoha_fe_clear(eth,\n+\t\t\tREG_SP_DFT_CPORT(src_port \u003e\u003e fls(SP_CPORT_DFT_MASK)),\n+\t\t\tSP_CPORT_MASK(src_port \u0026 SP_CPORT_DFT_MASK));\n+\n+\tairoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),\n+\t\t      GDM_STRIP_CRC_MASK);\n+\tairoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),\n+\t\t\t\t    FE_PSE_PORT_DROP);\n+\tairoha_fe_clear(eth, REG_GDM_LPBK_CFG(AIROHA_GDM2_IDX),\n+\t\t\tLPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK);\n+\tpse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2\n+\t\t\t\t\t\t : FE_PSE_PORT_PPE1;\n+\tairoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),\n+\t\t\t\t    pse_port);\n+\n+\tairoha_fe_rmw(eth, REG_FE_WAN_PORT, WAN0_MASK,\n+\t\t      FIELD_PREP(WAN0_MASK, AIROHA_GDM2_IDX));\n+\n+\tfor (i = 0; i \u003c eth-\u003esoc-\u003enum_ppe; i++)\n+\t\tairoha_fe_clear(eth, REG_PPE_DFT_CPORT(i, AIROHA_GDM2_IDX),\n+\t\t\t\tDFT_CPORT_MASK(AIROHA_GDM2_IDX));\n+\n+\t/* Enable VIP and IFC for GDM2 */\n+\tairoha_fe_set(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));\n+\tairoha_fe_set(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));\n+\n+\tif (port-\u003eid == AIROHA_GDM4_IDX \u0026\u0026 airoha_is_7581(eth)) {\n+\t\tu32 mask = FC_ID_OF_SRC_PORT_MASK(dev-\u003enbq);\n+\n+\t\tairoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask,\n+\t\t\t      FC_MAP6_DEF_VALUE \u0026 mask);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static struct airoha_gdm_dev *\n airoha_get_wan_gdm_dev(struct airoha_eth *eth)\n {\n@@ -2024,15 +2071,26 @@ airoha_get_wan_gdm_dev(struct airoha_eth *eth)\n static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev)\n {\n \tstruct net_device *netdev = netdev_from_priv(dev);\n+\tstruct airoha_qdma *cur_qdma, *qdma;\n \tstruct airoha_eth *eth = dev-\u003eeth;\n \tint ppe_id;\n \n \t/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */\n-\tdev-\u003eqdma = \u0026eth-\u003eqdma[!airoha_is_lan_gdm_dev(dev)];\n-\tnetdev-\u003eirq = dev-\u003eqdma-\u003eirq_banks[0].irq;\n+\tqdma = \u0026eth-\u003eqdma[!airoha_is_lan_gdm_dev(dev)];\n+\tcur_qdma = airoha_qdma_deref(dev);\n+\n+\trcu_assign_pointer(dev-\u003eqdma, qdma);\n+\tnetdev-\u003eirq = qdma-\u003eirq_banks[0].irq;\n \n \tppe_id = !airoha_is_lan_gdm_dev(dev) \u0026\u0026 airoha_ppe_is_enabled(eth, 1);\n \tairoha_ppe_set_cpu_port(dev, ppe_id, airoha_get_fe_port(dev));\n+\n+\tif (!cur_qdma)\n+\t\treturn;\n+\n+\tmemset(dev-\u003eqos_stats, 0, sizeof(dev-\u003eqos_stats));\n+\tsynchronize_rcu();\n+\tnetif_tx_wake_all_queues(netdev);\n }\n \n static int airoha_dev_init(struct net_device *netdev)\n@@ -2048,7 +2106,7 @@ static int airoha_dev_init(struct net_device *netdev)\n \t\tfallthrough;\n \tcase AIROHA_GDM2_IDX:\n \t\t/* GDM2 is always used as wan */\n-\t\tdev-\u003eflags |= AIROHA_PRIV_F_WAN;\n+\t\tdev-\u003eflags |= AIROHA_DEV_F_WAN;\n \t\tbreak;\n \tdefault:\n \t\tbreak;\n@@ -2187,9 +2245,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,\n \t\t\t\t   struct net_device *netdev)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n \tu32 nr_frags, tag, msg0, msg1, len;\n \tstruct airoha_queue_entry *e;\n+\tstruct airoha_qdma *qdma;\n \tstruct netdev_queue *txq;\n \tstruct airoha_queue *q;\n \tLIST_HEAD(tx_list);\n@@ -2198,6 +2256,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,\n \tu16 index;\n \tu8 fport;\n \n+\trcu_read_lock();\n+\tqdma = rcu_dereference(dev-\u003eqdma);\n \tqid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));\n \ttag = airoha_get_dsa_tag(skb, netdev);\n \n@@ -2247,6 +2307,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,\n \t\tnetif_tx_stop_queue(txq);\n \t\tq-\u003etxq_stopped = true;\n \t\tspin_unlock_bh(\u0026q-\u003elock);\n+\t\trcu_read_unlock();\n+\n \t\treturn NETDEV_TX_BUSY;\n \t}\n \n@@ -2309,6 +2371,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,\n \t\t\t\tFIELD_PREP(TX_RING_CPU_IDX_MASK, index));\n \n \tspin_unlock_bh(\u0026q-\u003elock);\n+\trcu_read_unlock();\n \n \treturn NETDEV_TX_OK;\n \n@@ -2324,6 +2387,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,\n error:\n \tdev_kfree_skb_any(skb);\n \tnetdev-\u003estats.tx_dropped++;\n+\trcu_read_unlock();\n \n \treturn NETDEV_TX_OK;\n }\n@@ -2403,17 +2467,19 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,\n \t\t\t\t\t const u16 *weights, u8 n_weights)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n+\tstruct airoha_qdma *qdma;\n \tint i;\n \n+\tqdma = airoha_qdma_deref(dev);\n \tfor (i = 0; i \u003c AIROHA_NUM_QOS_QUEUES; i++)\n-\t\tairoha_qdma_clear(dev-\u003eqdma, REG_QUEUE_CLOSE_CFG(channel),\n+\t\tairoha_qdma_clear(qdma, REG_QUEUE_CLOSE_CFG(channel),\n \t\t\t\t  TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i));\n \n \tfor (i = 0; i \u003c n_weights; i++) {\n \t\tu32 status;\n \t\tint err;\n \n-\t\tairoha_qdma_wr(dev-\u003eqdma, REG_TXWRR_WEIGHT_CFG,\n+\t\tairoha_qdma_wr(qdma, REG_TXWRR_WEIGHT_CFG,\n \t\t\t       TWRR_RW_CMD_MASK |\n \t\t\t       FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) |\n \t\t\t       FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) |\n@@ -2421,12 +2487,12 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,\n \t\terr = read_poll_timeout(airoha_qdma_rr, status,\n \t\t\t\t\tstatus \u0026 TWRR_RW_CMD_DONE,\n \t\t\t\t\tUSEC_PER_MSEC, 10 * USEC_PER_MSEC,\n-\t\t\t\t\ttrue, dev-\u003eqdma, REG_TXWRR_WEIGHT_CFG);\n+\t\t\t\t\ttrue, qdma, REG_TXWRR_WEIGHT_CFG);\n \t\tif (err)\n \t\t\treturn err;\n \t}\n \n-\tairoha_qdma_rmw(dev-\u003eqdma, REG_CHAN_QOS_MODE(channel \u003e\u003e 3),\n+\tairoha_qdma_rmw(qdma, REG_CHAN_QOS_MODE(channel \u003e\u003e 3),\n \t\t\tCHAN_QOS_MODE_MASK(channel),\n \t\t\t__field_prep(CHAN_QOS_MODE_MASK(channel), mode));\n \n@@ -2490,17 +2556,22 @@ static int airoha_qdma_get_tx_ets_stats(struct net_device *netdev, int channel,\n \t\t\t\t\tstruct tc_ets_qopt_offload *opt)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n+\tu32 cpu_tx_packets, fwd_tx_packets;\n+\tstruct airoha_qdma *qdma;\n+\tu64 tx_packets;\n \n-\tu64 cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel \u003c\u003c 1));\n-\tu64 fwd_tx_packets = airoha_qdma_rr(qdma,\n-\t\t\t\t\t    REG_CNTR_VAL((channel \u003c\u003c 1) + 1));\n-\tu64 tx_packets = (cpu_tx_packets - dev-\u003ecpu_tx_packets) +\n-\t\t\t (fwd_tx_packets - dev-\u003efwd_tx_packets);\n+\tqdma = airoha_qdma_deref(dev);\n+\tcpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel \u003c\u003c 1));\n+\tfwd_tx_packets = airoha_qdma_rr(qdma,\n+\t\t\t\t\tREG_CNTR_VAL((channel \u003c\u003c 1) + 1));\n+\ttx_packets = (u32)(cpu_tx_packets -\n+\t\t\t   dev-\u003eqos_stats[channel].cpu_tx_packets) +\n+\t\t     (u32)(fwd_tx_packets -\n+\t\t\t   dev-\u003eqos_stats[channel].fwd_tx_packets);\n \n \t_bstats_update(opt-\u003estats.bstats, 0, tx_packets);\n-\tdev-\u003ecpu_tx_packets = cpu_tx_packets;\n-\tdev-\u003efwd_tx_packets = fwd_tx_packets;\n+\tdev-\u003eqos_stats[channel].cpu_tx_packets = cpu_tx_packets;\n+\tdev-\u003eqos_stats[channel].fwd_tx_packets = fwd_tx_packets;\n \n \treturn 0;\n }\n@@ -2756,16 +2827,18 @@ static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev,\n \t\t\t\t\t u32 bucket_size)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n+\tstruct airoha_qdma *qdma;\n \tint i, err;\n \n+\tqdma = airoha_qdma_deref(dev);\n \tfor (i = 0; i \u003c= TRTCM_PEAK_MODE; i++) {\n-\t\terr = airoha_qdma_set_trtcm_config(dev-\u003eqdma, channel,\n+\t\terr = airoha_qdma_set_trtcm_config(qdma, channel,\n \t\t\t\t\t\t   REG_EGRESS_TRTCM_CFG, i,\n \t\t\t\t\t\t   !!rate, TRTCM_METER_MODE);\n \t\tif (err)\n \t\t\treturn err;\n \n-\t\terr = airoha_qdma_set_trtcm_token_bucket(dev-\u003eqdma, channel,\n+\t\terr = airoha_qdma_set_trtcm_token_bucket(qdma, channel,\n \t\t\t\t\t\t\t REG_EGRESS_TRTCM_CFG,\n \t\t\t\t\t\t\t i, rate, bucket_size);\n \t\tif (err)\n@@ -2801,11 +2874,12 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,\n \tu32 channel = TC_H_MIN(opt-\u003eclassid) % AIROHA_NUM_QOS_CHANNELS;\n \tint err, num_tx_queues = AIROHA_NUM_TX_RING + channel + 1;\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n+\tstruct airoha_qdma *qdma;\n \n \t/* Here we need to check the requested QDMA channel is not already\n \t * in use by another net_device running on the same QDMA block.\n \t */\n+\tqdma = airoha_qdma_deref(dev);\n \tif (test_and_set_bit(channel, qdma-\u003eqos_channel_map)) {\n \t\tNL_SET_ERR_MSG_MOD(opt-\u003eextack,\n \t\t\t\t   \"qdma qos channel already in use\");\n@@ -2841,7 +2915,7 @@ static int airoha_qdma_set_rx_meter(struct airoha_gdm_dev *dev,\n \t\t\t\t    u32 rate, u32 bucket_size,\n \t\t\t\t    enum trtcm_unit_type unit_type)\n {\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n+\tstruct airoha_qdma *qdma = airoha_qdma_deref(dev);\n \tint i;\n \n \tfor (i = 0; i \u003c ARRAY_SIZE(qdma-\u003eq_rx); i++) {\n@@ -3016,10 +3090,11 @@ static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n \tint num_tx_queues = AIROHA_NUM_TX_RING;\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n+\tstruct airoha_qdma *qdma;\n \n \tairoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0);\n \n+\tqdma = airoha_qdma_deref(dev);\n \tclear_bit(queue, qdma-\u003eqos_channel_map);\n \tclear_bit(queue, dev-\u003eqos_sq_bmap);\n \n@@ -3045,6 +3120,95 @@ static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev,\n \treturn 0;\n }\n \n+static void airoha_disable_qos_for_gdm34(struct net_device *netdev)\n+{\n+\tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n+\tstruct airoha_gdm_port *port = dev-\u003eport;\n+\tint err;\n+\n+\tif (port-\u003eid != AIROHA_GDM3_IDX \u0026\u0026\n+\t    port-\u003eid != AIROHA_GDM4_IDX)\n+\t\treturn;\n+\n+\terr = airoha_disable_gdm2_loopback(dev);\n+\tif (err)\n+\t\tnetdev_warn(netdev,\n+\t\t\t    \"failed disabling GDM2 loopback: %d\\n\", err);\n+\n+\tdev-\u003eflags \u0026= ~AIROHA_DEV_F_WAN;\n+\tairoha_dev_set_qdma(dev);\n+\n+\tairoha_set_macaddr(dev, netdev-\u003edev_addr);\n+\tif (netif_running(netdev))\n+\t\tairoha_set_gdm_port_fwd_cfg(dev-\u003eeth,\n+\t\t\t\t\t    REG_GDM_FWD_CFG(port-\u003eid),\n+\t\t\t\t\t    FE_PSE_PORT_PPE1);\n+}\n+\n+static int airoha_enable_qos_for_gdm34(struct net_device *netdev,\n+\t\t\t\t       struct netlink_ext_ack *extack)\n+{\n+\tstruct airoha_gdm_dev *wan_dev, *dev = netdev_priv(netdev);\n+\tstruct airoha_gdm_port *port = dev-\u003eport;\n+\tstruct airoha_eth *eth = dev-\u003eeth;\n+\tint err = -EBUSY;\n+\n+\tif (port-\u003eid != AIROHA_GDM3_IDX \u0026\u0026\n+\t    port-\u003eid != AIROHA_GDM4_IDX) {\n+\t\t/* HW QoS is always supported by GDM1 and GDM2 */\n+\t\treturn 0;\n+\t}\n+\n+\tif (!airoha_is_lan_gdm_dev(dev)) /* Already enabled */\n+\t\treturn 0;\n+\n+\tmutex_lock(\u0026flow_offload_mutex);\n+\n+\twan_dev = airoha_get_wan_gdm_dev(eth);\n+\tif (wan_dev) {\n+\t\tif ((wan_dev-\u003eflags \u0026 AIROHA_DEV_F_QOS) ||\n+\t\t    wan_dev-\u003eport-\u003eid == AIROHA_GDM2_IDX) {\n+\t\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t\t   \"QoS configured for WAN device\");\n+\t\t\tgoto error_unlock;\n+\t\t}\n+\t\tairoha_disable_qos_for_gdm34(netdev_from_priv(wan_dev));\n+\t}\n+\n+\tdev-\u003eflags |= AIROHA_DEV_F_WAN;\n+\tairoha_dev_set_qdma(dev);\n+\terr = airoha_enable_gdm2_loopback(dev);\n+\tif (err)\n+\t\tgoto error_disable_wan;\n+\n+\terr = airoha_set_macaddr(dev, netdev-\u003edev_addr);\n+\tif (err)\n+\t\tgoto error_disable_loopback;\n+\n+\tif (netif_running(netdev)) {\n+\t\tu32 pse_port;\n+\n+\t\tpse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2\n+\t\t\t\t\t\t\t : FE_PSE_PORT_PPE1;\n+\t\tairoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port-\u003eid),\n+\t\t\t\t\t    pse_port);\n+\t}\n+\n+\tmutex_unlock(\u0026flow_offload_mutex);\n+\n+\treturn 0;\n+\n+error_disable_loopback:\n+\tairoha_disable_gdm2_loopback(dev);\n+error_disable_wan:\n+\tdev-\u003eflags \u0026= ~AIROHA_DEV_F_WAN;\n+\tairoha_dev_set_qdma(dev);\n+error_unlock:\n+\tmutex_unlock(\u0026flow_offload_mutex);\n+\n+\treturn err;\n+}\n+\n static int airoha_tc_htb_destroy(struct net_device *netdev)\n {\n \tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n@@ -3053,6 +3217,8 @@ static int airoha_tc_htb_destroy(struct net_device *netdev)\n \tfor_each_set_bit(q, dev-\u003eqos_sq_bmap, AIROHA_NUM_QOS_CHANNELS)\n \t\tairoha_tc_remove_htb_queue(netdev, q);\n \n+\tdev-\u003eflags \u0026= ~AIROHA_DEV_F_QOS;\n+\n \treturn 0;\n }\n \n@@ -3072,24 +3238,33 @@ static int airoha_tc_get_htb_get_leaf_queue(struct net_device *netdev,\n \treturn 0;\n }\n \n-static int airoha_tc_setup_qdisc_htb(struct net_device *dev,\n+static int airoha_tc_setup_qdisc_htb(struct net_device *netdev,\n \t\t\t\t     struct tc_htb_qopt_offload *opt)\n {\n \tswitch (opt-\u003ecommand) {\n-\tcase TC_HTB_CREATE:\n+\tcase TC_HTB_CREATE: {\n+\t\tstruct airoha_gdm_dev *dev = netdev_priv(netdev);\n+\t\tint err;\n+\n+\t\terr = airoha_enable_qos_for_gdm34(netdev, opt-\u003eextack);\n+\t\tif (err)\n+\t\t\treturn err;\n+\n+\t\tdev-\u003eflags |= AIROHA_DEV_F_QOS;\n \t\tbreak;\n+\t}\n \tcase TC_HTB_DESTROY:\n-\t\treturn airoha_tc_htb_destroy(dev);\n+\t\treturn airoha_tc_htb_destroy(netdev);\n \tcase TC_HTB_NODE_MODIFY:\n-\t\treturn airoha_tc_htb_modify_queue(dev, opt);\n+\t\treturn airoha_tc_htb_modify_queue(netdev, opt);\n \tcase TC_HTB_LEAF_ALLOC_QUEUE:\n-\t\treturn airoha_tc_htb_alloc_leaf_queue(dev, opt);\n+\t\treturn airoha_tc_htb_alloc_leaf_queue(netdev, opt);\n \tcase TC_HTB_LEAF_DEL:\n \tcase TC_HTB_LEAF_DEL_LAST:\n \tcase TC_HTB_LEAF_DEL_LAST_FORCE:\n-\t\treturn airoha_tc_htb_delete_leaf_queue(dev, opt);\n+\t\treturn airoha_tc_htb_delete_leaf_queue(netdev, opt);\n \tcase TC_HTB_LEAF_QUERY_QUEUE:\n-\t\treturn airoha_tc_get_htb_get_leaf_queue(dev, opt);\n+\t\treturn airoha_tc_get_htb_get_leaf_queue(netdev, opt);\n \tdefault:\n \t\treturn -EOPNOTSUPP;\n \t}\ndiff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h\nindex d7ff8c5200e20c..a314330fcd48e2 100644\n--- a/drivers/net/ethernet/airoha/airoha_eth.h\n+++ b/drivers/net/ethernet/airoha/airoha_eth.h\n@@ -535,19 +535,21 @@ struct airoha_qdma {\n \tDECLARE_BITMAP(qos_channel_map, AIROHA_NUM_QOS_CHANNELS);\n };\n \n-enum airoha_priv_flags {\n-\tAIROHA_PRIV_F_WAN = BIT(0),\n+enum airoha_dev_flags {\n+\tAIROHA_DEV_F_WAN = BIT(0),\n+\tAIROHA_DEV_F_QOS = BIT(1),\n };\n \n struct airoha_gdm_dev {\n+\tstruct airoha_qdma __rcu *qdma;\n \tstruct airoha_gdm_port *port;\n-\tstruct airoha_qdma *qdma;\n \tstruct airoha_eth *eth;\n \n \tDECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS);\n-\t/* qos stats counters */\n-\tu64 cpu_tx_packets;\n-\tu64 fwd_tx_packets;\n+\tstruct {\n+\t\tu32 cpu_tx_packets;\n+\t\tu32 fwd_tx_packets;\n+\t} qos_stats[AIROHA_NUM_QOS_CHANNELS];\n \n \tu32 flags;\n \tint nbq;\n@@ -659,7 +661,7 @@ static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid)\n \n static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev)\n {\n-\treturn !(dev-\u003eflags \u0026 AIROHA_PRIV_F_WAN);\n+\treturn !(dev-\u003eflags \u0026 AIROHA_DEV_F_WAN);\n }\n \n static inline bool airoha_is_7581(struct airoha_eth *eth)\n@@ -676,6 +678,16 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev);\n bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,\n \t\t\t     struct airoha_gdm_dev *dev);\n \n+extern struct mutex flow_offload_mutex;\n+\n+static inline struct airoha_qdma *\n+airoha_qdma_deref(struct airoha_gdm_dev *dev)\n+{\n+\treturn rcu_dereference_protected(dev-\u003eqdma,\n+\t\t\t\t\t lockdep_rtnl_is_held() ||\n+\t\t\t\t\t lockdep_is_held(\u0026flow_offload_mutex));\n+}\n+\n void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport);\n bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);\n void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,\ndiff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c\nindex 42f4b0f21d1798..0f260c50ac3c90 100644\n--- a/drivers/net/ethernet/airoha/airoha_ppe.c\n+++ b/drivers/net/ethernet/airoha/airoha_ppe.c\n@@ -15,7 +15,10 @@\n #include \"airoha_regs.h\"\n #include \"airoha_eth.h\"\n \n-static DEFINE_MUTEX(flow_offload_mutex);\n+/* Serialize airoha_gdm_dev flags, QDMA pointer and PPE CPU port\n+ * configuration.\n+ */\n+DEFINE_MUTEX(flow_offload_mutex);\n static DEFINE_SPINLOCK(ppe_lock);\n \n static const struct rhashtable_params airoha_flow_table_params = {\n@@ -86,8 +89,8 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe)\n \n void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport)\n {\n-\tstruct airoha_qdma *qdma = dev-\u003eqdma;\n-\tstruct airoha_eth *eth = qdma-\u003eeth;\n+\tstruct airoha_qdma *qdma = airoha_qdma_deref(dev);\n+\tstruct airoha_eth *eth = dev-\u003eeth;\n \tu8 qdma_id = qdma - \u0026eth-\u003eqdma[0];\n \tu32 fe_cpu_port;\n \ndiff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h\nindex 436f3c8779c102..4e17dfbcf2b88a 100644\n--- a/drivers/net/ethernet/airoha/airoha_regs.h\n+++ b/drivers/net/ethernet/airoha/airoha_regs.h\n@@ -376,6 +376,7 @@\n \n #define REG_SRC_PORT_FC_MAP6\t\t0x2298\n #define FC_ID_OF_SRC_PORT_MASK(_n)\tGENMASK(4 + ((_n) \u003c\u003c 3), ((_n) \u003c\u003c 3))\n+#define FC_MAP6_DEF_VALUE\t\t0x1b1a1918\n \n #define REG_CDM5_RX_OQ1_DROP_CNT\t0x29d4\n \n"
}

2/1 2026/07/01 13:38 agent patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Airoha SoC ethernet driver (drivers/net/ethernet/airoha/). This is a hardware-specific platform driver that requires physical Airoha EN7581/AN7583 SoC hardware to probe and function. It cannot be reached or tested in standard virtualized environments like QEMU or GCE used by syzkaller.",
  "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).

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.
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.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. 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 834eb22ca40e2b60fa75bd16660649099b8cd14d
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Jul 1 13:38:32 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 932b3a3df2e577..609a5ea67fb743 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -929,7 +929,7 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
 			if (!dev)
 				continue;
 
-			if (dev->qdma != qdma)
+			if (rcu_access_pointer(dev->qdma) != qdma)
 				continue;
 
 			netdev = netdev_from_priv(dev);
@@ -1837,13 +1837,14 @@ static int airoha_dev_open(struct net_device *netdev)
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
 	struct airoha_gdm_port *port = dev->port;
 	u32 cur_len, pse_port = FE_PSE_PORT_PPE1;
-	struct airoha_qdma *qdma = dev->qdma;
+	struct airoha_qdma *qdma;
 
 	netif_tx_start_all_queues(netdev);
 	err = airoha_set_vip_for_gdm_port(dev, true);
 	if (err)
 		return err;
 
+	qdma = airoha_qdma_deref(dev);
 	if (netdev_uses_dsa(netdev))
 		airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
 			      GDM_STAG_EN_MASK);
@@ -1903,7 +1904,6 @@ static int airoha_dev_stop(struct net_device *netdev)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
 	struct airoha_gdm_port *port = dev->port;
-	struct airoha_qdma *qdma = dev->qdma;
 
 	netif_tx_disable(netdev);
 	airoha_set_vip_for_gdm_port(dev, false);
@@ -1911,7 +1911,7 @@ static int airoha_dev_stop(struct net_device *netdev)
 	if (--port->users)
 		airoha_set_port_mtu(dev->eth, port);
 	else
-		airoha_set_gdm_port_fwd_cfg(qdma->eth,
+		airoha_set_gdm_port_fwd_cfg(dev->eth,
 					    REG_GDM_FWD_CFG(port->id),
 					    FE_PSE_PORT_DROP);
 	return 0;
@@ -1998,6 +1998,53 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)
 	return 0;
 }
 
+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev)
+{
+	struct airoha_gdm_port *port = dev->port;
+	struct airoha_eth *eth = dev->eth;
+	int i, src_port;
+	u32 pse_port;
+
+	src_port = eth->soc->ops.get_sport(dev->port, dev->nbq);
+	if (src_port < 0)
+		return src_port;
+
+	airoha_fe_clear(eth,
+			REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)),
+			SP_CPORT_MASK(src_port & SP_CPORT_DFT_MASK));
+
+	airoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
+		      GDM_STRIP_CRC_MASK);
+	airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
+				    FE_PSE_PORT_DROP);
+	airoha_fe_clear(eth, REG_GDM_LPBK_CFG(AIROHA_GDM2_IDX),
+			LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK);
+	pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2
+						 : FE_PSE_PORT_PPE1;
+	airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
+				    pse_port);
+
+	airoha_fe_rmw(eth, REG_FE_WAN_PORT, WAN0_MASK,
+		      FIELD_PREP(WAN0_MASK, AIROHA_GDM2_IDX));
+
+	for (i = 0; i < eth->soc->num_ppe; i++)
+		airoha_fe_clear(eth, REG_PPE_DFT_CPORT(i, AIROHA_GDM2_IDX),
+				DFT_CPORT_MASK(AIROHA_GDM2_IDX));
+
+	/* Enable VIP and IFC for GDM2 */
+	airoha_fe_set(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
+	airoha_fe_set(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
+
+	if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) {
+		u32 mask = FC_ID_OF_SRC_PORT_MASK(dev->nbq);
+
+		airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, mask,
+			      FC_MAP6_DEF_VALUE & mask);
+	}
+
+	return 0;
+}
+
 static struct airoha_gdm_dev *
 airoha_get_wan_gdm_dev(struct airoha_eth *eth)
 {
@@ -2024,15 +2071,26 @@ airoha_get_wan_gdm_dev(struct airoha_eth *eth)
 static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev)
 {
 	struct net_device *netdev = netdev_from_priv(dev);
+	struct airoha_qdma *cur_qdma, *qdma;
 	struct airoha_eth *eth = dev->eth;
 	int ppe_id;
 
 	/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
-	dev->qdma = &eth->qdma[!airoha_is_lan_gdm_dev(dev)];
-	netdev->irq = dev->qdma->irq_banks[0].irq;
+	qdma = &eth->qdma[!airoha_is_lan_gdm_dev(dev)];
+	cur_qdma = airoha_qdma_deref(dev);
+
+	rcu_assign_pointer(dev->qdma, qdma);
+	netdev->irq = qdma->irq_banks[0].irq;
 
 	ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1);
 	airoha_ppe_set_cpu_port(dev, ppe_id, airoha_get_fe_port(dev));
+
+	if (!cur_qdma)
+		return;
+
+	memset(dev->qos_stats, 0, sizeof(dev->qos_stats));
+	synchronize_rcu();
+	netif_tx_wake_all_queues(netdev);
 }
 
 static int airoha_dev_init(struct net_device *netdev)
@@ -2048,7 +2106,7 @@ static int airoha_dev_init(struct net_device *netdev)
 		fallthrough;
 	case AIROHA_GDM2_IDX:
 		/* GDM2 is always used as wan */
-		dev->flags |= AIROHA_PRIV_F_WAN;
+		dev->flags |= AIROHA_DEV_F_WAN;
 		break;
 	default:
 		break;
@@ -2187,9 +2245,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
 				   struct net_device *netdev)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
-	struct airoha_qdma *qdma = dev->qdma;
 	u32 nr_frags, tag, msg0, msg1, len;
 	struct airoha_queue_entry *e;
+	struct airoha_qdma *qdma;
 	struct netdev_queue *txq;
 	struct airoha_queue *q;
 	LIST_HEAD(tx_list);
@@ -2198,6 +2256,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
 	u16 index;
 	u8 fport;
 
+	rcu_read_lock();
+	qdma = rcu_dereference(dev->qdma);
 	qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));
 	tag = airoha_get_dsa_tag(skb, netdev);
 
@@ -2247,6 +2307,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
 		netif_tx_stop_queue(txq);
 		q->txq_stopped = true;
 		spin_unlock_bh(&q->lock);
+		rcu_read_unlock();
+
 		return NETDEV_TX_BUSY;
 	}
 
@@ -2309,6 +2371,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
 				FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
 
 	spin_unlock_bh(&q->lock);
+	rcu_read_unlock();
 
 	return NETDEV_TX_OK;
 
@@ -2324,6 +2387,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
 error:
 	dev_kfree_skb_any(skb);
 	netdev->stats.tx_dropped++;
+	rcu_read_unlock();
 
 	return NETDEV_TX_OK;
 }
@@ -2403,17 +2467,19 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
 					 const u16 *weights, u8 n_weights)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
+	struct airoha_qdma *qdma;
 	int i;
 
+	qdma = airoha_qdma_deref(dev);
 	for (i = 0; i < AIROHA_NUM_QOS_QUEUES; i++)
-		airoha_qdma_clear(dev->qdma, REG_QUEUE_CLOSE_CFG(channel),
+		airoha_qdma_clear(qdma, REG_QUEUE_CLOSE_CFG(channel),
 				  TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i));
 
 	for (i = 0; i < n_weights; i++) {
 		u32 status;
 		int err;
 
-		airoha_qdma_wr(dev->qdma, REG_TXWRR_WEIGHT_CFG,
+		airoha_qdma_wr(qdma, REG_TXWRR_WEIGHT_CFG,
 			       TWRR_RW_CMD_MASK |
 			       FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) |
 			       FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) |
@@ -2421,12 +2487,12 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
 		err = read_poll_timeout(airoha_qdma_rr, status,
 					status & TWRR_RW_CMD_DONE,
 					USEC_PER_MSEC, 10 * USEC_PER_MSEC,
-					true, dev->qdma, REG_TXWRR_WEIGHT_CFG);
+					true, qdma, REG_TXWRR_WEIGHT_CFG);
 		if (err)
 			return err;
 	}
 
-	airoha_qdma_rmw(dev->qdma, REG_CHAN_QOS_MODE(channel >> 3),
+	airoha_qdma_rmw(qdma, REG_CHAN_QOS_MODE(channel >> 3),
 			CHAN_QOS_MODE_MASK(channel),
 			__field_prep(CHAN_QOS_MODE_MASK(channel), mode));
 
@@ -2490,17 +2556,22 @@ static int airoha_qdma_get_tx_ets_stats(struct net_device *netdev, int channel,
 					struct tc_ets_qopt_offload *opt)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
-	struct airoha_qdma *qdma = dev->qdma;
+	u32 cpu_tx_packets, fwd_tx_packets;
+	struct airoha_qdma *qdma;
+	u64 tx_packets;
 
-	u64 cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel << 1));
-	u64 fwd_tx_packets = airoha_qdma_rr(qdma,
-					    REG_CNTR_VAL((channel << 1) + 1));
-	u64 tx_packets = (cpu_tx_packets - dev->cpu_tx_packets) +
-			 (fwd_tx_packets - dev->fwd_tx_packets);
+	qdma = airoha_qdma_deref(dev);
+	cpu_tx_packets = airoha_qdma_rr(qdma, REG_CNTR_VAL(channel << 1));
+	fwd_tx_packets = airoha_qdma_rr(qdma,
+					REG_CNTR_VAL((channel << 1) + 1));
+	tx_packets = (u32)(cpu_tx_packets -
+			   dev->qos_stats[channel].cpu_tx_packets) +
+		     (u32)(fwd_tx_packets -
+			   dev->qos_stats[channel].fwd_tx_packets);
 
 	_bstats_update(opt->stats.bstats, 0, tx_packets);
-	dev->cpu_tx_packets = cpu_tx_packets;
-	dev->fwd_tx_packets = fwd_tx_packets;
+	dev->qos_stats[channel].cpu_tx_packets = cpu_tx_packets;
+	dev->qos_stats[channel].fwd_tx_packets = fwd_tx_packets;
 
 	return 0;
 }
@@ -2756,16 +2827,18 @@ static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev,
 					 u32 bucket_size)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
+	struct airoha_qdma *qdma;
 	int i, err;
 
+	qdma = airoha_qdma_deref(dev);
 	for (i = 0; i <= TRTCM_PEAK_MODE; i++) {
-		err = airoha_qdma_set_trtcm_config(dev->qdma, channel,
+		err = airoha_qdma_set_trtcm_config(qdma, channel,
 						   REG_EGRESS_TRTCM_CFG, i,
 						   !!rate, TRTCM_METER_MODE);
 		if (err)
 			return err;
 
-		err = airoha_qdma_set_trtcm_token_bucket(dev->qdma, channel,
+		err = airoha_qdma_set_trtcm_token_bucket(qdma, channel,
 							 REG_EGRESS_TRTCM_CFG,
 							 i, rate, bucket_size);
 		if (err)
@@ -2801,11 +2874,12 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
 	u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
 	int err, num_tx_queues = AIROHA_NUM_TX_RING + channel + 1;
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
-	struct airoha_qdma *qdma = dev->qdma;
+	struct airoha_qdma *qdma;
 
 	/* Here we need to check the requested QDMA channel is not already
 	 * in use by another net_device running on the same QDMA block.
 	 */
+	qdma = airoha_qdma_deref(dev);
 	if (test_and_set_bit(channel, qdma->qos_channel_map)) {
 		NL_SET_ERR_MSG_MOD(opt->extack,
 				   "qdma qos channel already in use");
@@ -2841,7 +2915,7 @@ static int airoha_qdma_set_rx_meter(struct airoha_gdm_dev *dev,
 				    u32 rate, u32 bucket_size,
 				    enum trtcm_unit_type unit_type)
 {
-	struct airoha_qdma *qdma = dev->qdma;
+	struct airoha_qdma *qdma = airoha_qdma_deref(dev);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
@@ -3016,10 +3090,11 @@ static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
 	int num_tx_queues = AIROHA_NUM_TX_RING;
-	struct airoha_qdma *qdma = dev->qdma;
+	struct airoha_qdma *qdma;
 
 	airoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0);
 
+	qdma = airoha_qdma_deref(dev);
 	clear_bit(queue, qdma->qos_channel_map);
 	clear_bit(queue, dev->qos_sq_bmap);
 
@@ -3045,6 +3120,95 @@ static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev,
 	return 0;
 }
 
+static void airoha_disable_qos_for_gdm34(struct net_device *netdev)
+{
+	struct airoha_gdm_dev *dev = netdev_priv(netdev);
+	struct airoha_gdm_port *port = dev->port;
+	int err;
+
+	if (port->id != AIROHA_GDM3_IDX &&
+	    port->id != AIROHA_GDM4_IDX)
+		return;
+
+	err = airoha_disable_gdm2_loopback(dev);
+	if (err)
+		netdev_warn(netdev,
+			    "failed disabling GDM2 loopback: %d\n", err);
+
+	dev->flags &= ~AIROHA_DEV_F_WAN;
+	airoha_dev_set_qdma(dev);
+
+	airoha_set_macaddr(dev, netdev->dev_addr);
+	if (netif_running(netdev))
+		airoha_set_gdm_port_fwd_cfg(dev->eth,
+					    REG_GDM_FWD_CFG(port->id),
+					    FE_PSE_PORT_PPE1);
+}
+
+static int airoha_enable_qos_for_gdm34(struct net_device *netdev,
+				       struct netlink_ext_ack *extack)
+{
+	struct airoha_gdm_dev *wan_dev, *dev = netdev_priv(netdev);
+	struct airoha_gdm_port *port = dev->port;
+	struct airoha_eth *eth = dev->eth;
+	int err = -EBUSY;
+
+	if (port->id != AIROHA_GDM3_IDX &&
+	    port->id != AIROHA_GDM4_IDX) {
+		/* HW QoS is always supported by GDM1 and GDM2 */
+		return 0;
+	}
+
+	if (!airoha_is_lan_gdm_dev(dev)) /* Already enabled */
+		return 0;
+
+	mutex_lock(&flow_offload_mutex);
+
+	wan_dev = airoha_get_wan_gdm_dev(eth);
+	if (wan_dev) {
+		if ((wan_dev->flags & AIROHA_DEV_F_QOS) ||
+		    wan_dev->port->id == AIROHA_GDM2_IDX) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "QoS configured for WAN device");
+			goto error_unlock;
+		}
+		airoha_disable_qos_for_gdm34(netdev_from_priv(wan_dev));
+	}
+
+	dev->flags |= AIROHA_DEV_F_WAN;
+	airoha_dev_set_qdma(dev);
+	err = airoha_enable_gdm2_loopback(dev);
+	if (err)
+		goto error_disable_wan;
+
+	err = airoha_set_macaddr(dev, netdev->dev_addr);
+	if (err)
+		goto error_disable_loopback;
+
+	if (netif_running(netdev)) {
+		u32 pse_port;
+
+		pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2
+							 : FE_PSE_PORT_PPE1;
+		airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id),
+					    pse_port);
+	}
+
+	mutex_unlock(&flow_offload_mutex);
+
+	return 0;
+
+error_disable_loopback:
+	airoha_disable_gdm2_loopback(dev);
+error_disable_wan:
+	dev->flags &= ~AIROHA_DEV_F_WAN;
+	airoha_dev_set_qdma(dev);
+error_unlock:
+	mutex_unlock(&flow_offload_mutex);
+
+	return err;
+}
+
 static int airoha_tc_htb_destroy(struct net_device *netdev)
 {
 	struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -3053,6 +3217,8 @@ static int airoha_tc_htb_destroy(struct net_device *netdev)
 	for_each_set_bit(q, dev->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS)
 		airoha_tc_remove_htb_queue(netdev, q);
 
+	dev->flags &= ~AIROHA_DEV_F_QOS;
+
 	return 0;
 }
 
@@ -3072,24 +3238,33 @@ static int airoha_tc_get_htb_get_leaf_queue(struct net_device *netdev,
 	return 0;
 }
 
-static int airoha_tc_setup_qdisc_htb(struct net_device *dev,
+static int airoha_tc_setup_qdisc_htb(struct net_device *netdev,
 				     struct tc_htb_qopt_offload *opt)
 {
 	switch (opt->command) {
-	case TC_HTB_CREATE:
+	case TC_HTB_CREATE: {
+		struct airoha_gdm_dev *dev = netdev_priv(netdev);
+		int err;
+
+		err = airoha_enable_qos_for_gdm34(netdev, opt->extack);
+		if (err)
+			return err;
+
+		dev->flags |= AIROHA_DEV_F_QOS;
 		break;
+	}
 	case TC_HTB_DESTROY:
-		return airoha_tc_htb_destroy(dev);
+		return airoha_tc_htb_destroy(netdev);
 	case TC_HTB_NODE_MODIFY:
-		return airoha_tc_htb_modify_queue(dev, opt);
+		return airoha_tc_htb_modify_queue(netdev, opt);
 	case TC_HTB_LEAF_ALLOC_QUEUE:
-		return airoha_tc_htb_alloc_leaf_queue(dev, opt);
+		return airoha_tc_htb_alloc_leaf_queue(netdev, opt);
 	case TC_HTB_LEAF_DEL:
 	case TC_HTB_LEAF_DEL_LAST:
 	case TC_HTB_LEAF_DEL_LAST_FORCE:
-		return airoha_tc_htb_delete_leaf_queue(dev, opt);
+		return airoha_tc_htb_delete_leaf_queue(netdev, opt);
 	case TC_HTB_LEAF_QUERY_QUEUE:
-		return airoha_tc_get_htb_get_leaf_queue(dev, opt);
+		return airoha_tc_get_htb_get_leaf_queue(netdev, opt);
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index d7ff8c5200e20c..a314330fcd48e2 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -535,19 +535,21 @@ struct airoha_qdma {
 	DECLARE_BITMAP(qos_channel_map, AIROHA_NUM_QOS_CHANNELS);
 };
 
-enum airoha_priv_flags {
-	AIROHA_PRIV_F_WAN = BIT(0),
+enum airoha_dev_flags {
+	AIROHA_DEV_F_WAN = BIT(0),
+	AIROHA_DEV_F_QOS = BIT(1),
 };
 
 struct airoha_gdm_dev {
+	struct airoha_qdma __rcu *qdma;
 	struct airoha_gdm_port *port;
-	struct airoha_qdma *qdma;
 	struct airoha_eth *eth;
 
 	DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS);
-	/* qos stats counters */
-	u64 cpu_tx_packets;
-	u64 fwd_tx_packets;
+	struct {
+		u32 cpu_tx_packets;
+		u32 fwd_tx_packets;
+	} qos_stats[AIROHA_NUM_QOS_CHANNELS];
 
 	u32 flags;
 	int nbq;
@@ -659,7 +661,7 @@ static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid)
 
 static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev)
 {
-	return !(dev->flags & AIROHA_PRIV_F_WAN);
+	return !(dev->flags & AIROHA_DEV_F_WAN);
 }
 
 static inline bool airoha_is_7581(struct airoha_eth *eth)
@@ -676,6 +678,16 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev);
 bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
 			     struct airoha_gdm_dev *dev);
 
+extern struct mutex flow_offload_mutex;
+
+static inline struct airoha_qdma *
+airoha_qdma_deref(struct airoha_gdm_dev *dev)
+{
+	return rcu_dereference_protected(dev->qdma,
+					 lockdep_rtnl_is_held() ||
+					 lockdep_is_held(&flow_offload_mutex));
+}
+
 void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport);
 bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
 void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 42f4b0f21d1798..0f260c50ac3c90 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -15,7 +15,10 @@
 #include "airoha_regs.h"
 #include "airoha_eth.h"
 
-static DEFINE_MUTEX(flow_offload_mutex);
+/* Serialize airoha_gdm_dev flags, QDMA pointer and PPE CPU port
+ * configuration.
+ */
+DEFINE_MUTEX(flow_offload_mutex);
 static DEFINE_SPINLOCK(ppe_lock);
 
 static const struct rhashtable_params airoha_flow_table_params = {
@@ -86,8 +89,8 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe)
 
 void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport)
 {
-	struct airoha_qdma *qdma = dev->qdma;
-	struct airoha_eth *eth = qdma->eth;
+	struct airoha_qdma *qdma = airoha_qdma_deref(dev);
+	struct airoha_eth *eth = dev->eth;
 	u8 qdma_id = qdma - &eth->qdma[0];
 	u32 fe_cpu_port;
 
diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
index 436f3c8779c102..4e17dfbcf2b88a 100644
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -376,6 +376,7 @@
 
 #define REG_SRC_PORT_FC_MAP6		0x2298
 #define FC_ID_OF_SRC_PORT_MASK(_n)	GENMASK(4 + ((_n) << 3), ((_n) << 3))
+#define FC_MAP6_DEF_VALUE		0x1b1a1918
 
 #define REG_CDM5_RX_OQ1_DROP_CNT	0x29d4
 

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

Args:
null

Results:
null

Tokens:
							input: 10104
							output: 34
							thoughts: 305
						

Thoughts:
**Analyzing the Airoha Ethernet Driver Patch**

Okay, so I've got this patch affecting the `airoha` ethernet driver, specifically in `drivers/net/ethernet/airoha/`. Immediately, I see it's a functional change, which always warrants a closer look. The patch introduces RCU protection for `dev->qdma` – always a good sign for potential concurrency issues and performance tuning. They're using the standard RCU primitives: `rcu_access_pointer`, `rcu_assign_pointer`, etc. Good practice. I also see additions of functions like `airoha_disable_gdm2_loopback`, `airoha_disable_qos_for_gdm34`, and `airoha_enable_qos_for_gdm34`. These likely relate to specific hardware features or configurations. The patch then tweaks QoS configuration and HTB setup in `airoha_tc_setup_qdisc_htb`, and adds a `flow_offload_mutex` to protect `dev->qdma` and related flags.

Functionally, these changes are all about improving the driver’s concurrency and potentially adding or modifying Quality of Service features. Before I dig too deep, I need to know if this is even relevant in a virtualized environment. The driver, as I understand it, targets Airoha EN7581 SoCs. Those are embedded systems.

So, the big question is, can I even *test* this in QEMU? These SoC-specific ethernet drivers are often a pain. They usually won't probe unless there's a dedicated emulator for the SoC, which is a rare occurrence. I need to quickly determine if it's a platform driver that's going to rely on specific hardware, or if there's any chance it's a PCI driver or something that could be emulated. I'll check `drivers/net/ethernet/airoha/Kconfig` or `drivers/net/ethernet/airoha/airoha_eth.c` to see how it's defined and how it's probed. From there, I can determine the feasibility of investigating the changes in my own environment.



4/2 2026/07/01 13:38 tool grepper
0m Args:
{
  "Expression": "module_.*driver",
  "PathPrefix": "drivers/net/ethernet/airoha/"
}

Results:
{
  "Output": "drivers/net/ethernet/airoha/airoha_eth.c=3903=static struct platform_driver airoha_driver = {\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-3910-};\ndrivers/net/ethernet/airoha/airoha_eth.c:3911:module_platform_driver(airoha_driver);\ndrivers/net/ethernet/airoha/airoha_eth.c-3912-\n--\ndrivers/net/ethernet/airoha/airoha_npu.c=813=static struct platform_driver airoha_npu_driver = {\n--\ndrivers/net/ethernet/airoha/airoha_npu.c-820-};\ndrivers/net/ethernet/airoha/airoha_npu.c:821:module_platform_driver(airoha_npu_driver);\ndrivers/net/ethernet/airoha/airoha_npu.c-822-\n"
}

5/2 2026/07/01 13:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11162
							output: 32
							thoughts: 46
						

Thoughts:
**Analyzing the Platform Driver**

Okay, so this is a platform driver, interesting. My initial thought is to figure out the best way to interact with it, and since I'm assuming QEMU is our testing environment, let's explore that. My first instinct is to see if we can probe it. The key question is how this driver gets instantiated. Is it handled by some generic platform initialization code, or does it depend on the device tree? Understanding that will dictate my probing strategy in QEMU. Determining the instantiation method is crucial to efficient and effective analysis.



6/2 2026/07/01 13:39 tool grepper
0m Args:
{
  "Expression": "\\.compatible",
  "PathPrefix": "drivers/net/ethernet/airoha/"
}

Results:
{
  "Output": "drivers/net/ethernet/airoha/airoha_eth.c=3896=static const struct of_device_id of_airoha_match[] = {\ndrivers/net/ethernet/airoha/airoha_eth.c:3897:\t{ .compatible = \"airoha,en7581-eth\", .data = \u0026en7581_soc_data },\ndrivers/net/ethernet/airoha/airoha_eth.c:3898:\t{ .compatible = \"airoha,an7583-eth\", .data = \u0026an7583_soc_data },\ndrivers/net/ethernet/airoha/airoha_eth.c-3899-\t{ /* sentinel */ }\n--\ndrivers/net/ethernet/airoha/airoha_npu.c=678=static const struct of_device_id of_airoha_npu_match[] = {\ndrivers/net/ethernet/airoha/airoha_npu.c:679:\t{ .compatible = \"airoha,en7581-npu\", .data = \u0026en7581_npu_soc_data },\ndrivers/net/ethernet/airoha/airoha_npu.c:680:\t{ .compatible = \"airoha,an7583-npu\", .data = \u0026an7583_npu_soc_data },\ndrivers/net/ethernet/airoha/airoha_npu.c-681-\t{ /* sentinel */ }\n"
}

7/2 2026/07/01 13:39 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11738
							output: 32
							thoughts: 285
						

Thoughts:
**Analyzing the Platform Driver's Fuzzability**

Okay, so I'm looking at this platform driver, and my initial thought is, how easily can Syzkaller get at this? The fact that it's using the device tree (`of_device_id`) is a good start. I know Syzkaller can inject platform devices through functions like `syz_dev_ipv4_setup` or even by mounting an image with a custom DTB. But generally, Syzkaller doesn't just randomly hit platform drivers unless they are explicitly targeted or part of a generic subsystem.

Wait, did I miss something? Does Syzkaller have a way to generate a fake device tree or can we use `syz_gen_platform_device`? No, it doesn't have a *general* mechanism for probing all platform drivers. But, I remember that Syzkaller *can* fuzz platform drivers if they are already instantiated.

But then there is that note about inaccessible code paths in virtualized environments like GCE or QEMU, even with emulated hardware like USB gadgets and mac80211_hwsim. This is a platform driver specifically for the Airoha EN7581/AN7583 SoC, so it is going to need specific hardware registers, clocks, resets, etc., which are not emulated in QEMU. That is definitely a blocker.

Alright, let's see if this driver is using `devm_ioremap_resource` or something similar. If it does, and the physical address isn't backed by RAM or the emulator, that would be a clear fail, wouldn't it? That would be a simple way to figure this out.



8/2 2026/07/01 13:39 tool grepper
0m Args:
{
  "Expression": "ioremap",
  "PathPrefix": "drivers/net/ethernet/airoha/"
}

Results:
{
  "Output": "drivers/net/ethernet/airoha/airoha_eth.c=1512=static int airoha_qdma_init(struct platform_device *pdev,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-1523-\ndrivers/net/ethernet/airoha/airoha_eth.c:1524:\tqdma-\u003eregs = devm_platform_ioremap_resource_byname(pdev, res);\ndrivers/net/ethernet/airoha/airoha_eth.c-1525-\tif (IS_ERR(qdma-\u003eregs))\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=3538=static int airoha_probe(struct platform_device *pdev)\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-3560-\ndrivers/net/ethernet/airoha/airoha_eth.c:3561:\teth-\u003efe_regs = devm_platform_ioremap_resource_byname(pdev, \"fe\");\ndrivers/net/ethernet/airoha/airoha_eth.c-3562-\tif (IS_ERR(eth-\u003efe_regs))\n--\ndrivers/net/ethernet/airoha/airoha_npu.c=245=static int airoha_npu_run_firmware(struct device *dev, void __iomem *base,\n--\ndrivers/net/ethernet/airoha/airoha_npu.c-255-\ndrivers/net/ethernet/airoha/airoha_npu.c:256:\taddr = devm_ioremap_resource(dev, res);\ndrivers/net/ethernet/airoha/airoha_npu.c-257-\tif (IS_ERR(addr))\n--\ndrivers/net/ethernet/airoha/airoha_npu.c=430=static int airoha_npu_ppe_stats_setup(struct airoha_npu *npu,\n--\ndrivers/net/ethernet/airoha/airoha_npu.c-449-\ndrivers/net/ethernet/airoha/airoha_npu.c:450:\tnpu-\u003estats = devm_ioremap(npu-\u003edev,\ndrivers/net/ethernet/airoha/airoha_npu.c-451-\t\t\t\t  ppe_data-\u003estats_info.npu_stats_addr,\n--\ndrivers/net/ethernet/airoha/airoha_npu.c=693=static int airoha_npu_probe(struct platform_device *pdev)\n--\ndrivers/net/ethernet/airoha/airoha_npu.c-701-\ndrivers/net/ethernet/airoha/airoha_npu.c:702:\tbase = devm_platform_ioremap_resource(pdev, 0);\ndrivers/net/ethernet/airoha/airoha_npu.c-703-\tif (IS_ERR(base))\n"
}

9/2 2026/07/01 13:39 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13175
							output: 35
							thoughts: 118
						

Thoughts:
**Analyzing the Virtualization Challenge**

Okay, so I'm looking at this driver, and it's using `devm_platform_ioremap_resource_byname`. That screams "physical memory mapping," doesn't it? My immediate concern is the virtualized environment. Without specific emulation for this particular SoC, probing this driver is almost guaranteed to bomb out. Even if we somehow manage to trick the system into thinking the device tree node exists, accessing that mapped memory is a recipe for disaster. We're looking at potential faults, garbage data (all zeros or ones), and a probable early exit from the driver initialization, maybe it's waiting for a hardware reset or reading a specific hardware ID, either way, it'll fail.

The key now is to dig into the `airoha_probe` function. I need to pinpoint exactly *where* this driver might be making those fatal hardware reads. If I can understand the exact sequence of events, I can better assess the likelihood of success and identify potential workarounds (or conclude that this is a dead end for virtualization without significant emulation). Let's see what `airoha_probe` is actually doing.



10/2 2026/07/01 13:39 tool grepper
0m Args:
{
  "Expression": "read_poll_timeout",
  "PathPrefix": "drivers/net/ethernet/airoha/"
}

Results:
{
  "Output": "drivers/net/ethernet/airoha/airoha_eth.c=403=static int airoha_fe_mc_vlan_clear(struct airoha_eth *eth)\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-415-\t\tairoha_fe_wr(eth, REG_MC_VLAN_CFG, val);\ndrivers/net/ethernet/airoha/airoha_eth.c:416:\t\terr = read_poll_timeout(airoha_fe_rr, val,\ndrivers/net/ethernet/airoha/airoha_eth.c-417-\t\t\t\t\tval \u0026 MC_VLAN_CFG_CMD_DONE_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-429-\t\t\tairoha_fe_wr(eth, REG_MC_VLAN_CFG, val);\ndrivers/net/ethernet/airoha/airoha_eth.c:430:\t\t\terr = read_poll_timeout(airoha_fe_rr, val,\ndrivers/net/ethernet/airoha/airoha_eth.c-431-\t\t\t\t\t\tval \u0026 MC_VLAN_CFG_CMD_DONE_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=1151=static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma)\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-1157-\t\t\t  GLOBAL_CFG_TX_DMA_EN_MASK);\ndrivers/net/ethernet/airoha/airoha_eth.c:1158:\tif (read_poll_timeout(airoha_qdma_rr, status,\ndrivers/net/ethernet/airoha/airoha_eth.c-1159-\t\t\t      !(status \u0026 GLOBAL_CFG_TX_DMA_BUSY_MASK),\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=1223=static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-1286-\ndrivers/net/ethernet/airoha/airoha_eth.c:1287:\treturn read_poll_timeout(airoha_qdma_rr, status,\ndrivers/net/ethernet/airoha/airoha_eth.c-1288-\t\t\t\t !(status \u0026 LMGR_INIT_START), USEC_PER_MSEC,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=1548=static void airoha_qdma_cleanup(struct airoha_eth *eth,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-1557-\t\t\t\t  GLOBAL_CFG_RX_DMA_EN_MASK);\ndrivers/net/ethernet/airoha/airoha_eth.c:1558:\t\tif (read_poll_timeout(airoha_qdma_rr, status,\ndrivers/net/ethernet/airoha/airoha_eth.c-1559-\t\t\t\t      !(status \u0026 GLOBAL_CFG_RX_DMA_BUSY_MASK),\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=2465=static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-2486-\t\t\t       FIELD_PREP(TWRR_VALUE_MASK, weights[i]));\ndrivers/net/ethernet/airoha/airoha_eth.c:2487:\t\terr = read_poll_timeout(airoha_qdma_rr, status,\ndrivers/net/ethernet/airoha/airoha_eth.c-2488-\t\t\t\t\tstatus \u0026 TWRR_RW_CMD_DONE,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=2603=static int airoha_qdma_get_rl_param(struct airoha_qdma *qdma, int queue_id,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-2612-\tairoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);\ndrivers/net/ethernet/airoha/airoha_eth.c:2613:\tif (read_poll_timeout(airoha_qdma_rr, val,\ndrivers/net/ethernet/airoha/airoha_eth.c-2614-\t\t\t      val \u0026 RATE_LIMIT_PARAM_RW_DONE_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=2626=static int airoha_qdma_set_rl_param(struct airoha_qdma *qdma, int queue_id,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-2638-\ndrivers/net/ethernet/airoha/airoha_eth.c:2639:\treturn read_poll_timeout(airoha_qdma_rr, val,\ndrivers/net/ethernet/airoha/airoha_eth.c-2640-\t\t\t\t val \u0026 RATE_LIMIT_PARAM_RW_DONE_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=2722=static int airoha_qdma_get_trtcm_param(struct airoha_qdma *qdma, int channel,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-2733-\tairoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);\ndrivers/net/ethernet/airoha/airoha_eth.c:2734:\tif (read_poll_timeout(airoha_qdma_rr, val,\ndrivers/net/ethernet/airoha/airoha_eth.c-2735-\t\t\t      val \u0026 TRTCM_PARAM_RW_DONE_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=2747=static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel,\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-2760-\ndrivers/net/ethernet/airoha/airoha_eth.c:2761:\treturn read_poll_timeout(airoha_qdma_rr, val,\ndrivers/net/ethernet/airoha/airoha_eth.c-2762-\t\t\t\t val \u0026 TRTCM_PARAM_RW_DONE_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_npu.c=163=static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,\n--\ndrivers/net/ethernet/airoha/airoha_npu.c-184-\ndrivers/net/ethernet/airoha/airoha_npu.c:185:\tret = regmap_read_poll_timeout_atomic(npu-\u003eregmap,\ndrivers/net/ethernet/airoha/airoha_npu.c-186-\t\t\t\t\t      REG_CR_MBQ0_CTRL(3) + offset,\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c=661=airoha_ppe_foe_get_entry_locked(struct airoha_ppe *ppe, u32 hash)\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c-676-\t\t\t     PPE_SRAM_CTRL_REQ_MASK);\ndrivers/net/ethernet/airoha/airoha_ppe.c:677:\t\tif (read_poll_timeout_atomic(airoha_fe_rr, val,\ndrivers/net/ethernet/airoha/airoha_ppe.c-678-\t\t\t\t\t     val \u0026 PPE_SRAM_CTRL_ACK_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c=721=static int airoha_ppe_foe_commit_sram_entry(struct airoha_ppe *ppe, u32 hash)\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c-735-\ndrivers/net/ethernet/airoha/airoha_ppe.c:736:\treturn read_poll_timeout_atomic(airoha_fe_rr, val,\ndrivers/net/ethernet/airoha/airoha_ppe.c-737-\t\t\t\t\tval \u0026 PPE_SRAM_CTRL_ACK_MASK,\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c=1386=static int airoha_ppe_wait_for_npu_init(struct airoha_eth *eth)\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c-1394-\t */\ndrivers/net/ethernet/airoha/airoha_ppe.c:1395:\terr = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,\ndrivers/net/ethernet/airoha/airoha_ppe.c-1396-\t\t\t\t100 * USEC_PER_MSEC, false, eth,\n--\ndrivers/net/ethernet/airoha/airoha_ppe.c-1401-\tif (airoha_ppe_is_enabled(eth, 1))\ndrivers/net/ethernet/airoha/airoha_ppe.c:1402:\t\terr = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,\ndrivers/net/ethernet/airoha/airoha_ppe.c-1403-\t\t\t\t\t100 * USEC_PER_MSEC, false, eth,\n"
}

11/2 2026/07/01 13:39 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16037
							output: 31
							thoughts: 357
						

Thoughts:
**WorthFuzzing=False: Airoha Ethernet Driver**

Okay, so I'm looking at this patch and, yes, I'm seeing a bunch of `read_poll_timeout` calls directly interacting with hardware registers. In a virtualized setup, those are just going to timeout and fail – no surprise there. Wait a second, could this driver be getting some kind of mock device treatment from syzkaller? But, no, syzkaller doesn't have a mock for this specific Airoha ethernet.

Alright, but I have to be absolutely sure. Let me confirm this patch isn't touching any broad, generic code. The good news is, from what I can tell, it's all contained within `drivers/net/ethernet/airoha/`. Specifically, I see changes in `airoha_eth.c`, `airoha_eth.h`, `airoha_ppe.c`, and `airoha_regs.h`. That makes this hardware-specific, right? Exactly.

Considering this is an Airoha EN7581 SoC ethernet driver, that code won't run without the physical SoC or a specific QEMU machine model that emulates it. Standard syzkaller instances on x86_64 or arm64 QEMU/GCE don't have this, so the code paths are unreachable.

Now, let me just double-check the instructions. "Return WorthFuzzing=false if the patch only contains code paths that are impossible to reach in virtualized environments like GCE or QEMU."

That's it then. The standard syzkaller setup won't be able to reach this Airoha driver. It needs a special QEMU machine model, or the actual hardware. I'll need to confirm there's no software emulation available for Airoha ethernet in the kernel, but assuming there isn't, this isn't worth fuzzing with current infrastructure. WorthFuzzing=false.



12/2 2026/07/01 13:39 tool grepper
0m Args:
{
  "Expression": "airoha",
  "PathPrefix": "drivers/net/ethernet/Kconfig"
}

Results:
{
  "Output": "drivers/net/ethernet/Kconfig=22=source \"drivers/net/ethernet/agere/Kconfig\"\ndrivers/net/ethernet/Kconfig:23:source \"drivers/net/ethernet/airoha/Kconfig\"\ndrivers/net/ethernet/Kconfig-24-source \"drivers/net/ethernet/alacritech/Kconfig\"\n"
}

13/2 2026/07/01 13:39 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16949
							output: 33
							thoughts: 23
						

Thoughts:
Here's my thought process, as it went:

**Examining Kconfig Dependencies**

Okay, I need to understand the dependencies for this Airoha Ethernet driver configuration. Let's start with `drivers/net/ethernet/airoha/Kconfig`. That's where I would expect to find the configuration options and their relationships to other parts of the system. I'm assuming that Kconfig file contains all the necessary information to determine what other components are required for this driver to function correctly, right? This is standard procedure for understanding the build system and ensuring that I'm considering all relevant settings. Time to see what I can find.



14/2 2026/07/01 13:39 tool grepper
0m Args:
{
  "Expression": ".*",
  "PathPrefix": "drivers/net/ethernet/airoha/Kconfig"
}

Results:
{
  "Output": "drivers/net/ethernet/airoha/Kconfig:1:# SPDX-License-Identifier: GPL-2.0-only\ndrivers/net/ethernet/airoha/Kconfig:2:config NET_VENDOR_AIROHA\ndrivers/net/ethernet/airoha/Kconfig:3:\tbool \"Airoha devices\"\ndrivers/net/ethernet/airoha/Kconfig:4:\tdepends on ARCH_AIROHA || COMPILE_TEST\ndrivers/net/ethernet/airoha/Kconfig:5:\thelp\ndrivers/net/ethernet/airoha/Kconfig:6:\t  If you have a Airoha SoC with ethernet, say Y.\ndrivers/net/ethernet/airoha/Kconfig:7:\ndrivers/net/ethernet/airoha/Kconfig:8:if NET_VENDOR_AIROHA\ndrivers/net/ethernet/airoha/Kconfig:9:\ndrivers/net/ethernet/airoha/Kconfig:10:config NET_AIROHA_NPU\ndrivers/net/ethernet/airoha/Kconfig:11:\ttristate \"Airoha NPU support\"\ndrivers/net/ethernet/airoha/Kconfig:12:\tselect WANT_DEV_COREDUMP\ndrivers/net/ethernet/airoha/Kconfig:13:\tselect REGMAP_MMIO\ndrivers/net/ethernet/airoha/Kconfig:14:\thelp\ndrivers/net/ethernet/airoha/Kconfig:15:\t  This driver supports Airoha Network Processor (NPU) available\ndrivers/net/ethernet/airoha/Kconfig:16:\t  on the Airoha Soc family.\ndrivers/net/ethernet/airoha/Kconfig:17:\ndrivers/net/ethernet/airoha/Kconfig:18:config NET_AIROHA\ndrivers/net/ethernet/airoha/Kconfig:19:\ttristate \"Airoha SoC Gigabit Ethernet support\"\ndrivers/net/ethernet/airoha/Kconfig:20:\tdepends on NET_DSA || !NET_DSA\ndrivers/net/ethernet/airoha/Kconfig:21:\tselect NET_AIROHA_NPU\ndrivers/net/ethernet/airoha/Kconfig:22:\tselect PAGE_POOL\ndrivers/net/ethernet/airoha/Kconfig:23:\thelp\ndrivers/net/ethernet/airoha/Kconfig:24:\t  This driver supports the gigabit ethernet MACs in the\ndrivers/net/ethernet/airoha/Kconfig:25:\t  Airoha SoC family.\ndrivers/net/ethernet/airoha/Kconfig:26:\ndrivers/net/ethernet/airoha/Kconfig:27:config NET_AIROHA_FLOW_STATS\ndrivers/net/ethernet/airoha/Kconfig:28:\tdefault y\ndrivers/net/ethernet/airoha/Kconfig:29:\tbool \"Airoha flow stats\"\ndrivers/net/ethernet/airoha/Kconfig:30:\tdepends on NET_AIROHA \u0026\u0026 NET_AIROHA_NPU\ndrivers/net/ethernet/airoha/Kconfig:31:\thelp\ndrivers/net/ethernet/airoha/Kconfig:32:\t  Enable Airoha flowtable statistic counters.\ndrivers/net/ethernet/airoha/Kconfig:33:\ndrivers/net/ethernet/airoha/Kconfig:34:endif #NET_VENDOR_AIROHA\n"
}

15/2 2026/07/01 13:39 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 17984
							output: 108
							thoughts: 150
						

Thoughts:
**My Assessment: Not Worth Fuzzing**

Okay, let's break this down. From what I can see, this patch's effectiveness hinges entirely on either `ARCH_AIROHA` or `COMPILE_TEST`. Now, Syzkaller, in theory, *could* build this with `COMPILE_TEST` enabled. However, that's where the good news ends. The real sticking point is that `COMPILE_TEST` isn't enough; we need the actual Airoha hardware, or a very specific QEMU setup that precisely emulates the `ARCH_AIROHA` architecture. Unfortunately, as we know, Syzkaller doesn't use that level of specialized QEMU configuration for our standard fuzzing runs.

So, in short, this patch is dead in the water from a fuzzing perspective, at least in our current setup. It's modifying code paths that are inherently unreachable in environments like GCE or the QEMU configurations we are using. It is modifying a hardware-specific ethernet driver (Airoha SoC), and we have no ability to effectively probe or reach that driver in our standard virtualized fuzzing setups.

Therefore, I'm going to return `WorthFuzzing=false`. The reasoning is straightforward: this modifies a hardware-specific driver, meaning it's impossible to efficiently test in GCE or QEMU using our standard configurations. We can't actually trigger the code this patch touches. We should not waste our cycles on this.



16/2 2026/07/01 13:39 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Airoha SoC ethernet driver (drivers/net/ethernet/airoha/). This is a hardware-specific platform driver that requires physical Airoha EN7581/AN7583 SoC hardware to probe and function. It cannot be reached or tested in standard virtualized environments like QEMU or GCE used by syzkaller.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Airoha SoC ethernet driver (drivers/net/ethernet/airoha/). This is a hardware-specific platform driver that requires physical Airoha EN7581/AN7583 SoC hardware to probe and function. It cannot be reached or tested in standard virtualized environments like QEMU or GCE used by syzkaller.",
  "WorthFuzzing": false
}

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)