AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/10/07 09:06 flow patch-triage
11m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The changes are entirely confined to the Broadcom GENET Ethernet driver (drivers/net/ethernet/broadcom/genet/). Broadcom GENET is an on-SoC MAC found in Broadcom BCM7xxx and BCM2711 (Raspberry Pi 4) architectures. It is a platform driver requiring specific MMIO and IRQ resources that are not present or emulated in standard virtualized environments (QEMU/GCE) on the target architecture (amd64). Because the hardware is structurally unreachable, syzkaller cannot execute this code.",
  "WorthFuzzing": false
}

1/1 2026/10/07 09:06 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 8af23543570fde3af2cc0d011261880e1218abc2\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Oct 7 09:06:34 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c\nindex 4c9db2f9fc25f..80215b5c00630 100644\n--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c\n+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c\n@@ -48,17 +48,44 @@\n #define GENET_Q0_TX_BD_CNT\t\\\n \t(TOTAL_DESC - priv-\u003ehw_params-\u003etx_queues * priv-\u003ehw_params-\u003etx_bds_per_q)\n \n-#define RX_BUF_LENGTH\t\t2048\n #define SKB_ALIGNMENT\t\t32\n \n+/* RBUF and TBUF hand a frame to the DMA once the threshold is reached. Both\n+ * registers are 8 bit in units of 16 bytes and want a multiple of the 256\n+ * byte burst size, so 0xf0 is the largest usable value.\n+ */\n+#define ENET_THLD_UNIT\t\t16\n+#define ENET_THLD_BURST\t\t256\n+#define ENET_THLD_DEFAULT\t0x80\n+#define ENET_THLD_MAX\t\t0xf0\n+\n+/* A frame ending just past the transmit threshold stops the transmitter once\n+ * a shorter frame follows, so pad frames that land there this far past it.\n+ */\n+#define ENET_TX_SAFE_MARGIN\t64\n+\n /* Page pool RX buffer layout:\n  * RSB(64) + pad(2) | frame data | skb_shared_info\n- * The HW writes the 64B RSB + 2B alignment padding before the frame.\n+ * The HW writes the 64B RSB before every descriptor of a frame. Only the\n+ * first one also gets the 2B alignment padding.\n  */\n-#define GENET_RSB_PAD\t\t(sizeof(struct status_64) + 2)\n+#define GENET_RBUF_ALIGN\t2\n+#define GENET_RSB_PAD\t\t(sizeof(struct status_64) + GENET_RBUF_ALIGN)\n \n-/* RX buffer plus the skb_shared_info napi_build_skb() places behind it */\n-#define GENET_RX_BUF_SIZE\tSKB_HEAD_ALIGN(RX_BUF_LENGTH)\n+/* A descriptor never spans more than one page, which also holds\n+ * skb_shared_info behind the frame, so on 4K pages the page bounds the\n+ * threshold before the register does. Larger pages fit several descriptors.\n+ */\n+#define ENET_SHINFO_LEN\t\tSKB_DATA_ALIGN(sizeof(struct skb_shared_info))\n+#define ENET_THLD_PAGE_LEN\tround_down(PAGE_SIZE - ENET_SHINFO_LEN - \\\n+\t\t\t\t\t   sizeof(struct status_64), \\\n+\t\t\t\t\t   ENET_THLD_BURST)\n+#define ENET_THLD_MAX_LEN\tmin_t(unsigned int, \\\n+\t\t\t\t      ENET_THLD_MAX * ENET_THLD_UNIT, \\\n+\t\t\t\t      ENET_THLD_PAGE_LEN)\n+\n+/* UMAC_MAX_FRAME_LEN is 14 bits wide and counts the FCS */\n+#define ENET_MAX_JUMBO_MTU\t(GENMASK(13, 0) - ENET_FRAME_OVERHEAD)\n \n /* Tx/Rx DMA register offset, skip 256 descriptors */\n #define WORDS_PER_BD(p)\t\t(p-\u003ehw_params-\u003ewords_per_bd)\n@@ -2119,6 +2146,15 @@ static void bcmgenet_hide_tsb(struct sk_buff *skb)\n \t__skb_pull(skb, sizeof(struct status_64));\n }\n \n+static void bcmgenet_tx_kick(struct bcmgenet_priv *priv,\n+\t\t\t     struct bcmgenet_tx_ring *ring,\n+\t\t\t     struct netdev_queue *txq)\n+{\n+\tif (!netdev_xmit_more() || netif_xmit_stopped(txq))\n+\t\tbcmgenet_tdma_ring_writel(priv, ring-\u003eindex,\n+\t\t\t\t\t  ring-\u003eprod_index, TDMA_PROD_INDEX);\n+}\n+\n static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n {\n \tstruct bcmgenet_priv *priv = netdev_priv(dev);\n@@ -2148,6 +2184,29 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n \t\tgoto out;\n \t}\n \n+\t/* The MAC holds a frame to insert its checksum, but only as much as\n+\t * its FIFO takes. Longer frames are dropped silently.\n+\t */\n+\tif (unlikely(skb-\u003elen \u003e priv-\u003etx_thld_len) \u0026\u0026\n+\t    skb-\u003eip_summed == CHECKSUM_PARTIAL) {\n+\t\tif (skb_checksum_help(skb)) {\n+\t\t\tBCMGENET_STATS64_INC((\u0026ring-\u003estats64), dropped);\n+\t\t\tdev_kfree_skb_any(skb);\n+\t\t\tgoto drop;\n+\t\t}\n+\t}\n+\n+\t/* Keep the frame out of the window just past the threshold */\n+\tif (unlikely(skb-\u003elen \u003e priv-\u003etx_thld_len \u0026\u0026\n+\t\t     skb-\u003elen \u003c priv-\u003etx_thld_len + ENET_TX_SAFE_MARGIN)) {\n+\t\tif (skb_put_padto(skb, priv-\u003etx_thld_len + ENET_TX_SAFE_MARGIN)) {\n+\t\t\tBCMGENET_STATS64_INC((\u0026ring-\u003estats64), dropped);\n+\t\t\tgoto drop;\n+\t\t}\n+\t}\n+\n+\tnr_frags = skb_shinfo(skb)-\u003enr_frags;\n+\n \t/* Retain how many bytes will be sent on the wire, without TSB inserted\n \t * by transmit checksum offload\n \t */\n@@ -2155,10 +2214,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n \n \t/* add the Transmit Status Block */\n \tskb = bcmgenet_add_tsb(dev, skb, ring);\n-\tif (!skb) {\n-\t\tret = NETDEV_TX_OK;\n-\t\tgoto out;\n-\t}\n+\tif (!skb)\n+\t\tgoto drop;\n \n \tfor (i = 0; i \u003c= nr_frags; i++) {\n \t\ttx_cb_ptr = bcmgenet_get_txcb(priv, ring);\n@@ -2183,7 +2240,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n \t\tif (ret) {\n \t\t\tpriv-\u003emib.tx_dma_failed++;\n \t\t\tnetif_err(priv, tx_err, dev, \"Tx DMA map failed\\n\");\n-\t\t\tret = NETDEV_TX_OK;\n \t\t\tgoto out_unmap_frags;\n \t\t}\n \t\tdma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);\n@@ -2225,10 +2281,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n \tif (ring-\u003efree_bds \u003c= (MAX_SKB_FRAGS + 1))\n \t\tnetif_tx_stop_queue(txq);\n \n-\tif (!netdev_xmit_more() || netif_xmit_stopped(txq))\n-\t\t/* Packets are ready, update producer index */\n-\t\tbcmgenet_tdma_ring_writel(priv, ring-\u003eindex,\n-\t\t\t\t\t  ring-\u003eprod_index, TDMA_PROD_INDEX);\n+\tbcmgenet_tx_kick(priv, ring, txq);\n out:\n \tspin_unlock(\u0026ring-\u003elock);\n \n@@ -2245,6 +2298,10 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n \t}\n \n \tdev_kfree_skb(skb);\n+drop:\n+\t/* The dropped frame may have been the last one of the batch */\n+\tbcmgenet_tx_kick(priv, ring, txq);\n+\tret = NETDEV_TX_OK;\n \tgoto out;\n }\n \n@@ -2252,7 +2309,7 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring,\n \t\t\t      struct enet_cb *cb)\n {\n \tstruct bcmgenet_priv *priv = ring-\u003epriv;\n-\tunsigned int size = GENET_RX_BUF_SIZE;\n+\tunsigned int size = SKB_HEAD_ALIGN(priv-\u003erx_buf_len);\n \tunsigned int offset;\n \tdma_addr_t mapping;\n \tstruct page *page;\n@@ -2267,7 +2324,7 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring,\n \n \t/* page_pool handles DMA mapping via PP_FLAG_DMA_MAP */\n \tmapping = page_pool_get_dma_addr(page) + offset;\n-\tdma_sync_single_for_device(\u0026priv-\u003epdev-\u003edev, mapping, RX_BUF_LENGTH,\n+\tdma_sync_single_for_device(\u0026priv-\u003epdev-\u003edev, mapping, priv-\u003erx_buf_len,\n \t\t\t\t   DMA_FROM_DEVICE);\n \n \tcb-\u003erx_page = page;\n@@ -2278,6 +2335,54 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring,\n \treturn 0;\n }\n \n+/* Drop the frame being collected. Its remaining descriptors carry no SOP,\n+ * so they are dropped quietly until the next one does.\n+ */\n+static void bcmgenet_discard_frags(struct bcmgenet_rx_ring *ring)\n+{\n+\tring-\u003efrag_drop = true;\n+\n+\tif (!ring-\u003efrag_head)\n+\t\treturn;\n+\n+\tdev_kfree_skb_any(ring-\u003efrag_head);\n+\tring-\u003efrag_head = NULL;\n+}\n+\n+/* A frame longer than the threshold arrives in several descriptors, each with\n+ * its own status block. Only the first one carries a header, so hand the page\n+ * of every later one to the frame already being collected. Returns the frame\n+ * once EOP is in, NULL while more descriptors are expected or once the frame\n+ * had to be dropped.\n+ */\n+static struct sk_buff *bcmgenet_add_frag(struct bcmgenet_rx_ring *ring,\n+\t\t\t\t\t struct page *page,\n+\t\t\t\t\t unsigned int offset,\n+\t\t\t\t\t unsigned int size,\n+\t\t\t\t\t unsigned int dma_flag,\n+\t\t\t\t\t unsigned int len)\n+{\n+\tstruct sk_buff *head = ring-\u003efrag_head;\n+\n+\tif (unlikely(skb_shinfo(head)-\u003enr_frags \u003e= MAX_SKB_FRAGS)) {\n+\t\tBCMGENET_STATS64_INC((\u0026ring-\u003estats64), fragmented_errors);\n+\t\tbcmgenet_discard_frags(ring);\n+\t\tpage_pool_put_full_page(ring-\u003epage_pool, page, true);\n+\t\treturn NULL;\n+\t}\n+\n+\tskb_add_rx_frag(head, skb_shinfo(head)-\u003enr_frags, page,\n+\t\t\toffset + sizeof(struct status_64),\n+\t\t\tlen - sizeof(struct status_64), size);\n+\n+\tif (!(dma_flag \u0026 DMA_EOP))\n+\t\treturn NULL;\n+\n+\tring-\u003efrag_head = NULL;\n+\n+\treturn head;\n+}\n+\n /* bcmgenet_desc_rx - descriptor based rx process.\n  * this could be called from bottom half, or from NAPI polling method.\n  */\n@@ -2329,6 +2434,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,\n \t\tunsigned int rx_offset, rx_size;\n \t\tstruct status_64 *status;\n \t\tstruct page *rx_page;\n+\t\tunsigned int min_len;\n \t\tvoid *hard_start;\n \t\t__be16 rx_csum;\n \n@@ -2341,14 +2447,15 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,\n \n \t\tif (bcmgenet_rx_refill(ring, cb)) {\n \t\t\tBCMGENET_STATS64_INC(stats, dropped);\n+\t\t\tbcmgenet_discard_frags(ring);\n \t\t\tgoto next;\n \t\t}\n \n \t\t/* Sync the full buffer; the HW may have written anywhere\n-\t\t * up to RX_BUF_LENGTH.\n+\t\t * up to priv-\u003erx_buf_len.\n \t\t */\n \t\tpage_pool_dma_sync_for_cpu(ring-\u003epage_pool, rx_page, rx_offset,\n-\t\t\t\t\t   RX_BUF_LENGTH);\n+\t\t\t\t\t   priv-\u003erx_buf_len);\n \n \t\thard_start = page_address(rx_page) + rx_offset;\n \t\tstatus = (struct status_64 *)hard_start;\n@@ -2365,20 +2472,41 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,\n \t\t\t  __func__, p_index, ring-\u003ec_index,\n \t\t\t  ring-\u003eread_ptr, dma_length_status);\n \n+\t\t/* Only the first descriptor carries the alignment pad. A head\n+\t\t * with more to come must hold the Ethernet header.\n+\t\t */\n+\t\tif (dma_flag \u0026 DMA_SOP) {\n+\t\t\tmin_len = GENET_RSB_PAD;\n+\t\t\tif (!(dma_flag \u0026 DMA_EOP))\n+\t\t\t\tmin_len += ETH_HLEN;\n+\t\t} else {\n+\t\t\tmin_len = sizeof(struct status_64);\n+\t\t}\n+\n \t\t/* Reject lengths that would underflow the SKB build path. */\n-\t\tif (unlikely(len \u003e RX_BUF_LENGTH || len \u003c GENET_RSB_PAD)) {\n+\t\tif (unlikely(len \u003e priv-\u003erx_buf_len || len \u003c min_len)) {\n \t\t\tnetif_err(priv, rx_status, dev,\n \t\t\t\t  \"invalid packet length %d\\n\", len);\n \t\t\tBCMGENET_STATS64_INC(stats, length_errors);\n+\t\t\tbcmgenet_discard_frags(ring);\n \t\t\tpage_pool_put_full_page(ring-\u003epage_pool, rx_page,\n \t\t\t\t\t\ttrue);\n \t\t\tgoto next;\n \t\t}\n \n-\t\tif (unlikely(!(dma_flag \u0026 DMA_EOP) || !(dma_flag \u0026 DMA_SOP))) {\n-\t\t\tnetif_err(priv, rx_status, dev,\n-\t\t\t\t  \"dropping fragmented packet!\\n\");\n-\t\t\tBCMGENET_STATS64_INC(stats, fragmented_errors);\n+\t\t/* A new SOP resynchronizes after an incomplete frame */\n+\t\tif (dma_flag \u0026 DMA_SOP) {\n+\t\t\tif (ring-\u003efrag_head) {\n+\t\t\t\tBCMGENET_STATS64_INC(stats, fragmented_errors);\n+\t\t\t\tbcmgenet_discard_frags(ring);\n+\t\t\t}\n+\t\t\tring-\u003efrag_drop = false;\n+\t\t} else if (unlikely(!ring-\u003efrag_head)) {\n+\t\t\t/* Rest of a dropped frame, or no SOP seen yet */\n+\t\t\tif (!ring-\u003efrag_drop) {\n+\t\t\t\tBCMGENET_STATS64_INC(stats, fragmented_errors);\n+\t\t\t\tring-\u003efrag_drop = true;\n+\t\t\t}\n \t\t\tpage_pool_put_full_page(ring-\u003epage_pool, rx_page,\n \t\t\t\t\t\ttrue);\n \t\t\tgoto next;\n@@ -2408,17 +2536,27 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,\n \t\t\t\t\t\tDMA_RX_RXER)) == DMA_RX_RXER)\n \t\t\t\tu64_stats_inc(\u0026stats-\u003eerrors);\n \t\t\tu64_stats_update_end(\u0026stats-\u003esyncp);\n+\t\t\tbcmgenet_discard_frags(ring);\n \t\t\tpage_pool_put_full_page(ring-\u003epage_pool, rx_page,\n \t\t\t\t\t\ttrue);\n \t\t\tgoto next;\n \t\t} /* error packet */\n \n+\t\tif (!(dma_flag \u0026 DMA_SOP)) {\n+\t\t\tskb = bcmgenet_add_frag(ring, rx_page, rx_offset,\n+\t\t\t\t\t\trx_size, dma_flag, len);\n+\t\t\tif (!skb)\n+\t\t\t\tgoto next;\n+\t\t\tgoto deliver;\n+\t\t}\n+\n \t\t/* Build SKB from the page - data starts at hard_start,\n \t\t * frame begins after RSB(64) + pad(2) = 66 bytes.\n \t\t */\n \t\tskb = napi_build_skb(hard_start, rx_size);\n \t\tif (unlikely(!skb)) {\n \t\t\tBCMGENET_STATS64_INC(stats, dropped);\n+\t\t\tbcmgenet_discard_frags(ring);\n \t\t\tpage_pool_put_full_page(ring-\u003epage_pool, rx_page,\n \t\t\t\t\t\ttrue);\n \t\t\tgoto next;\n@@ -2430,17 +2568,26 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,\n \t\tskb_reserve(skb, GENET_RSB_PAD);\n \t\t__skb_put(skb, len - GENET_RSB_PAD);\n \n-\t\tif (priv-\u003ecrc_fwd_en) {\n-\t\t\tskb_trim(skb, skb-\u003elen - ETH_FCS_LEN);\n+\t\tif (unlikely(!(dma_flag \u0026 DMA_EOP))) {\n+\t\t\tring-\u003efrag_head = skb;\n+\t\t\tgoto next;\n+\t\t}\n+\n+deliver:\n+\t\t/* The FCS trim may release the page with the last status block */\n+\t\trx_csum = (__force __be16)(status-\u003erx_csum \u0026 0xffff);\n+\n+\t\tif (priv-\u003ecrc_fwd_en \u0026\u0026\n+\t\t    unlikely(pskb_trim(skb, skb-\u003elen - ETH_FCS_LEN))) {\n+\t\t\tBCMGENET_STATS64_INC(stats, dropped);\n+\t\t\tdev_kfree_skb_any(skb);\n+\t\t\tgoto next;\n \t\t}\n \n \t\t/* Set up checksum offload */\n-\t\tif (dev-\u003efeatures \u0026 NETIF_F_RXCSUM) {\n-\t\t\trx_csum = (__force __be16)(status-\u003erx_csum \u0026 0xffff);\n-\t\t\tif (rx_csum) {\n-\t\t\t\tskb-\u003ecsum = (__force __wsum)ntohs(rx_csum);\n-\t\t\t\tskb-\u003eip_summed = CHECKSUM_COMPLETE;\n-\t\t\t}\n+\t\tif ((dev-\u003efeatures \u0026 NETIF_F_RXCSUM) \u0026\u0026 rx_csum) {\n+\t\t\tskb-\u003ecsum = (__force __wsum)ntohs(rx_csum);\n+\t\t\tskb-\u003eip_summed = CHECKSUM_COMPLETE;\n \t\t}\n \n \t\tlen = skb-\u003elen;\n@@ -2548,6 +2695,8 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)\n \t\t\tcb = ring-\u003ecbs + i;\n \t\t\tbcmgenet_free_rx_cb(cb, ring-\u003epage_pool);\n \t\t}\n+\t\t/* a partial frame still holds pages of this pool */\n+\t\tbcmgenet_discard_frags(ring);\n \t}\n }\n \n@@ -2617,6 +2766,63 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)\n \tbcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);\n }\n \n+/* Receive threshold in register units. Covers the alignment bytes and the\n+ * frame up to the register maximum, but not the status block, which the\n+ * hardware adds on top. A longer frame arrives in several descriptors.\n+ */\n+static unsigned int bcmgenet_pkt_rdy_thld(unsigned int mtu)\n+{\n+\tunsigned int len = GENET_RBUF_ALIGN + mtu + ETH_HLEN + VLAN_HLEN;\n+\n+\tlen = round_up(len, ENET_THLD_BURST) / ENET_THLD_UNIT;\n+\n+\t/* Keep the reset default for the common MTUs */\n+\treturn clamp_t(unsigned int, len, ENET_THLD_DEFAULT,\n+\t\t       ENET_THLD_MAX_LEN / ENET_THLD_UNIT);\n+}\n+\n+/* Transmit threshold in register units. Frames landing in the window just\n+ * past it are padded clear of it, so pick a threshold that leaves room for\n+ * that padding inside the frame the MTU allows. Size the window against the\n+ * longest frame the MAC has to accept, since the tag count is not bounded.\n+ */\n+static unsigned int bcmgenet_tx_pkt_rdy_thld(unsigned int mtu)\n+{\n+\tunsigned int thld = ENET_THLD_MAX;\n+\n+\twhile (thld \u003e ENET_THLD_DEFAULT \u0026\u0026\n+\t       ENET_MAX_FRAME_LEN(mtu) - ETH_FCS_LEN \u003e thld * ENET_THLD_UNIT \u0026\u0026\n+\t       thld * ENET_THLD_UNIT + ENET_TX_SAFE_MARGIN \u003e mtu + ETH_HLEN)\n+\t\tthld -= ENET_THLD_BURST / ENET_THLD_UNIT;\n+\n+\treturn thld;\n+}\n+\n+/* A buffer has to hold everything the threshold lets the hardware deliver */\n+static unsigned int bcmgenet_rx_buf_len(unsigned int mtu)\n+{\n+\treturn sizeof(struct status_64) +\n+\t       bcmgenet_pkt_rdy_thld(mtu) * ENET_THLD_UNIT;\n+}\n+\n+/* Program the MTU dependent registers. Call with the MAC disabled. */\n+static void bcmgenet_set_mtu_regs(struct bcmgenet_priv *priv, unsigned int mtu)\n+{\n+\tu32 tx_thld = bcmgenet_tx_pkt_rdy_thld(mtu);\n+\tu32 thld = bcmgenet_pkt_rdy_thld(mtu);\n+\n+\tpriv-\u003etx_thld_len = tx_thld * ENET_THLD_UNIT;\n+\tbcmgenet_umac_writel(priv, ENET_MAX_FRAME_LEN(mtu), UMAC_MAX_FRAME_LEN);\n+\n+\t/* GENET v1 maps other registers at these offsets */\n+\tif (GENET_IS_V1(priv))\n+\t\treturn;\n+\n+\tbcmgenet_rbuf_writel(priv, thld, RBUF_PKT_RDY_THLD);\n+\tbcmgenet_writel(tx_thld, priv-\u003ebase + priv-\u003ehw_params-\u003etbuf_offset +\n+\t\t\tTBUF_PKT_RDY_THLD);\n+}\n+\n static void init_umac(struct bcmgenet_priv *priv)\n {\n \tstruct device *kdev = \u0026priv-\u003epdev-\u003edev;\n@@ -2633,7 +2839,7 @@ static void init_umac(struct bcmgenet_priv *priv)\n \t\t\t     UMAC_MIB_CTRL);\n \tbcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL);\n \n-\tbcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);\n+\tbcmgenet_set_mtu_regs(priv, priv-\u003edev-\u003emtu);\n \n \t/* init tx registers, enable TSB */\n \treg = bcmgenet_tbuf_ctrl_get(priv);\n@@ -2739,7 +2945,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,\n \n \t/* Set flow period for ring != 0 */\n \tif (index)\n-\t\tflow_period_val = ENET_MAX_MTU_SIZE \u003c\u003c 16;\n+\t\tflow_period_val = ENET_MAX_FRAME_LEN(priv-\u003edev-\u003emtu) \u003c\u003c 16;\n \n \tbcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);\n \tbcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);\n@@ -2749,7 +2955,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,\n \t\t\t\t  TDMA_FLOW_PERIOD);\n \tbcmgenet_tdma_ring_writel(priv, index,\n \t\t\t\t  ((size \u003c\u003c DMA_RING_SIZE_SHIFT) |\n-\t\t\t\t   RX_BUF_LENGTH), DMA_RING_BUF_SIZE);\n+\t\t\t\t   priv-\u003erx_buf_len), DMA_RING_BUF_SIZE);\n \n \t/* Set start and end address, read and write pointers */\n \tbcmgenet_tdma_ring_writel(priv, index, start_ptr * words_per_bd,\n@@ -2768,8 +2974,9 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,\n static int bcmgenet_rx_ring_create_pool(struct bcmgenet_priv *priv,\n \t\t\t\t\tstruct bcmgenet_rx_ring *ring)\n {\n-\t/* Buffers share a page. bcmgenet_rx_refill() syncs each one for the\n-\t * device, PP_FLAG_DMA_SYNC_DEV would sync the whole page.\n+\t/* Buffers may share a page, depending on PAGE_SIZE and the MTU.\n+\t * bcmgenet_rx_refill() syncs each one for the device,\n+\t * PP_FLAG_DMA_SYNC_DEV would sync the whole page.\n \t */\n \tstruct page_pool_params pp_params = {\n \t\t.order = 0,\n@@ -2832,7 +3039,7 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,\n \tbcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX);\n \tbcmgenet_rdma_ring_writel(priv, index,\n \t\t\t\t  ((size \u003c\u003c DMA_RING_SIZE_SHIFT) |\n-\t\t\t\t   RX_BUF_LENGTH), DMA_RING_BUF_SIZE);\n+\t\t\t\t   priv-\u003erx_buf_len), DMA_RING_BUF_SIZE);\n \tbcmgenet_rdma_ring_writel(priv, index,\n \t\t\t\t  (DMA_FC_THRESH_LO \u003c\u003c\n \t\t\t\t   DMA_XOFF_THRESHOLD_SHIFT) |\n@@ -3348,7 +3555,7 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv,\n \tput_unaligned_be16(addr_tmp, \u0026addr[4]);\n }\n \n-static void bcmgenet_netif_start(struct net_device *dev)\n+static void bcmgenet_netif_start(struct net_device *dev, bool start_phy)\n {\n \tstruct bcmgenet_priv *priv = netdev_priv(dev);\n \n@@ -3365,7 +3572,8 @@ static void bcmgenet_netif_start(struct net_device *dev)\n \t/* Monitor link interrupts now */\n \tbcmgenet_link_intr_enable(priv);\n \n-\tphy_start(dev-\u003ephydev);\n+\tif (start_phy)\n+\t\tphy_start(dev-\u003ephydev);\n }\n \n static int bcmgenet_open(struct net_device *dev)\n@@ -3428,8 +3636,9 @@ static int bcmgenet_open(struct net_device *dev)\n \n \tbcmgenet_phy_pause_set(dev, priv-\u003erx_pause, priv-\u003etx_pause);\n \n-\tbcmgenet_netif_start(dev);\n+\tbcmgenet_netif_start(dev, true);\n \n+\tpriv-\u003edatapath_up = true;\n \tnetif_tx_start_all_queues(dev);\n \n \treturn 0;\n@@ -3488,7 +3697,11 @@ static int bcmgenet_close(struct net_device *dev)\n \n \tnetif_dbg(priv, ifdown, dev, \"bcmgenet_close\\n\");\n \n-\tbcmgenet_netif_stop(dev, false);\n+\t/* A failed MTU change can have torn the datapath down already */\n+\tif (priv-\u003edatapath_up) {\n+\t\tbcmgenet_netif_stop(dev, false);\n+\t\tpriv-\u003edatapath_up = false;\n+\t}\n \n \t/* Really kill the PHY state machine and disconnect from it */\n \tphy_disconnect(dev-\u003ephydev);\n@@ -3736,6 +3949,71 @@ static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier)\n \treturn 0;\n }\n \n+static int bcmgenet_change_mtu(struct net_device *dev, int new_mtu)\n+{\n+\tstruct bcmgenet_priv *priv = netdev_priv(dev);\n+\tunsigned int old_mtu = dev-\u003emtu;\n+\tint ret;\n+\n+\tif (!netif_running(dev)) {\n+\t\tWRITE_ONCE(dev-\u003emtu, new_mtu);\n+\t\tpriv-\u003erx_buf_len = bcmgenet_rx_buf_len(new_mtu);\n+\t\treturn 0;\n+\t}\n+\n+\t/* The watchdog trips on an idle queue once the rings are gone */\n+\tnetif_device_detach(dev);\n+\n+\t/* Only the buffers and the MTU registers change, leave the PHY up */\n+\tbcmgenet_netif_stop(dev, false);\n+\tpriv-\u003edatapath_up = false;\n+\n+\tWRITE_ONCE(dev-\u003emtu, new_mtu);\n+\tpriv-\u003erx_buf_len = bcmgenet_rx_buf_len(new_mtu);\n+\tbcmgenet_set_mtu_regs(priv, new_mtu);\n+\n+\tret = bcmgenet_init_dma(priv, true);\n+\tif (ret) {\n+\t\t/* Retry the size that was allocated a moment ago */\n+\t\tWRITE_ONCE(dev-\u003emtu, old_mtu);\n+\t\tpriv-\u003erx_buf_len = bcmgenet_rx_buf_len(old_mtu);\n+\t\tbcmgenet_set_mtu_regs(priv, old_mtu);\n+\t\tif (bcmgenet_init_dma(priv, true)) {\n+\t\t\t/* Nothing left to run on. Take the interface down so\n+\t\t\t * that close and suspend do not tear it down twice.\n+\t\t\t */\n+\t\t\tnetdev_err(dev, \"failed to restore MTU %u, closing\\n\",\n+\t\t\t\t   old_mtu);\n+\t\t\tnetif_close(dev);\n+\n+\t\t\t/* Mark the device present again, __dev_open()\n+\t\t\t * refuses a detached one. The queues stay stopped\n+\t\t\t * because the interface is down by now.\n+\t\t\t */\n+\t\t\tnetif_device_attach(dev);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tbcmgenet_hfb_restore(priv);\n+\tbcmgenet_netif_start(dev, false);\n+\n+\t/* bcmgenet_netif_start() only restores the link interrupt */\n+\tif (bcmgenet_has_mdio_intr(priv))\n+\t\tbcmgenet_intrl2_0_writel(priv, UMAC_IRQ_MDIO_EVENT,\n+\t\t\t\t\t INTRL2_CPU_MASK_CLEAR);\n+\n+\t/* A link event latched while the interrupts were off is gone. Internal\n+\t * PHYs on GENET v1-v4 are not polled, so resync the state machine.\n+\t */\n+\tphy_mac_interrupt(dev-\u003ephydev);\n+\n+\tpriv-\u003edatapath_up = true;\n+\tnetif_device_attach(dev);\n+\n+\treturn ret;\n+}\n+\n static const struct net_device_ops bcmgenet_netdev_ops = {\n \t.ndo_open\t\t= bcmgenet_open,\n \t.ndo_stop\t\t= bcmgenet_close,\n@@ -3747,6 +4025,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = {\n \t.ndo_set_features\t= bcmgenet_set_features,\n \t.ndo_get_stats64\t= bcmgenet_get_stats64,\n \t.ndo_change_carrier\t= bcmgenet_change_carrier,\n+\t.ndo_change_mtu\t\t= bcmgenet_change_mtu,\n };\n \n /* GENET hardware parameters/characteristics */\n@@ -4100,6 +4379,11 @@ static int bcmgenet_probe(struct platform_device *pdev)\n \t/* Mii wait queue */\n \tinit_waitqueue_head(\u0026priv-\u003ewq);\n \tbcmgenet_hfb_init(priv);\n+\n+\t/* v1 cannot program the thresholds, so it stays at the default MTU */\n+\tpriv-\u003erx_buf_len = bcmgenet_rx_buf_len(dev-\u003emtu);\n+\tif (!GENET_IS_V1(priv))\n+\t\tdev-\u003emax_mtu = ENET_MAX_JUMBO_MTU;\n \tINIT_WORK(\u0026priv-\u003ebcmgenet_irq_work, bcmgenet_irq_task);\n \n \tpriv-\u003eclk_wol = devm_clk_get_optional(\u0026priv-\u003epdev-\u003edev, \"enet-wol\");\n@@ -4312,7 +4596,7 @@ static int bcmgenet_resume(struct device *d)\n \tif (!device_may_wakeup(d))\n \t\tphy_resume(dev-\u003ephydev);\n \n-\tbcmgenet_netif_start(dev);\n+\tbcmgenet_netif_start(dev, true);\n \n \tnetif_device_attach(dev);\n \ndiff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h\nindex 86f2aed20dbe8..97c27b7920d53 100644\n--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h\n+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h\n@@ -28,13 +28,16 @@\n /* which ring is descriptor based */\n #define DESC_INDEX\t\t\t\t16\n \n-/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528.\n- * 1536 is multiple of 256 bytes\n- */\n #define ENET_BRCM_TAG_LEN\t6\n #define ENET_PAD\t\t8\n-#define ENET_MAX_MTU_SIZE\t(ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \\\n-\t\t\t\t ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)\n+\n+/* Longest frame the MAC must accept for a given MTU. ENET_PAD is slack the\n+ * driver has always carried, it rounded the default up to 1536 from 1528.\n+ */\n+#define ENET_FRAME_OVERHEAD\t(ETH_HLEN + VLAN_HLEN + ENET_BRCM_TAG_LEN + \\\n+\t\t\t\t ETH_FCS_LEN + ENET_PAD)\n+#define ENET_MAX_FRAME_LEN(mtu)\t((mtu) + ENET_FRAME_OVERHEAD)\n+\n #define DMA_MAX_BURST_LENGTH    0x10\n \n /* misc. configuration */\n@@ -219,6 +222,8 @@ struct bcmgenet_rx_stats64 {\n #define  RBUF_ALIGN_2B\t\t\t(1 \u003c\u003c 1)\n #define  RBUF_BAD_DIS\t\t\t(1 \u003c\u003c 2)\n \n+#define RBUF_PKT_RDY_THLD\t\t0x08\n+\n #define RBUF_STATUS\t\t\t0x0C\n #define  RBUF_STATUS_WOL\t\t(1 \u003c\u003c 0)\n #define  RBUF_STATUS_MPD_INTR_ACTIVE\t(1 \u003c\u003c 1)\n@@ -249,6 +254,7 @@ struct bcmgenet_rx_stats64 {\n #define TBUF_CTRL\t\t\t0x00\n #define  TBUF_64B_EN\t\t\t(1 \u003c\u003c 0)\n #define TBUF_BP_MC\t\t\t0x0C\n+#define TBUF_PKT_RDY_THLD\t\t0x10\n #define TBUF_ENERGY_CTRL\t\t0x14\n #define  TBUF_EEE_EN\t\t\t(1 \u003c\u003c 0)\n #define  TBUF_PM_EN\t\t\t(1 \u003c\u003c 1)\n@@ -575,6 +581,8 @@ struct bcmgenet_rx_ring {\n \tunsigned int\tcb_ptr;\t\t/* Rx ring initial CB ptr */\n \tunsigned int\tend_ptr;\t/* Rx ring end CB ptr */\n \tunsigned int\told_discards;\n+\tstruct sk_buff\t*frag_head;\t/* frame being reassembled */\n+\tbool\t\tfrag_drop;\t/* discarding until the next SOP */\n \tstruct bcmgenet_net_dim dim;\n \tu32\t\trx_max_coalesced_frames;\n \tu32\t\trx_coalesce_usecs;\n@@ -613,6 +621,8 @@ struct bcmgenet_priv {\n \tvoid __iomem *rx_bds;\n \tstruct enet_cb *rx_cbs;\n \tunsigned int num_rx_bds;\n+\tunsigned int rx_buf_len;\n+\tunsigned int tx_thld_len;\n \tstruct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES];\n \tstruct list_head rxnfc_list;\n \n@@ -624,6 +634,7 @@ struct bcmgenet_priv {\n \tunsigned autoneg_pause:1;\n \tunsigned tx_pause:1;\n \tunsigned rx_pause:1;\n+\tunsigned datapath_up:1;\n \n \t/* MDIO bus variables */\n \twait_queue_head_t wq;\n"
}

2/1 2026/10/07 09:06 agent patch-evaluator
11m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The changes are entirely confined to the Broadcom GENET Ethernet driver (drivers/net/ethernet/broadcom/genet/). Broadcom GENET is an on-SoC MAC found in Broadcom BCM7xxx and BCM2711 (Raspberry Pi 4) architectures. It is a platform driver requiring specific MMIO and IRQ resources that are not present or emulated in standard virtualized environments (QEMU/GCE) on the target architecture (amd64). Because the hardware is structurally unreachable, syzkaller cannot execute this code.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any '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:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 8af23543570fde3af2cc0d011261880e1218abc2
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Oct 7 09:06:34 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 4c9db2f9fc25f..80215b5c00630 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -48,17 +48,44 @@
 #define GENET_Q0_TX_BD_CNT	\
 	(TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->tx_bds_per_q)
 
-#define RX_BUF_LENGTH		2048
 #define SKB_ALIGNMENT		32
 
+/* RBUF and TBUF hand a frame to the DMA once the threshold is reached. Both
+ * registers are 8 bit in units of 16 bytes and want a multiple of the 256
+ * byte burst size, so 0xf0 is the largest usable value.
+ */
+#define ENET_THLD_UNIT		16
+#define ENET_THLD_BURST		256
+#define ENET_THLD_DEFAULT	0x80
+#define ENET_THLD_MAX		0xf0
+
+/* A frame ending just past the transmit threshold stops the transmitter once
+ * a shorter frame follows, so pad frames that land there this far past it.
+ */
+#define ENET_TX_SAFE_MARGIN	64
+
 /* Page pool RX buffer layout:
  * RSB(64) + pad(2) | frame data | skb_shared_info
- * The HW writes the 64B RSB + 2B alignment padding before the frame.
+ * The HW writes the 64B RSB before every descriptor of a frame. Only the
+ * first one also gets the 2B alignment padding.
  */
-#define GENET_RSB_PAD		(sizeof(struct status_64) + 2)
+#define GENET_RBUF_ALIGN	2
+#define GENET_RSB_PAD		(sizeof(struct status_64) + GENET_RBUF_ALIGN)
 
-/* RX buffer plus the skb_shared_info napi_build_skb() places behind it */
-#define GENET_RX_BUF_SIZE	SKB_HEAD_ALIGN(RX_BUF_LENGTH)
+/* A descriptor never spans more than one page, which also holds
+ * skb_shared_info behind the frame, so on 4K pages the page bounds the
+ * threshold before the register does. Larger pages fit several descriptors.
+ */
+#define ENET_SHINFO_LEN		SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
+#define ENET_THLD_PAGE_LEN	round_down(PAGE_SIZE - ENET_SHINFO_LEN - \
+					   sizeof(struct status_64), \
+					   ENET_THLD_BURST)
+#define ENET_THLD_MAX_LEN	min_t(unsigned int, \
+				      ENET_THLD_MAX * ENET_THLD_UNIT, \
+				      ENET_THLD_PAGE_LEN)
+
+/* UMAC_MAX_FRAME_LEN is 14 bits wide and counts the FCS */
+#define ENET_MAX_JUMBO_MTU	(GENMASK(13, 0) - ENET_FRAME_OVERHEAD)
 
 /* Tx/Rx DMA register offset, skip 256 descriptors */
 #define WORDS_PER_BD(p)		(p->hw_params->words_per_bd)
@@ -2119,6 +2146,15 @@ static void bcmgenet_hide_tsb(struct sk_buff *skb)
 	__skb_pull(skb, sizeof(struct status_64));
 }
 
+static void bcmgenet_tx_kick(struct bcmgenet_priv *priv,
+			     struct bcmgenet_tx_ring *ring,
+			     struct netdev_queue *txq)
+{
+	if (!netdev_xmit_more() || netif_xmit_stopped(txq))
+		bcmgenet_tdma_ring_writel(priv, ring->index,
+					  ring->prod_index, TDMA_PROD_INDEX);
+}
+
 static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -2148,6 +2184,29 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 		goto out;
 	}
 
+	/* The MAC holds a frame to insert its checksum, but only as much as
+	 * its FIFO takes. Longer frames are dropped silently.
+	 */
+	if (unlikely(skb->len > priv->tx_thld_len) &&
+	    skb->ip_summed == CHECKSUM_PARTIAL) {
+		if (skb_checksum_help(skb)) {
+			BCMGENET_STATS64_INC((&ring->stats64), dropped);
+			dev_kfree_skb_any(skb);
+			goto drop;
+		}
+	}
+
+	/* Keep the frame out of the window just past the threshold */
+	if (unlikely(skb->len > priv->tx_thld_len &&
+		     skb->len < priv->tx_thld_len + ENET_TX_SAFE_MARGIN)) {
+		if (skb_put_padto(skb, priv->tx_thld_len + ENET_TX_SAFE_MARGIN)) {
+			BCMGENET_STATS64_INC((&ring->stats64), dropped);
+			goto drop;
+		}
+	}
+
+	nr_frags = skb_shinfo(skb)->nr_frags;
+
 	/* Retain how many bytes will be sent on the wire, without TSB inserted
 	 * by transmit checksum offload
 	 */
@@ -2155,10 +2214,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	/* add the Transmit Status Block */
 	skb = bcmgenet_add_tsb(dev, skb, ring);
-	if (!skb) {
-		ret = NETDEV_TX_OK;
-		goto out;
-	}
+	if (!skb)
+		goto drop;
 
 	for (i = 0; i <= nr_frags; i++) {
 		tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
@@ -2183,7 +2240,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 		if (ret) {
 			priv->mib.tx_dma_failed++;
 			netif_err(priv, tx_err, dev, "Tx DMA map failed\n");
-			ret = NETDEV_TX_OK;
 			goto out_unmap_frags;
 		}
 		dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
@@ -2225,10 +2281,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (ring->free_bds <= (MAX_SKB_FRAGS + 1))
 		netif_tx_stop_queue(txq);
 
-	if (!netdev_xmit_more() || netif_xmit_stopped(txq))
-		/* Packets are ready, update producer index */
-		bcmgenet_tdma_ring_writel(priv, ring->index,
-					  ring->prod_index, TDMA_PROD_INDEX);
+	bcmgenet_tx_kick(priv, ring, txq);
 out:
 	spin_unlock(&ring->lock);
 
@@ -2245,6 +2298,10 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	dev_kfree_skb(skb);
+drop:
+	/* The dropped frame may have been the last one of the batch */
+	bcmgenet_tx_kick(priv, ring, txq);
+	ret = NETDEV_TX_OK;
 	goto out;
 }
 
@@ -2252,7 +2309,7 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring,
 			      struct enet_cb *cb)
 {
 	struct bcmgenet_priv *priv = ring->priv;
-	unsigned int size = GENET_RX_BUF_SIZE;
+	unsigned int size = SKB_HEAD_ALIGN(priv->rx_buf_len);
 	unsigned int offset;
 	dma_addr_t mapping;
 	struct page *page;
@@ -2267,7 +2324,7 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring,
 
 	/* page_pool handles DMA mapping via PP_FLAG_DMA_MAP */
 	mapping = page_pool_get_dma_addr(page) + offset;
-	dma_sync_single_for_device(&priv->pdev->dev, mapping, RX_BUF_LENGTH,
+	dma_sync_single_for_device(&priv->pdev->dev, mapping, priv->rx_buf_len,
 				   DMA_FROM_DEVICE);
 
 	cb->rx_page = page;
@@ -2278,6 +2335,54 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring,
 	return 0;
 }
 
+/* Drop the frame being collected. Its remaining descriptors carry no SOP,
+ * so they are dropped quietly until the next one does.
+ */
+static void bcmgenet_discard_frags(struct bcmgenet_rx_ring *ring)
+{
+	ring->frag_drop = true;
+
+	if (!ring->frag_head)
+		return;
+
+	dev_kfree_skb_any(ring->frag_head);
+	ring->frag_head = NULL;
+}
+
+/* A frame longer than the threshold arrives in several descriptors, each with
+ * its own status block. Only the first one carries a header, so hand the page
+ * of every later one to the frame already being collected. Returns the frame
+ * once EOP is in, NULL while more descriptors are expected or once the frame
+ * had to be dropped.
+ */
+static struct sk_buff *bcmgenet_add_frag(struct bcmgenet_rx_ring *ring,
+					 struct page *page,
+					 unsigned int offset,
+					 unsigned int size,
+					 unsigned int dma_flag,
+					 unsigned int len)
+{
+	struct sk_buff *head = ring->frag_head;
+
+	if (unlikely(skb_shinfo(head)->nr_frags >= MAX_SKB_FRAGS)) {
+		BCMGENET_STATS64_INC((&ring->stats64), fragmented_errors);
+		bcmgenet_discard_frags(ring);
+		page_pool_put_full_page(ring->page_pool, page, true);
+		return NULL;
+	}
+
+	skb_add_rx_frag(head, skb_shinfo(head)->nr_frags, page,
+			offset + sizeof(struct status_64),
+			len - sizeof(struct status_64), size);
+
+	if (!(dma_flag & DMA_EOP))
+		return NULL;
+
+	ring->frag_head = NULL;
+
+	return head;
+}
+
 /* bcmgenet_desc_rx - descriptor based rx process.
  * this could be called from bottom half, or from NAPI polling method.
  */
@@ -2329,6 +2434,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 		unsigned int rx_offset, rx_size;
 		struct status_64 *status;
 		struct page *rx_page;
+		unsigned int min_len;
 		void *hard_start;
 		__be16 rx_csum;
 
@@ -2341,14 +2447,15 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 
 		if (bcmgenet_rx_refill(ring, cb)) {
 			BCMGENET_STATS64_INC(stats, dropped);
+			bcmgenet_discard_frags(ring);
 			goto next;
 		}
 
 		/* Sync the full buffer; the HW may have written anywhere
-		 * up to RX_BUF_LENGTH.
+		 * up to priv->rx_buf_len.
 		 */
 		page_pool_dma_sync_for_cpu(ring->page_pool, rx_page, rx_offset,
-					   RX_BUF_LENGTH);
+					   priv->rx_buf_len);
 
 		hard_start = page_address(rx_page) + rx_offset;
 		status = (struct status_64 *)hard_start;
@@ -2365,20 +2472,41 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 			  __func__, p_index, ring->c_index,
 			  ring->read_ptr, dma_length_status);
 
+		/* Only the first descriptor carries the alignment pad. A head
+		 * with more to come must hold the Ethernet header.
+		 */
+		if (dma_flag & DMA_SOP) {
+			min_len = GENET_RSB_PAD;
+			if (!(dma_flag & DMA_EOP))
+				min_len += ETH_HLEN;
+		} else {
+			min_len = sizeof(struct status_64);
+		}
+
 		/* Reject lengths that would underflow the SKB build path. */
-		if (unlikely(len > RX_BUF_LENGTH || len < GENET_RSB_PAD)) {
+		if (unlikely(len > priv->rx_buf_len || len < min_len)) {
 			netif_err(priv, rx_status, dev,
 				  "invalid packet length %d\n", len);
 			BCMGENET_STATS64_INC(stats, length_errors);
+			bcmgenet_discard_frags(ring);
 			page_pool_put_full_page(ring->page_pool, rx_page,
 						true);
 			goto next;
 		}
 
-		if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
-			netif_err(priv, rx_status, dev,
-				  "dropping fragmented packet!\n");
-			BCMGENET_STATS64_INC(stats, fragmented_errors);
+		/* A new SOP resynchronizes after an incomplete frame */
+		if (dma_flag & DMA_SOP) {
+			if (ring->frag_head) {
+				BCMGENET_STATS64_INC(stats, fragmented_errors);
+				bcmgenet_discard_frags(ring);
+			}
+			ring->frag_drop = false;
+		} else if (unlikely(!ring->frag_head)) {
+			/* Rest of a dropped frame, or no SOP seen yet */
+			if (!ring->frag_drop) {
+				BCMGENET_STATS64_INC(stats, fragmented_errors);
+				ring->frag_drop = true;
+			}
 			page_pool_put_full_page(ring->page_pool, rx_page,
 						true);
 			goto next;
@@ -2408,17 +2536,27 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 						DMA_RX_RXER)) == DMA_RX_RXER)
 				u64_stats_inc(&stats->errors);
 			u64_stats_update_end(&stats->syncp);
+			bcmgenet_discard_frags(ring);
 			page_pool_put_full_page(ring->page_pool, rx_page,
 						true);
 			goto next;
 		} /* error packet */
 
+		if (!(dma_flag & DMA_SOP)) {
+			skb = bcmgenet_add_frag(ring, rx_page, rx_offset,
+						rx_size, dma_flag, len);
+			if (!skb)
+				goto next;
+			goto deliver;
+		}
+
 		/* Build SKB from the page - data starts at hard_start,
 		 * frame begins after RSB(64) + pad(2) = 66 bytes.
 		 */
 		skb = napi_build_skb(hard_start, rx_size);
 		if (unlikely(!skb)) {
 			BCMGENET_STATS64_INC(stats, dropped);
+			bcmgenet_discard_frags(ring);
 			page_pool_put_full_page(ring->page_pool, rx_page,
 						true);
 			goto next;
@@ -2430,17 +2568,26 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 		skb_reserve(skb, GENET_RSB_PAD);
 		__skb_put(skb, len - GENET_RSB_PAD);
 
-		if (priv->crc_fwd_en) {
-			skb_trim(skb, skb->len - ETH_FCS_LEN);
+		if (unlikely(!(dma_flag & DMA_EOP))) {
+			ring->frag_head = skb;
+			goto next;
+		}
+
+deliver:
+		/* The FCS trim may release the page with the last status block */
+		rx_csum = (__force __be16)(status->rx_csum & 0xffff);
+
+		if (priv->crc_fwd_en &&
+		    unlikely(pskb_trim(skb, skb->len - ETH_FCS_LEN))) {
+			BCMGENET_STATS64_INC(stats, dropped);
+			dev_kfree_skb_any(skb);
+			goto next;
 		}
 
 		/* Set up checksum offload */
-		if (dev->features & NETIF_F_RXCSUM) {
-			rx_csum = (__force __be16)(status->rx_csum & 0xffff);
-			if (rx_csum) {
-				skb->csum = (__force __wsum)ntohs(rx_csum);
-				skb->ip_summed = CHECKSUM_COMPLETE;
-			}
+		if ((dev->features & NETIF_F_RXCSUM) && rx_csum) {
+			skb->csum = (__force __wsum)ntohs(rx_csum);
+			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
 		len = skb->len;
@@ -2548,6 +2695,8 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
 			cb = ring->cbs + i;
 			bcmgenet_free_rx_cb(cb, ring->page_pool);
 		}
+		/* a partial frame still holds pages of this pool */
+		bcmgenet_discard_frags(ring);
 	}
 }
 
@@ -2617,6 +2766,63 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)
 	bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
 }
 
+/* Receive threshold in register units. Covers the alignment bytes and the
+ * frame up to the register maximum, but not the status block, which the
+ * hardware adds on top. A longer frame arrives in several descriptors.
+ */
+static unsigned int bcmgenet_pkt_rdy_thld(unsigned int mtu)
+{
+	unsigned int len = GENET_RBUF_ALIGN + mtu + ETH_HLEN + VLAN_HLEN;
+
+	len = round_up(len, ENET_THLD_BURST) / ENET_THLD_UNIT;
+
+	/* Keep the reset default for the common MTUs */
+	return clamp_t(unsigned int, len, ENET_THLD_DEFAULT,
+		       ENET_THLD_MAX_LEN / ENET_THLD_UNIT);
+}
+
+/* Transmit threshold in register units. Frames landing in the window just
+ * past it are padded clear of it, so pick a threshold that leaves room for
+ * that padding inside the frame the MTU allows. Size the window against the
+ * longest frame the MAC has to accept, since the tag count is not bounded.
+ */
+static unsigned int bcmgenet_tx_pkt_rdy_thld(unsigned int mtu)
+{
+	unsigned int thld = ENET_THLD_MAX;
+
+	while (thld > ENET_THLD_DEFAULT &&
+	       ENET_MAX_FRAME_LEN(mtu) - ETH_FCS_LEN > thld * ENET_THLD_UNIT &&
+	       thld * ENET_THLD_UNIT + ENET_TX_SAFE_MARGIN > mtu + ETH_HLEN)
+		thld -= ENET_THLD_BURST / ENET_THLD_UNIT;
+
+	return thld;
+}
+
+/* A buffer has to hold everything the threshold lets the hardware deliver */
+static unsigned int bcmgenet_rx_buf_len(unsigned int mtu)
+{
+	return sizeof(struct status_64) +
+	       bcmgenet_pkt_rdy_thld(mtu) * ENET_THLD_UNIT;
+}
+
+/* Program the MTU dependent registers. Call with the MAC disabled. */
+static void bcmgenet_set_mtu_regs(struct bcmgenet_priv *priv, unsigned int mtu)
+{
+	u32 tx_thld = bcmgenet_tx_pkt_rdy_thld(mtu);
+	u32 thld = bcmgenet_pkt_rdy_thld(mtu);
+
+	priv->tx_thld_len = tx_thld * ENET_THLD_UNIT;
+	bcmgenet_umac_writel(priv, ENET_MAX_FRAME_LEN(mtu), UMAC_MAX_FRAME_LEN);
+
+	/* GENET v1 maps other registers at these offsets */
+	if (GENET_IS_V1(priv))
+		return;
+
+	bcmgenet_rbuf_writel(priv, thld, RBUF_PKT_RDY_THLD);
+	bcmgenet_writel(tx_thld, priv->base + priv->hw_params->tbuf_offset +
+			TBUF_PKT_RDY_THLD);
+}
+
 static void init_umac(struct bcmgenet_priv *priv)
 {
 	struct device *kdev = &priv->pdev->dev;
@@ -2633,7 +2839,7 @@ static void init_umac(struct bcmgenet_priv *priv)
 			     UMAC_MIB_CTRL);
 	bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL);
 
-	bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
+	bcmgenet_set_mtu_regs(priv, priv->dev->mtu);
 
 	/* init tx registers, enable TSB */
 	reg = bcmgenet_tbuf_ctrl_get(priv);
@@ -2739,7 +2945,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
 
 	/* Set flow period for ring != 0 */
 	if (index)
-		flow_period_val = ENET_MAX_MTU_SIZE << 16;
+		flow_period_val = ENET_MAX_FRAME_LEN(priv->dev->mtu) << 16;
 
 	bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
 	bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
@@ -2749,7 +2955,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
 				  TDMA_FLOW_PERIOD);
 	bcmgenet_tdma_ring_writel(priv, index,
 				  ((size << DMA_RING_SIZE_SHIFT) |
-				   RX_BUF_LENGTH), DMA_RING_BUF_SIZE);
+				   priv->rx_buf_len), DMA_RING_BUF_SIZE);
 
 	/* Set start and end address, read and write pointers */
 	bcmgenet_tdma_ring_writel(priv, index, start_ptr * words_per_bd,
@@ -2768,8 +2974,9 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
 static int bcmgenet_rx_ring_create_pool(struct bcmgenet_priv *priv,
 					struct bcmgenet_rx_ring *ring)
 {
-	/* Buffers share a page. bcmgenet_rx_refill() syncs each one for the
-	 * device, PP_FLAG_DMA_SYNC_DEV would sync the whole page.
+	/* Buffers may share a page, depending on PAGE_SIZE and the MTU.
+	 * bcmgenet_rx_refill() syncs each one for the device,
+	 * PP_FLAG_DMA_SYNC_DEV would sync the whole page.
 	 */
 	struct page_pool_params pp_params = {
 		.order = 0,
@@ -2832,7 +3039,7 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
 	bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX);
 	bcmgenet_rdma_ring_writel(priv, index,
 				  ((size << DMA_RING_SIZE_SHIFT) |
-				   RX_BUF_LENGTH), DMA_RING_BUF_SIZE);
+				   priv->rx_buf_len), DMA_RING_BUF_SIZE);
 	bcmgenet_rdma_ring_writel(priv, index,
 				  (DMA_FC_THRESH_LO <<
 				   DMA_XOFF_THRESHOLD_SHIFT) |
@@ -3348,7 +3555,7 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv,
 	put_unaligned_be16(addr_tmp, &addr[4]);
 }
 
-static void bcmgenet_netif_start(struct net_device *dev)
+static void bcmgenet_netif_start(struct net_device *dev, bool start_phy)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 
@@ -3365,7 +3572,8 @@ static void bcmgenet_netif_start(struct net_device *dev)
 	/* Monitor link interrupts now */
 	bcmgenet_link_intr_enable(priv);
 
-	phy_start(dev->phydev);
+	if (start_phy)
+		phy_start(dev->phydev);
 }
 
 static int bcmgenet_open(struct net_device *dev)
@@ -3428,8 +3636,9 @@ static int bcmgenet_open(struct net_device *dev)
 
 	bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);
 
-	bcmgenet_netif_start(dev);
+	bcmgenet_netif_start(dev, true);
 
+	priv->datapath_up = true;
 	netif_tx_start_all_queues(dev);
 
 	return 0;
@@ -3488,7 +3697,11 @@ static int bcmgenet_close(struct net_device *dev)
 
 	netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
 
-	bcmgenet_netif_stop(dev, false);
+	/* A failed MTU change can have torn the datapath down already */
+	if (priv->datapath_up) {
+		bcmgenet_netif_stop(dev, false);
+		priv->datapath_up = false;
+	}
 
 	/* Really kill the PHY state machine and disconnect from it */
 	phy_disconnect(dev->phydev);
@@ -3736,6 +3949,71 @@ static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier)
 	return 0;
 }
 
+static int bcmgenet_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct bcmgenet_priv *priv = netdev_priv(dev);
+	unsigned int old_mtu = dev->mtu;
+	int ret;
+
+	if (!netif_running(dev)) {
+		WRITE_ONCE(dev->mtu, new_mtu);
+		priv->rx_buf_len = bcmgenet_rx_buf_len(new_mtu);
+		return 0;
+	}
+
+	/* The watchdog trips on an idle queue once the rings are gone */
+	netif_device_detach(dev);
+
+	/* Only the buffers and the MTU registers change, leave the PHY up */
+	bcmgenet_netif_stop(dev, false);
+	priv->datapath_up = false;
+
+	WRITE_ONCE(dev->mtu, new_mtu);
+	priv->rx_buf_len = bcmgenet_rx_buf_len(new_mtu);
+	bcmgenet_set_mtu_regs(priv, new_mtu);
+
+	ret = bcmgenet_init_dma(priv, true);
+	if (ret) {
+		/* Retry the size that was allocated a moment ago */
+		WRITE_ONCE(dev->mtu, old_mtu);
+		priv->rx_buf_len = bcmgenet_rx_buf_len(old_mtu);
+		bcmgenet_set_mtu_regs(priv, old_mtu);
+		if (bcmgenet_init_dma(priv, true)) {
+			/* Nothing left to run on. Take the interface down so
+			 * that close and suspend do not tear it down twice.
+			 */
+			netdev_err(dev, "failed to restore MTU %u, closing\n",
+				   old_mtu);
+			netif_close(dev);
+
+			/* Mark the device present again, __dev_open()
+			 * refuses a detached one. The queues stay stopped
+			 * because the interface is down by now.
+			 */
+			netif_device_attach(dev);
+			return ret;
+		}
+	}
+
+	bcmgenet_hfb_restore(priv);
+	bcmgenet_netif_start(dev, false);
+
+	/* bcmgenet_netif_start() only restores the link interrupt */
+	if (bcmgenet_has_mdio_intr(priv))
+		bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_MDIO_EVENT,
+					 INTRL2_CPU_MASK_CLEAR);
+
+	/* A link event latched while the interrupts were off is gone. Internal
+	 * PHYs on GENET v1-v4 are not polled, so resync the state machine.
+	 */
+	phy_mac_interrupt(dev->phydev);
+
+	priv->datapath_up = true;
+	netif_device_attach(dev);
+
+	return ret;
+}
+
 static const struct net_device_ops bcmgenet_netdev_ops = {
 	.ndo_open		= bcmgenet_open,
 	.ndo_stop		= bcmgenet_close,
@@ -3747,6 +4025,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = {
 	.ndo_set_features	= bcmgenet_set_features,
 	.ndo_get_stats64	= bcmgenet_get_stats64,
 	.ndo_change_carrier	= bcmgenet_change_carrier,
+	.ndo_change_mtu		= bcmgenet_change_mtu,
 };
 
 /* GENET hardware parameters/characteristics */
@@ -4100,6 +4379,11 @@ static int bcmgenet_probe(struct platform_device *pdev)
 	/* Mii wait queue */
 	init_waitqueue_head(&priv->wq);
 	bcmgenet_hfb_init(priv);
+
+	/* v1 cannot program the thresholds, so it stays at the default MTU */
+	priv->rx_buf_len = bcmgenet_rx_buf_len(dev->mtu);
+	if (!GENET_IS_V1(priv))
+		dev->max_mtu = ENET_MAX_JUMBO_MTU;
 	INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task);
 
 	priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol");
@@ -4312,7 +4596,7 @@ static int bcmgenet_resume(struct device *d)
 	if (!device_may_wakeup(d))
 		phy_resume(dev->phydev);
 
-	bcmgenet_netif_start(dev);
+	bcmgenet_netif_start(dev, true);
 
 	netif_device_attach(dev);
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 86f2aed20dbe8..97c27b7920d53 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -28,13 +28,16 @@
 /* which ring is descriptor based */
 #define DESC_INDEX				16
 
-/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528.
- * 1536 is multiple of 256 bytes
- */
 #define ENET_BRCM_TAG_LEN	6
 #define ENET_PAD		8
-#define ENET_MAX_MTU_SIZE	(ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
-				 ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
+
+/* Longest frame the MAC must accept for a given MTU. ENET_PAD is slack the
+ * driver has always carried, it rounded the default up to 1536 from 1528.
+ */
+#define ENET_FRAME_OVERHEAD	(ETH_HLEN + VLAN_HLEN + ENET_BRCM_TAG_LEN + \
+				 ETH_FCS_LEN + ENET_PAD)
+#define ENET_MAX_FRAME_LEN(mtu)	((mtu) + ENET_FRAME_OVERHEAD)
+
 #define DMA_MAX_BURST_LENGTH    0x10
 
 /* misc. configuration */
@@ -219,6 +222,8 @@ struct bcmgenet_rx_stats64 {
 #define  RBUF_ALIGN_2B			(1 << 1)
 #define  RBUF_BAD_DIS			(1 << 2)
 
+#define RBUF_PKT_RDY_THLD		0x08
+
 #define RBUF_STATUS			0x0C
 #define  RBUF_STATUS_WOL		(1 << 0)
 #define  RBUF_STATUS_MPD_INTR_ACTIVE	(1 << 1)
@@ -249,6 +254,7 @@ struct bcmgenet_rx_stats64 {
 #define TBUF_CTRL			0x00
 #define  TBUF_64B_EN			(1 << 0)
 #define TBUF_BP_MC			0x0C
+#define TBUF_PKT_RDY_THLD		0x10
 #define TBUF_ENERGY_CTRL		0x14
 #define  TBUF_EEE_EN			(1 << 0)
 #define  TBUF_PM_EN			(1 << 1)
@@ -575,6 +581,8 @@ struct bcmgenet_rx_ring {
 	unsigned int	cb_ptr;		/* Rx ring initial CB ptr */
 	unsigned int	end_ptr;	/* Rx ring end CB ptr */
 	unsigned int	old_discards;
+	struct sk_buff	*frag_head;	/* frame being reassembled */
+	bool		frag_drop;	/* discarding until the next SOP */
 	struct bcmgenet_net_dim dim;
 	u32		rx_max_coalesced_frames;
 	u32		rx_coalesce_usecs;
@@ -613,6 +621,8 @@ struct bcmgenet_priv {
 	void __iomem *rx_bds;
 	struct enet_cb *rx_cbs;
 	unsigned int num_rx_bds;
+	unsigned int rx_buf_len;
+	unsigned int tx_thld_len;
 	struct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES];
 	struct list_head rxnfc_list;
 
@@ -624,6 +634,7 @@ struct bcmgenet_priv {
 	unsigned autoneg_pause:1;
 	unsigned tx_pause:1;
 	unsigned rx_pause:1;
+	unsigned datapath_up:1;
 
 	/* MDIO bus variables */
 	wait_queue_head_t wq;

3/2 2026/10/07 09:06 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 12778
							output: 40
							thoughts: 106
						

Thoughts:
**Analyzing a Kernel Git Commit: Deep Dive**

Okay, so the user wants me to dissect a specific git commit that's been applied to the kernel, targeting the amd64 architecture. That's a good starting point. Let's see what we're dealing with. The focus is on these files: `drivers/net/ethernet/broadcom/genet/bcmgenet.c` and `drivers/net/ethernet/broadcom/genet/bcmgenet.h`. Alright, I recognize those directory structures... broadcom... GENET...

Hmm, Broadcom GENET. My immediate thought is, I need to brush up on my knowledge of that specific driver. I can get a better handle on the changes if I know what it actually *does*. Is it a gigabit ethernet driver? Something specific to Broadcom hardware? Let's quickly search the kernel tree. I'll reach for grepper, or maybe even skim the relevant Kconfig files. Understanding the *purpose* of this GENET driver is absolutely critical before I can really analyze the commit effectively.



4/2 2026/10/07 09:07 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "BCMGENET",
  "PathPrefixes": [
    "drivers/net/ethernet/broadcom/genet/Kconfig"
  ]
}

Results:
{
  "error": "no matches"
}

5/2 2026/10/07 09:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 13170
							output: 30
							thoughts: 24
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Kconfig Location Hunt: Broadcom Ethernet**

Alright, let's get down to brass tacks. I need to locate the Kconfig file for Broadcom Ethernet drivers. Knowing Broadcom, the usual suspects are going to be under `drivers/net/ethernet/broadcom/` or perhaps `broadcom/genet/`. Given the potential for a more general network interface implementation in Broadcom's hardware, it might be in either place, depending on how they've organized their code. I'm leaning toward the first location as the more typical placement, but `broadcom/genet/` is also a valid possibility for generic Ethernet support. Time to dive into the directory structure and see what we find. I'm expecting to find features, modules, and hardware configurations there. I'll need to remember to check for any conditional inclusion statements, depending on the Broadcom Ethernet variant. Let's start the hunt and see what's in there!



6/2 2026/10/07 09:07 tool codesearch-dir-index
0m Args:
{
  "Dir": "drivers/net/ethernet/broadcom/genet"
}

Results:
{
  "Files": [
    "bcmgenet.c",
    "bcmgenet.h",
    "bcmgenet_wol.c",
    "bcmmii.c"
  ],
  "Subdirs": null
}

7/2 2026/10/07 09:07 llm patch-evaluator
1m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 13495
							output: 35
							thoughts: 17
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience and presented in the first person:

**Investigating the Broadcom Ethernet Driver Configuration**

Alright, let's dive into this. My initial thought is to zero in on the Broadcom Ethernet driver's Kconfig file, specifically within the `drivers/net/ethernet/broadcom/` directory. This is where the configuration options for that particular driver are defined, and it's the logical starting point for understanding how it's enabled, disabled, and customized within the kernel build system. I need to refresh my memory on what options are available and how they interact with the broader network stack. I anticipate finding things like support for specific Broadcom chipsets, features like VLAN offloading or checksum offloading, and potential configuration knobs for things like link speed negotiation and interrupt coalescing. The Kconfig file should illuminate the dependencies on other kernel features and any hardware platform limitations. I'm hoping it's well-commented, as is usually the case in the Linux kernel; otherwise, I will have some digging to do. This will give me a solid understanding of this driver and what it can and can't do.



8/2 2026/10/07 09:09 tool grepper
0m Args:
{
  "Expression": "BCMGENET",
  "PathPrefixes": [
    "drivers/net/ethernet/broadcom/"
  ]
}

Results:
{
  "Output": "\nFull output is too long, showing 200 out of 257 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (5 files in total):\ndrivers/net/ethernet/broadcom/Kconfig:1\ndrivers/net/ethernet/broadcom/Makefile:1\ndrivers/net/ethernet/broadcom/genet/Makefile:1\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:59\ndrivers/net/ethernet/broadcom/genet/bcmgenet.h:7\n\ndrivers/net/ethernet/broadcom/Kconfig=63=config BCM63XX_ENET\n--\ndrivers/net/ethernet/broadcom/Kconfig-71-\ndrivers/net/ethernet/broadcom/Kconfig:72:config BCMGENET\ndrivers/net/ethernet/broadcom/Kconfig-73-\ttristate \"Broadcom GENET internal MAC support\"\n--\ndrivers/net/ethernet/broadcom/Makefile=8=obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o\ndrivers/net/ethernet/broadcom/Makefile:9:obj-$(CONFIG_BCMGENET) += genet/\ndrivers/net/ethernet/broadcom/Makefile-10-obj-$(CONFIG_BNX2) += bnx2.o\n--\ndrivers/net/ethernet/broadcom/genet/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/net/ethernet/broadcom/genet/Makefile:2:obj-$(CONFIG_BCMGENET) += genet.o\ndrivers/net/ethernet/broadcom/genet/Makefile-3-genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=632=static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-732-\tbcmgenet_hfb_enable_filter(priv, f);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:733:\trule-\u003estate = BCMGENET_RXNFC_STATE_ENABLED;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-734-}\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=773=static void bcmgenet_hfb_init(struct bcmgenet_priv *priv)\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-779-\t\tINIT_LIST_HEAD(\u0026priv-\u003erxnfc_rules[i].list);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:780:\t\tpriv-\u003erxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-781-\t}\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=784=static void bcmgenet_hfb_restore(struct bcmgenet_priv *priv)\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-790-\tlist_for_each_entry(rule, \u0026priv-\u003erxnfc_list, list)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:791:\t\tif (rule-\u003estate != BCMGENET_RXNFC_STATE_UNUSED)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-792-\t\t\tbcmgenet_hfb_create_rxnfc_filter(priv, rule);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1015=enum bcmgenet_stat_type {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1016:\tBCMGENET_STAT_RTNL = -1,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1017:\tBCMGENET_STAT_MIB_RX,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1018:\tBCMGENET_STAT_MIB_TX,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1019:\tBCMGENET_STAT_RUNT,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1020:\tBCMGENET_STAT_MISC,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1021:\tBCMGENET_STAT_SOFT,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1022:\tBCMGENET_STAT_SOFT64,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1023-};\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1025=struct bcmgenet_stats {\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1039-\t.stat_offset = offsetof(struct rtnl_link_stats64, m), \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1040:\t.type = BCMGENET_STAT_RTNL, \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1041-}\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1053-\t.stat_offset = offsetof(struct bcmgenet_priv, s.m), \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1054:\t.type = BCMGENET_STAT_SOFT64, \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1055-\t.syncp_offset = offsetof(struct bcmgenet_priv, s.syncp), \\\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1057-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1058:#define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1059:#define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1060:#define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1061:#define STAT_GENET_SOFT_MIB(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_SOFT)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1062-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1066-\t.stat_offset = offsetof(struct bcmgenet_priv, m), \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1067:\t.type = BCMGENET_STAT_MISC, \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1068-\t.reg_offset = offset, \\\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1107- */\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1108:#define BCMGENET_STAT_OFFSET\t0xc\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1109-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1113=static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1212-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1213:#define BCMGENET_STATS_LEN\tARRAY_SIZE(bcmgenet_gstrings_stats)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1214-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1215:#define BCMGENET_STATS64_ADD(stats, m, v) \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1216-\tdo { \\\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1221-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1222:#define BCMGENET_STATS64_INC(stats, m) \\\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1223-\tdo { \\\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1235=static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1238-\tcase ETH_SS_STATS:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1239:\t\treturn BCMGENET_STATS_LEN;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1240-\tdefault:\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1245=static void bcmgenet_get_strings(struct net_device *dev, u32 stringset,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1252-\tcase ETH_SS_STATS:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1253:\t\tfor (i = 0; i \u003c BCMGENET_STATS_LEN; i++) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1254-\t\t\tstr = bcmgenet_gstrings_stats[i].stat_string;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1300=static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1303-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1304:\tfor (i = 0; i \u003c BCMGENET_STATS_LEN; i++) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1305-\t\tconst struct bcmgenet_stats *s;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1311-\t\tswitch (s-\u003etype) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1312:\t\tcase BCMGENET_STAT_RTNL:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1313:\t\tcase BCMGENET_STAT_SOFT:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1314:\t\tcase BCMGENET_STAT_SOFT64:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1315-\t\t\tcontinue;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1316:\t\tcase BCMGENET_STAT_RUNT:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1317:\t\t\toffset += BCMGENET_STAT_OFFSET;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1318-\t\t\tfallthrough;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1319:\t\tcase BCMGENET_STAT_MIB_TX:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1320:\t\t\toffset += BCMGENET_STAT_OFFSET;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1321-\t\t\tfallthrough;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1322:\t\tcase BCMGENET_STAT_MIB_RX:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1323-\t\t\tval = bcmgenet_umac_readl(priv,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1326-\t\t\tbreak;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1327:\t\tcase BCMGENET_STAT_MISC:\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1328-\t\t\tif (GENET_IS_V1(priv)) {\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1347=static void bcmgenet_get_ethtool_stats(struct net_device *dev,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1361-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1362:\tfor (i = 0; i \u003c BCMGENET_STATS_LEN; i++) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1363-\t\tconst struct bcmgenet_stats *s;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1368-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1369:\t\tif (s-\u003etype == BCMGENET_STAT_SOFT64) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1370-\t\t\tsyncp = (struct u64_stats_sync *)(p + s-\u003esyncp_offset);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1375-\t\t} else {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1376:\t\t\tif (s-\u003etype == BCMGENET_STAT_RTNL)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1377-\t\t\t\tp = (char *)\u0026stats64;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1533=static int bcmgenet_insert_flow(struct net_device *dev,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1567-\t\t\tloc_rule = \u0026priv-\u003erxnfc_rules[i];\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1568:\t\t\tif (loc_rule-\u003estate == BCMGENET_RXNFC_STATE_UNUSED) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1569-\t\t\t\tcmd-\u003efs.location = i;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1579-\t}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1580:\tif (loc_rule-\u003estate == BCMGENET_RXNFC_STATE_ENABLED)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1581-\t\tbcmgenet_hfb_disable_filter(priv, cmd-\u003efs.location + 1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1582:\tif (loc_rule-\u003estate != BCMGENET_RXNFC_STATE_UNUSED) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1583-\t\tlist_del(\u0026loc_rule-\u003elist);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1585-\t}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1586:\tloc_rule-\u003estate = BCMGENET_RXNFC_STATE_UNUSED;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1587-\tmemcpy(\u0026loc_rule-\u003efs, \u0026cmd-\u003efs,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1597=static int bcmgenet_delete_flow(struct net_device *dev,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1607-\trule = \u0026priv-\u003erxnfc_rules[cmd-\u003efs.location];\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1608:\tif (rule-\u003estate == BCMGENET_RXNFC_STATE_UNUSED) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1609-\t\terr =  -ENOENT;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1612-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1613:\tif (rule-\u003estate == BCMGENET_RXNFC_STATE_ENABLED)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1614-\t\tbcmgenet_hfb_disable_filter(priv, cmd-\u003efs.location + 1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1615:\tif (rule-\u003estate != BCMGENET_RXNFC_STATE_UNUSED) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1616-\t\tlist_del(\u0026rule-\u003elist);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1618-\t}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1619:\trule-\u003estate = BCMGENET_RXNFC_STATE_UNUSED;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1620-\tmemset(\u0026rule-\u003efs, 0, sizeof(struct ethtool_rx_flow_spec));\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=1647=static int bcmgenet_get_flow(struct net_device *dev, struct ethtool_rxnfc *cmd,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1657-\trule = \u0026priv-\u003erxnfc_rules[loc];\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:1658:\tif (rule-\u003estate == BCMGENET_RXNFC_STATE_UNUSED)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-1659-\t\terr = -ENOENT;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=2082=static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2102-\t\t\tpriv-\u003emib.tx_realloc_tsb_failed++;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:2103:\t\t\tBCMGENET_STATS64_INC(stats, dropped);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2104-\t\t\treturn NULL;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=2158=static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2192-\t\tif (skb_checksum_help(skb)) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:2193:\t\t\tBCMGENET_STATS64_INC((\u0026ring-\u003estats64), dropped);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2194-\t\t\tdev_kfree_skb_any(skb);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2202-\t\tif (skb_put_padto(skb, priv-\u003etx_thld_len + ENET_TX_SAFE_MARGIN)) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:2203:\t\t\tBCMGENET_STATS64_INC((\u0026ring-\u003estats64), dropped);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2204-\t\t\tgoto drop;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=2358=static struct sk_buff *bcmgenet_add_frag(struct bcmgenet_rx_ring *ring,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2367-\tif (unlikely(skb_shinfo(head)-\u003enr_frags \u003e= MAX_SKB_FRAGS)) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:2368:\t\tBCMGENET_STATS64_INC((\u0026ring-\u003estats64), fragmented_errors);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2369-\t\tbcmgenet_discard_frags(ring);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=2389=static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2414-\t\tdiscards = discards - ring-\u003eold_discards;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:2415:\t\tBCMGENET_STATS64_ADD(stats, missed, discards);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2416-\t\tring-\u003eold_discards += discards;\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2448-\t\tif (bcmgenet_rx_refill(ring, cb)) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:2449:\t\t\tBCMGENET_STATS64_INC(stats, dropped);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2450-\t\t\tbcmgenet_discard_frags(ring);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-2489-\t\t\t\t  \"invalid packet length %d\\n\", len);\n\n"
}

9/2 2026/10/07 09:09 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 19944
							output: 39
							thoughts: 28
						

Thoughts:
Here's a summary of my thought process, tailored for an expert like you:

**Investigating Broadcom Ethernet Driver Configuration**

Okay, so I need to dive into the configuration of the Broadcom Ethernet driver. My first instinct is to zero in on the relevant Kconfig file, specifically the one located at `drivers/net/ethernet/broadcom/Kconfig`. I'm guessing that line 72 is a likely starting point for the configuration options I'm interested in. I'll use `read-file` to grab that section of the Kconfig file and quickly assess what's defined there. Hopefully, that will give me the information I'm looking for.



10/2 2026/10/07 09:09 tool read-file
0m Args:
{
  "File": "drivers/net/ethernet/broadcom/Kconfig",
  "FirstLine": 70,
  "LineCount": 30
}

Results:
{
  "Contents": "  70:\t\t  MIPS chipset family (BCM63XX).\n  71:\t\n  72:\tconfig BCMGENET\n  73:\t\ttristate \"Broadcom GENET internal MAC support\"\n  74:\t\tdepends on HAS_IOMEM\n  75:\t\tdepends on PTP_1588_CLOCK_OPTIONAL || !ARCH_BCM2835\n  76:\t\tselect PHYLIB\n  77:\t\tselect FIXED_PHY\n  78:\t\tselect BCM7XXX_PHY\n  79:\t\tselect MDIO_BCM_UNIMAC\n  80:\t\tselect DIMLIB\n  81:\t\tselect PAGE_POOL\n  82:\t\tselect BROADCOM_PHY if ARCH_BCM2835\n  83:\t\thelp\n  84:\t\t  This driver supports the built-in Ethernet MACs found in the\n  85:\t\t  Broadcom BCM7xxx Set Top Box family chipset.\n  86:\t\n  87:\tconfig BNX2\n  88:\t\ttristate \"QLogic bnx2 support\"\n  89:\t\tdepends on PCI\n  90:\t\tselect CRC32\n  91:\t\tselect FW_LOADER\n  92:\t\thelp\n  93:\t\t  This driver supports QLogic bnx2 gigabit Ethernet cards.\n  94:\t\n  95:\t\t  To compile this driver as a module, choose M here: the module\n  96:\t\t  will be called bnx2.  This is recommended.\n  97:\t\n  98:\tconfig CNIC\n  99:\t\ttristate \"QLogic CNIC support\"\n"
}

11/2 2026/10/07 09:09 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 20564
							output: 49
							thoughts: 103
						

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

**BCMGENET Probe & Instantiation: A Quick Dive**

Alright, so `BCMGENET`... that's Broadcom's internal MAC support for their GENET architecture, baked into a bunch of BCM7xxx set-top box chips and the Raspberry Pi 4 (specifically the BCM2711 – which falls under the ARCH_BCM2835 umbrella). My initial question is always, "How does this thing actually get instantiated and probed into the system?" Is it a platform device, perhaps ACPI-driven, or even showing up as a PCI device? I need to clarify the system's awareness. I'll need to dig into the source code to get the answer. The probe function and the platform driver definition in `bcmgenet.c` will provide the critical information. Time to check the source.



12/2 2026/10/07 09:09 tool grepper
0m Args:
{
  "Expression": "module_platform_driver|platform_driver",
  "PathPrefixes": [
    "drivers/net/ethernet/broadcom/genet/bcmgenet.c"
  ]
}

Results:
{
  "Output": "drivers/net/ethernet/broadcom/genet/bcmgenet.c=4709=MODULE_DEVICE_TABLE(acpi, genet_acpi_match);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4710-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:4711:static struct platform_driver bcmgenet_driver = {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4712-\t.probe\t= bcmgenet_probe,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4721-};\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:4722:module_platform_driver(bcmgenet_driver);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4723-\n"
}

13/2 2026/10/07 09:09 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 21160
							output: 48
							thoughts: 43
						

Thoughts:
Okay, let's dive into this `bcmgenet` driver and figure out how the hardware is being identified. My initial thought is to confirm the matching mechanisms – is it going through ACPI or the Device Tree (OF)? A quick check of the code reveals that's the likely location for device initialization.

I'll specifically zero in on the `bcmgenet.c` file and jump towards line 4700 as a starting point. That region likely holds crucial device matching or initialization logic, I'll be looking for any hints about the matching process.



14/2 2026/10/07 09:10 tool read-file
0m Args:
{
  "File": "drivers/net/ethernet/broadcom/genet/bcmgenet.c",
  "FirstLine": 4690,
  "LineCount": 35
}

Results:
{
  "Contents": "4690:\t}\n4691:\t#else\n4692:\t#define bcmgenet_suspend\tNULL\n4693:\t#define bcmgenet_suspend_noirq\tNULL\n4694:\t#define bcmgenet_resume\t\tNULL\n4695:\t#define bcmgenet_resume_noirq\tNULL\n4696:\t#endif /* CONFIG_PM_SLEEP */\n4697:\t\n4698:\tstatic const struct dev_pm_ops bcmgenet_pm_ops = {\n4699:\t\t.suspend\t= bcmgenet_suspend,\n4700:\t\t.suspend_noirq\t= bcmgenet_suspend_noirq,\n4701:\t\t.resume\t\t= bcmgenet_resume,\n4702:\t\t.resume_noirq\t= bcmgenet_resume_noirq,\n4703:\t};\n4704:\t\n4705:\tstatic const struct acpi_device_id genet_acpi_match[] = {\n4706:\t\t{ \"BCM6E4E\", (kernel_ulong_t)\u0026bcm2711_plat_data },\n4707:\t\t{ },\n4708:\t};\n4709:\tMODULE_DEVICE_TABLE(acpi, genet_acpi_match);\n4710:\t\n4711:\tstatic struct platform_driver bcmgenet_driver = {\n4712:\t\t.probe\t= bcmgenet_probe,\n4713:\t\t.remove = bcmgenet_remove,\n4714:\t\t.shutdown = bcmgenet_shutdown,\n4715:\t\t.driver\t= {\n4716:\t\t\t.name\t= \"bcmgenet\",\n4717:\t\t\t.of_match_table = bcmgenet_match,\n4718:\t\t\t.pm\t= \u0026bcmgenet_pm_ops,\n4719:\t\t\t.acpi_match_table = genet_acpi_match,\n4720:\t\t},\n4721:\t};\n4722:\tmodule_platform_driver(bcmgenet_driver);\n4723:\t\n4724:\tMODULE_AUTHOR(\"Broadcom Corporation\");\n"
}

15/2 2026/10/07 09:10 llm patch-evaluator
1m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 21960
							output: 46
							thoughts: 62
						

Thoughts:
Okay, let's break this down.

**Decoding ACPI and Device Tree Matches**

Right, so I'm looking at this code and first I see `genet_acpi_match`, and that immediately tells me we're dealing with ACPI, specifically "BCM6E4E". Ah, yes, that rings a bell – Raspberry Pi 4 UEFI / ACPI. Classic. Now, the interesting part is seeing how this links with the Open Firmware side. The `OF match table` is `bcmgenet_match`. That's the key. Now, the next logical step is to dive right into the `bcmgenet_match` table and see what that's all about. That’ll tell me the relevant Device Tree binding information for this setup.



16/2 2026/10/07 09:12 tool grepper
0m Args:
{
  "Expression": "bcmgenet_match",
  "PathPrefixes": [
    "drivers/net/ethernet/broadcom/genet/bcmgenet.c"
  ]
}

Results:
{
  "Output": "drivers/net/ethernet/broadcom/genet/bcmgenet.c=4251=static const struct bcmgenet_plat_data bcm7712_plat_data = {\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4258-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:4259:static const struct of_device_id bcmgenet_match[] = {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4260-\t{ .compatible = \"brcm,genet-v1\", .data = \u0026v1_plat_data },\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4268-};\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:4269:MODULE_DEVICE_TABLE(of, bcmgenet_match);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4270-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=4711=static struct platform_driver bcmgenet_driver = {\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4716-\t\t.name\t= \"bcmgenet\",\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:4717:\t\t.of_match_table = bcmgenet_match,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4718-\t\t.pm\t= \u0026bcmgenet_pm_ops,\n"
}

17/2 2026/10/07 09:12 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 22678
							output: 29
							thoughts: 800
						

Thoughts:
**Analyzing the Reachability of `bcmgenet` for Fuzzing on amd64**

Okay, so the fundamental principle is clear: fuzzing is only effective on code that's *reachable* in a standard virtualized environment like QEMU or GCE. Right, if the code's structurally unreachable, no fuzzing, no matter what it does. That's the gate.

Now, considering `bcmgenet`, the question becomes: can this thing *actually* run on amd64 within a standard virtualized environment? And by that, I mean an environment where I can reliably execute code.

The text points out several negative criteria, like vendor-specific hardware requiring dedicated physical cards or drivers that get triggered only during specific hardware operations, and the critical point here is that my target architecture is *amd64*.

First, let's establish a baseline: can `bcmgenet` even *be* probed or used on amd64 in a standard setup? Is it emulated in QEMU? I know QEMU has Raspberry Pi emulation, using arm or arm64 architecture, and that might include some bcm drivers, but even then, does that really include bcmgenet or not? My mind is focusing on the amd64 architecture.

The critical issue is the target architecture, which is *amd64*! Can I even *instantiate* `bcmgenet` on amd64? Can I create a platform device with the "BCM6E4E" or "brcm,genet-*" compatible string on amd64?

And how would that even happen? Can userspace instantiate platform devices on amd64 via sysfs or configfs? Linux and Syzkaller, are they even capable of creating arbitrary platform devices, or is it going to be a custom system? The text notes that syzkaller needs a specific subsystem or driver. Hmm... x86/amd64 doesn't use a device tree in the standard QEMU setup, unless it's configured for ACPI. But those ACPI tables, the emulated tables, they're provided by QEMU/firmware, and the standard QEMU x86 setups (e.g., `pc` or `q35`) don't have this Broadcom GENET in ACPI. I see, so it will be a no.

Let's be clear: does QEMU even have `bcmgenet` *hardware* emulation on x86/amd64? No. The standard QEMU x86 emulations are e1000, e1000e, virtio-net, etc.. It is an on-SoC Ethernet MAC exclusively found in Broadcom STB chips (BCM7xxx) and Raspberry Pi 4/5 (BCM2711 / BCM2712).

But wait, does QEMU even emulate `bcmgenet` on *any* architecture? Even the arm emulation doesn't have it natively, although it's included in newer versions, but the important detail here is my target architecture is amd64!

Ok, I'll stop to check references to bcmgenet in the kernel.



18/2 2026/10/07 09:13 tool grepper
0m Args:
{
  "Expression": "bcmgenet",
  "PathPrefixes": [
    "drivers/net/"
  ]
}

Results:
{
  "Output": "\nFull output is too long, showing 200 out of 2758 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (5 files in total):\ndrivers/net/ethernet/broadcom/genet/Makefile:1\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:755\ndrivers/net/ethernet/broadcom/genet/bcmgenet.h:56\ndrivers/net/ethernet/broadcom/genet/bcmgenet_wol.c:36\ndrivers/net/ethernet/broadcom/genet/bcmmii.c:64\n\ndrivers/net/ethernet/broadcom/genet/Makefile=2=obj-$(CONFIG_BCMGENET) += genet.o\ndrivers/net/ethernet/broadcom/genet/Makefile:3:genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-7-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:8:#define pr_fmt(fmt)\t\t\t\t\"bcmgenet: \" fmt\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-9-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-40-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:41:#include \"bcmgenet.h\"\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-42-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-100-/* Forward declarations */\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:101:static void bcmgenet_set_rx_mode(struct net_device *dev);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-102-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:103:static inline void bcmgenet_writel(u32 value, void __iomem *offset)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-104-{\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-113-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:114:static inline u32 bcmgenet_readl(void __iomem *offset)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-115-{\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-121-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:122:static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-123-\t\t\t\t\t     void __iomem *d, u32 value)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-124-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:125:\tbcmgenet_writel(value, d + DMA_DESC_LENGTH_STATUS);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-126-}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-127-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:128:static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-129-\t\t\t\t    void __iomem *d,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-131-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:132:\tbcmgenet_writel(lower_32_bits(addr), d + DMA_DESC_ADDRESS_LO);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-133-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-138-#ifdef CONFIG_PHYS_ADDR_T_64BIT\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:139:\tif (bcmgenet_has_40bits(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:140:\t\tbcmgenet_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-141-#endif\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-144-/* Combined address + length/status setter */\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:145:static inline void dmadesc_set(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-146-\t\t\t       void __iomem *d, dma_addr_t addr, u32 val)\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-156-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:157:static inline u32 bcmgenet_rbuf_ctrl_get(struct bcmgenet_priv *priv)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-158-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-159-\tif (GENET_IS_V1(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:160:\t\treturn bcmgenet_rbuf_readl(priv, RBUF_FLUSH_CTRL_V1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-161-\telse\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:162:\t\treturn bcmgenet_sys_readl(priv, SYS_RBUF_FLUSH_CTRL);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-163-}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-164-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:165:static inline void bcmgenet_rbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-166-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-167-\tif (GENET_IS_V1(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:168:\t\tbcmgenet_rbuf_writel(priv, val, RBUF_FLUSH_CTRL_V1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-169-\telse\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:170:\t\tbcmgenet_sys_writel(priv, val, SYS_RBUF_FLUSH_CTRL);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-171-}\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-176- */\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:177:static inline u32 bcmgenet_tbuf_ctrl_get(struct bcmgenet_priv *priv)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-178-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-179-\tif (GENET_IS_V1(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:180:\t\treturn bcmgenet_rbuf_readl(priv, TBUF_CTRL_V1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-181-\telse\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:182:\t\treturn bcmgenet_readl(priv-\u003ebase +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-183-\t\t\t\t      priv-\u003ehw_params-\u003etbuf_offset + TBUF_CTRL);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-185-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:186:static inline void bcmgenet_tbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-187-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-188-\tif (GENET_IS_V1(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:189:\t\tbcmgenet_rbuf_writel(priv, val, TBUF_CTRL_V1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-190-\telse\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:191:\t\tbcmgenet_writel(val, priv-\u003ebase +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-192-\t\t\t\tpriv-\u003ehw_params-\u003etbuf_offset + TBUF_CTRL);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-194-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:195:static inline u32 bcmgenet_bp_mc_get(struct bcmgenet_priv *priv)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-196-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-197-\tif (GENET_IS_V1(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:198:\t\treturn bcmgenet_rbuf_readl(priv, TBUF_BP_MC_V1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-199-\telse\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:200:\t\treturn bcmgenet_readl(priv-\u003ebase +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-201-\t\t\t\t      priv-\u003ehw_params-\u003etbuf_offset + TBUF_BP_MC);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-203-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:204:static inline void bcmgenet_bp_mc_set(struct bcmgenet_priv *priv, u32 val)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-205-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-206-\tif (GENET_IS_V1(priv))\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:207:\t\tbcmgenet_rbuf_writel(priv, val, TBUF_BP_MC_V1);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-208-\telse\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:209:\t\tbcmgenet_writel(val, priv-\u003ebase +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-210-\t\t\t\tpriv-\u003ehw_params-\u003etbuf_offset + TBUF_BP_MC);\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=214=enum dma_reg {\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-249-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:250:static const u8 bcmgenet_dma_regs_v3plus[] = {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-251-\t[DMA_RING_CFG]\t\t= 0x00,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-285-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:286:static const u8 bcmgenet_dma_regs_v2[] = {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-287-\t[DMA_RING_CFG]\t\t= 0x00,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-313-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:314:static const u8 bcmgenet_dma_regs_v1[] = {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-315-\t[DMA_CTRL]\t\t= 0x00,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-340-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:341:/* Set at runtime once bcmgenet version is known */\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:342:static const u8 *bcmgenet_dma_regs;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-343-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:344:static inline struct bcmgenet_priv *dev_to_priv(struct device *dev)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-345-{\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-348-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:349:static inline u32 bcmgenet_tdma_readl(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-350-\t\t\t\t      enum dma_reg r)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-351-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:352:\treturn bcmgenet_readl(priv-\u003ebase + GENET_TDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:353:\t\t\t      DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-354-}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-355-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:356:static inline void bcmgenet_tdma_writel(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-357-\t\t\t\t\tu32 val, enum dma_reg r)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-358-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:359:\tbcmgenet_writel(val, priv-\u003ebase + GENET_TDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:360:\t\t\tDMA_RINGS_SIZE + bcmgenet_dma_regs[r]);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-361-}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-362-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:363:static inline u32 bcmgenet_rdma_readl(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-364-\t\t\t\t      enum dma_reg r)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-365-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:366:\treturn bcmgenet_readl(priv-\u003ebase + GENET_RDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:367:\t\t\t      DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-368-}\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-369-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:370:static inline void bcmgenet_rdma_writel(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-371-\t\t\t\t\tu32 val, enum dma_reg r)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-372-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:373:\tbcmgenet_writel(val, priv-\u003ebase + GENET_RDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:374:\t\t\tDMA_RINGS_SIZE + bcmgenet_dma_regs[r]);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-375-}\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c=438=static const u8 *genet_dma_ring_regs;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-439-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:440:static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-441-\t\t\t\t\t   unsigned int ring,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-443-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:444:\treturn bcmgenet_readl(priv-\u003ebase + GENET_TDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-445-\t\t\t      (DMA_RING_SIZE * ring) +\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-448-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:449:static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-450-\t\t\t\t\t     unsigned int ring, u32 val,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-452-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:453:\tbcmgenet_writel(val, priv-\u003ebase + GENET_TDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-454-\t\t\t(DMA_RING_SIZE * ring) +\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-457-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:458:static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-459-\t\t\t\t\t   unsigned int ring,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-461-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:462:\treturn bcmgenet_readl(priv-\u003ebase + GENET_RDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-463-\t\t\t      (DMA_RING_SIZE * ring) +\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-466-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:467:static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv,\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-468-\t\t\t\t\t     unsigned int ring, u32 val,\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-470-{\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:471:\tbcmgenet_writel(val, priv-\u003ebase + GENET_RDMA_REG_OFF +\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-472-\t\t\t(DMA_RING_SIZE * ring) +\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-475-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:476:static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-477-{\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-481-\tif (GENET_IS_V1(priv) || GENET_IS_V2(priv)) {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:482:\t\treg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-483-\t\treg |= (1 \u003c\u003c ((f_index % 32) + RBUF_HFB_FILTER_EN_SHIFT)) |\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-484-\t\t\tRBUF_HFB_EN;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:485:\t\tbcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-486-\t} else {\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-487-\t\toffset = HFB_FLT_ENABLE_V3PLUS + (f_index \u003c 32) * sizeof(u32);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:488:\t\treg = bcmgenet_hfb_reg_readl(priv, offset);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-489-\t\treg |= (1 \u003c\u003c (f_index % 32));\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:490:\t\tbcmgenet_hfb_reg_writel(priv, reg, offset);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:491:\t\treg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-492-\t\treg |= RBUF_HFB_EN;\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:493:\t\tbcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-494-\t}\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-496-\n\n"
}

19/2 2026/10/07 09:13 llm patch-evaluator
1m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30673
							output: 48
							thoughts: 30
						

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

**Analyzing `bcmgenet_probe`**

Okay, let's dive into `bcmgenet_probe`. I need to quickly ascertain a few key things here. First, I need to understand how this probe function handles resource acquisition. Is it grabbing memory regions, IRQs, clocks? Are there any subtle issues with resource sharing or conflicts I should be aware of, perhaps with other device drivers? And a related question, is this strictly a platform driver, or is there a more complex device model at play here? Is it using something like a generic PHY driver? I need to get a handle on the overall resource management strategy employed here to start with. Let's see how that's handled.



20/2 2026/10/07 09:14 tool read-file
0m Args:
{
  "File": "drivers/net/ethernet/broadcom/genet/bcmgenet.c",
  "FirstLine": 4080,
  "LineCount": 80
}

Results:
{
  "Contents": "4080:\t\t.rdma_offset = 0x10000,\n4081:\t\t.tdma_offset = 0x11000,\n4082:\t\t.words_per_bd = 2,\n4083:\t};\n4084:\t\n4085:\tstatic const struct bcmgenet_hw_params bcmgenet_hw_params_v4 = {\n4086:\t\t.tx_queues = 4,\n4087:\t\t.tx_bds_per_q = 32,\n4088:\t\t.rx_queues = 0,\n4089:\t\t.rx_bds_per_q = 0,\n4090:\t\t.bp_in_en_shift = 17,\n4091:\t\t.bp_in_mask = 0x1ffff,\n4092:\t\t.hfb_filter_cnt = 48,\n4093:\t\t.hfb_filter_size = 128,\n4094:\t\t.qtag_mask = 0x3F,\n4095:\t\t.tbuf_offset = 0x0600,\n4096:\t\t.hfb_offset = 0x8000,\n4097:\t\t.hfb_reg_offset = 0xfc00,\n4098:\t\t.rdma_offset = 0x2000,\n4099:\t\t.tdma_offset = 0x4000,\n4100:\t\t.words_per_bd = 3,\n4101:\t};\n4102:\t\n4103:\t/* Infer hardware parameters from the detected GENET version */\n4104:\tstatic void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)\n4105:\t{\n4106:\t\tconst struct bcmgenet_hw_params *params;\n4107:\t\tu32 reg;\n4108:\t\tu8 major;\n4109:\t\tu16 gphy_rev;\n4110:\t\n4111:\t\t/* default to latest values */\n4112:\t\tparams = \u0026bcmgenet_hw_params_v4;\n4113:\t\tbcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;\n4114:\t\tgenet_dma_ring_regs = genet_dma_ring_regs_v4;\n4115:\t\tif (GENET_IS_V3(priv)) {\n4116:\t\t\tparams = \u0026bcmgenet_hw_params_v3;\n4117:\t\t\tbcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;\n4118:\t\t\tgenet_dma_ring_regs = genet_dma_ring_regs_v123;\n4119:\t\t} else if (GENET_IS_V2(priv)) {\n4120:\t\t\tparams = \u0026bcmgenet_hw_params_v2;\n4121:\t\t\tbcmgenet_dma_regs = bcmgenet_dma_regs_v2;\n4122:\t\t\tgenet_dma_ring_regs = genet_dma_ring_regs_v123;\n4123:\t\t} else if (GENET_IS_V1(priv)) {\n4124:\t\t\tparams = \u0026bcmgenet_hw_params_v1;\n4125:\t\t\tbcmgenet_dma_regs = bcmgenet_dma_regs_v1;\n4126:\t\t\tgenet_dma_ring_regs = genet_dma_ring_regs_v123;\n4127:\t\t}\n4128:\t\tpriv-\u003ehw_params = params;\n4129:\t\n4130:\t\t/* Read GENET HW version */\n4131:\t\treg = bcmgenet_sys_readl(priv, SYS_REV_CTRL);\n4132:\t\tmajor = (reg \u003e\u003e 24 \u0026 0x0f);\n4133:\t\tif (major == 6 || major == 7)\n4134:\t\t\tmajor = 5;\n4135:\t\telse if (major == 5)\n4136:\t\t\tmajor = 4;\n4137:\t\telse if (major == 0)\n4138:\t\t\tmajor = 1;\n4139:\t\tif (major != priv-\u003eversion) {\n4140:\t\t\tdev_err(\u0026priv-\u003epdev-\u003edev,\n4141:\t\t\t\t\"GENET version mismatch, got: %d, configured for: %d\\n\",\n4142:\t\t\t\tmajor, priv-\u003eversion);\n4143:\t\t}\n4144:\t\n4145:\t\t/* Print the GENET core version */\n4146:\t\tdev_info(\u0026priv-\u003epdev-\u003edev, \"GENET \" GENET_VER_FMT,\n4147:\t\t\t major, (reg \u003e\u003e 16) \u0026 0x0f, reg \u0026 0xffff);\n4148:\t\n4149:\t\t/* Store the integrated PHY revision for the MDIO probing function\n4150:\t\t * to pass this information to the PHY driver. The PHY driver expects\n4151:\t\t * to find the PHY major revision in bits 15:8 while the GENET register\n4152:\t\t * stores that information in bits 7:0, account for that.\n4153:\t\t *\n4154:\t\t * On newer chips, starting with PHY revision G0, a new scheme is\n4155:\t\t * deployed similar to the Starfighter 2 switch with GPHY major\n4156:\t\t * revision in bits 15:8 and patch level in bits 7:0. Major revision 0\n4157:\t\t * is reserved as well as special value 0x01ff, we have a small\n4158:\t\t * heuristic to check for the new GPHY revision and re-arrange things\n4159:\t\t * so the GPHY driver is happy.\n"
}

21/2 2026/10/07 09:14 llm patch-evaluator
1m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 32457
							output: 47
							thoughts: 15
						

Thoughts:
Here's my take on the thought process, summarized as you requested:

**Diving into the bcmgenet_probe Function**

Okay, time to get to the heart of the matter. I need to understand how this Broadcom Gigabit Ethernet driver initializes. The logical starting point is `bcmgenet_probe`. I'll go straight to those initial lines of code – the first few lines of `bcmgenet_probe` will give me the first clues. I need to grasp the very beginning of the probing process, see what checks it's doing first, and what its overall strategy is. It will be the foundation to understanding the rest of the probe.



22/2 2026/10/07 09:15 tool grepper
0m Args:
{
  "Expression": "bcmgenet_probe\\(",
  "PathPrefixes": [
    "drivers/net/ethernet/broadcom/genet/bcmgenet.c"
  ]
}

Results:
{
  "Output": "drivers/net/ethernet/broadcom/genet/bcmgenet.c=4269=MODULE_DEVICE_TABLE(of, bcmgenet_match);\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4270-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:4271:static int bcmgenet_probe(struct platform_device *pdev)\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-4272-{\n"
}

23/2 2026/10/07 09:15 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 32809
							output: 48
							thoughts: 20
						

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

**Diving into `bcmgenet_probe`**

Alright, let's zero in on `bcmgenet_probe`. That's where the rubber meets the road, isn't it? Line 4271 should be a good starting point. I want to see how this driver is initialized – the core hardware configuration, resource allocation, and device registration. Specifically, I'm looking for the sequence of events. Where's the bus probing happening? What's the interrupt setup look like? I'm assuming it's handling the usual suspects: memory mapping, DMA setup, and PHY initialization. The `probe` routine is the make or break point. This is where you see if the driver correctly identifies the hardware and sets itself up for smooth operation. From there, I'll be looking for common gotchas, the error handling, and anything particularly clever in its approach to interrupt management and buffer handling. This is where I can quickly identify possible performance bottlenecks or subtle race conditions.



24/2 2026/10/07 09:16 tool read-file
0m Args:
{
  "File": "drivers/net/ethernet/broadcom/genet/bcmgenet.c",
  "FirstLine": 4271,
  "LineCount": 80
}

Results:
{
  "Contents": "4271:\tstatic int bcmgenet_probe(struct platform_device *pdev)\n4272:\t{\n4273:\t\tconst struct bcmgenet_plat_data *pdata;\n4274:\t\tstruct bcmgenet_priv *priv;\n4275:\t\tstruct net_device *dev;\n4276:\t\tunsigned int i;\n4277:\t\tint err = -EIO;\n4278:\t\n4279:\t\t/* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */\n4280:\t\tdev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1,\n4281:\t\t\t\t\t GENET_MAX_MQ_CNT + 1);\n4282:\t\tif (!dev) {\n4283:\t\t\tdev_err(\u0026pdev-\u003edev, \"can't allocate net device\\n\");\n4284:\t\t\treturn -ENOMEM;\n4285:\t\t}\n4286:\t\n4287:\t\tpriv = netdev_priv(dev);\n4288:\t\tpriv-\u003eirq0 = platform_get_irq(pdev, 0);\n4289:\t\tif (priv-\u003eirq0 \u003c 0) {\n4290:\t\t\terr = priv-\u003eirq0;\n4291:\t\t\tgoto err;\n4292:\t\t}\n4293:\t\tpriv-\u003eirq1 = platform_get_irq(pdev, 1);\n4294:\t\tif (priv-\u003eirq1 \u003c 0) {\n4295:\t\t\terr = priv-\u003eirq1;\n4296:\t\t\tgoto err;\n4297:\t\t}\n4298:\t\tpriv-\u003ewol_irq = platform_get_irq_optional(pdev, 2);\n4299:\t\tif (priv-\u003ewol_irq == -EPROBE_DEFER) {\n4300:\t\t\terr = priv-\u003ewol_irq;\n4301:\t\t\tgoto err;\n4302:\t\t}\n4303:\t\n4304:\t\tpriv-\u003ebase = devm_platform_ioremap_resource(pdev, 0);\n4305:\t\tif (IS_ERR(priv-\u003ebase)) {\n4306:\t\t\terr = PTR_ERR(priv-\u003ebase);\n4307:\t\t\tgoto err;\n4308:\t\t}\n4309:\t\n4310:\t\tspin_lock_init(\u0026priv-\u003ereg_lock);\n4311:\t\tspin_lock_init(\u0026priv-\u003elock);\n4312:\t\n4313:\t\t/* Set default pause parameters */\n4314:\t\tpriv-\u003eautoneg_pause = 1;\n4315:\t\tpriv-\u003etx_pause = 1;\n4316:\t\tpriv-\u003erx_pause = 1;\n4317:\t\n4318:\t\tSET_NETDEV_DEV(dev, \u0026pdev-\u003edev);\n4319:\t\tdev_set_drvdata(\u0026pdev-\u003edev, dev);\n4320:\t\tdev-\u003ewatchdog_timeo = 2 * HZ;\n4321:\t\tdev-\u003eethtool_ops = \u0026bcmgenet_ethtool_ops;\n4322:\t\tdev-\u003enetdev_ops = \u0026bcmgenet_netdev_ops;\n4323:\t\n4324:\t\tpriv-\u003emsg_enable = netif_msg_init(-1, GENET_MSG_DEFAULT);\n4325:\t\n4326:\t\t/* Set default features */\n4327:\t\tdev-\u003efeatures |= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM |\n4328:\t\t\t\t NETIF_F_RXCSUM;\n4329:\t\tdev-\u003ehw_features |= dev-\u003efeatures;\n4330:\t\tdev-\u003evlan_features |= dev-\u003efeatures;\n4331:\t\n4332:\t\tnetdev_sw_irq_coalesce_default_on(dev);\n4333:\t\n4334:\t\t/* Request the WOL interrupt and advertise suspend if available */\n4335:\t\tpriv-\u003ewol_irq_disabled = true;\n4336:\t\tif (priv-\u003ewol_irq \u003e 0) {\n4337:\t\t\terr = devm_request_irq(\u0026pdev-\u003edev, priv-\u003ewol_irq,\n4338:\t\t\t\t\t       bcmgenet_wol_isr, 0, dev-\u003ename, priv);\n4339:\t\t\tif (!err)\n4340:\t\t\t\tdevice_set_wakeup_capable(\u0026pdev-\u003edev, 1);\n4341:\t\t}\n4342:\t\n4343:\t\t/* Set the needed headroom to account for any possible\n4344:\t\t * features enabling/disabling at runtime\n4345:\t\t */\n4346:\t\tdev-\u003eneeded_headroom += 64;\n4347:\t\n4348:\t\tpriv-\u003edev = dev;\n4349:\t\tpriv-\u003epdev = pdev;\n4350:\t\n"
}

25/2 2026/10/07 09:16 llm patch-evaluator
1m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 34403
							output: 20
							thoughts: 1184
						

Thoughts:
**WorthFuzzing Assessment: Negative**

Okay, here's the breakdown.  I'm looking at this code and immediately see a problem: it's all about Broadcom GENET.  Specifically, `priv->irq0 = platform_get_irq(pdev, 0);`, `priv->irq1 = platform_get_irq(pdev, 1);`, and `priv->base = devm_platform_ioremap_resource(pdev, 0);` scream "platform device, hardware-specific."  It's fetching IRQs and MMIO regions, which is a big red flag.

Then I note the driver matching: OF compatible strings like "brcm,genet-v1" and the ACPI ID "BCM6E4E", which is Raspberry Pi 4 territory.  The question immediately becomes: Can this *ever* be reached in a standard, virtualized environment like QEMU or Google Compute Engine (GCE) on amd64?

I go straight to the instructions, section 2: "WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)."  This is critical.  The relevant sections are: "Structurally unreachable hardware: Vendor-specific PCIe switches, SmartNICs, or GPU drivers... requiring physical ASIC/PCIe cards not emulated in standard QEMU" and "Code paths exclusive to architectures other than the target architecture."

Broadcom GENET is clearly an on-chip Ethernet MAC controller used in Broadcom BCM7xxx/BCM2711 SoCs.  These are ARM/MIPS chips!  QEMU on amd64 emulates standard PC hardware, not Broadcom GENET.  It uses things like e1000, rtl8139, and virtio-net, none of which is a BCMGENET device. There's no Broadcom GENET emulation *at all* on x86/amd64. Even in QEMU's arm/aarch64 emulation, which sometimes can target the raspi4/bcm2838, there is no emulation for bcmgenet or a device of that type.

Could I somehow *fake* it?  Can userspace create a platform device that this driver would bind to on amd64? No way. Platform devices are created by the kernel, via board files, Device Tree, or ACPI, or perhaps something like uio or vfio, but none of these approaches would attach to `bcmgenet_driver`. This doesn't have a USB interface, a virtio interface, or a PCI interface. There's no back door.

The instructions are clear: "REACHABILITY IS THE PRIMARY GATE."  This code is *structurally unreachable* given the target architecture, amd64. Even if it added assertions or complex logic.  The *target* is amd64, and the code modifies `bcmgenet.c` and `bcmgenet.h`, which are *solely* within `drivers/net/ethernet/broadcom/genet/`.

Therefore, the verdict is **WorthFuzzing=false**.



26/2 2026/10/07 09:18 tool grepper
0m Args:
{
  "Expression": "bcmgenet\\.h"
}

Results:
{
  "Output": "drivers/net/ethernet/broadcom/genet/bcmgenet.c-40-\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c:41:#include \"bcmgenet.h\"\ndrivers/net/ethernet/broadcom/genet/bcmgenet.c-42-\n--\ndrivers/net/ethernet/broadcom/genet/bcmgenet_wol.c-34-\ndrivers/net/ethernet/broadcom/genet/bcmgenet_wol.c:35:#include \"bcmgenet.h\"\ndrivers/net/ethernet/broadcom/genet/bcmgenet_wol.c-36-\n--\ndrivers/net/ethernet/broadcom/genet/bcmmii.c-24-\ndrivers/net/ethernet/broadcom/genet/bcmmii.c:25:#include \"bcmgenet.h\"\ndrivers/net/ethernet/broadcom/genet/bcmmii.c-26-\n"
}

27/2 2026/10/07 09:18 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36551
							output: 150
							thoughts: 770
						

Thoughts:
**WorthFuzzing Assessment: bcmgenet Driver on amd64**

Okay, let's break this down. My analysis indicates that the `bcmgenet` driver, specifically within the `drivers/net/ethernet/broadcom/genet/` directory, presents a clear case for `WorthFuzzing = false`. The logic is as follows:

First, this driver, defined by `bcmgenet.h` and `bcmgenet.c`, is exclusively built when `CONFIG_BCMGENET` is enabled. It registers `bcmgenet_driver`, a platform driver. This driver is *only* meant to support Broadcom GENET MACs found in specific Broadcom SoCs like the BCM7xxx set-top boxes, and the BCM2711/BCM2712 found in Raspberry Pi 4/5.

Crucially, my target architecture is amd64. I know that standard virtualized environments like QEMU and GCE, which I'm using for syzkaller fuzzing, *do not* emulate Broadcom GENET hardware. They don't instantiate platform devices for this. So, the driver's probe function will never execute. This means the device is never created, and all its core functions, like `bcmgenet_xmit`, `bcmgenet_desc_rx`, and `bcmgenet_change_mtu`, are fundamentally unreachable during my fuzzing efforts.

This aligns perfectly with the guidance. The documentation explicitly states that I *must not* fuzz code that is structurally unreachable, especially in the context of standard virtualized environments. The scenario of vendor-specific hardware or architectures other than the target is explicitly mentioned as a reason to return `WorthFuzzing = false`.

I have confirmed this:

1.  My changes are confined to the `bcmgenet` driver.
2.  The target hardware is not available on amd64 in my fuzzing environment.
3.  The driver relies on platform device bindings specific to the Broadcom SoCs and not emulated.
4.  Consequently, the code paths are unreachable.

Therefore, the decision is straightforward. Given the architecture mismatch and the lack of emulated hardware, this is an easy `WorthFuzzing = false`. No `FocusSymbols` or `EnableConfigs` are needed. All the provided guidance points towards this determination, and there's no reason to question the logic. I can proceed to set the results accordingly.



28/2 2026/10/07 09:18 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The changes are entirely confined to the Broadcom GENET Ethernet driver (drivers/net/ethernet/broadcom/genet/). Broadcom GENET is an on-SoC MAC found in Broadcom BCM7xxx and BCM2711 (Raspberry Pi 4) architectures. It is a platform driver requiring specific MMIO and IRQ resources that are not present or emulated in standard virtualized environments (QEMU/GCE) on the target architecture (amd64). Because the hardware is structurally unreachable, syzkaller cannot execute this code.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The changes are entirely confined to the Broadcom GENET Ethernet driver (drivers/net/ethernet/broadcom/genet/). Broadcom GENET is an on-SoC MAC found in Broadcom BCM7xxx and BCM2711 (Raspberry Pi 4) architectures. It is a platform driver requiring specific MMIO and IRQ resources that are not present or emulated in standard virtualized environments (QEMU/GCE) on the target architecture (amd64). Because the hardware is structurally unreachable, syzkaller cannot execute this code.",
  "WorthFuzzing": false
}

29/1 2026/10/07 09:18 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)