AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The changes in this patch series exclusively modify the IBM EMAC network device driver (drivers/net/ethernet/ibm/emac/), which depends on CONFIG_PPC_DCR (PowerPC Device Control Register support). This driver is specific to PowerPC architectures (IBM/AMCC PowerPC 4xx SoCs) and cannot be compiled or executed on the target architecture (amd64).",
  "WorthFuzzing": false
}

1/1 2026/11/02 10:03 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit dd7447ed502ea93ce17e6918a5f4a6795f95e347\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Mon Nov 2 10:03:34 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/ibm/emac/Kconfig b/drivers/net/ethernet/ibm/emac/Kconfig\nindex c8e5de5987ac60..8779c5b6a2c34f 100644\n--- a/drivers/net/ethernet/ibm/emac/Kconfig\n+++ b/drivers/net/ethernet/ibm/emac/Kconfig\n@@ -3,6 +3,7 @@ config IBM_EMAC\n \ttristate \"IBM EMAC Ethernet support\"\n \tdepends on PPC_DCR\n \tselect CRC32\n+\tselect PAGE_POOL\n \tselect PHYLIB\n \thelp\n \t  This driver supports the IBM EMAC family of Ethernet controllers\ndiff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c\nindex 640618c0a09e9a..9496c09d7a7cfd 100644\n--- a/drivers/net/ethernet/ibm/emac/core.c\n+++ b/drivers/net/ethernet/ibm/emac/core.c\n@@ -41,6 +41,7 @@\n #include \u003clinux/of_platform.h\u003e\n #include \u003clinux/platform_device.h\u003e\n #include \u003clinux/slab.h\u003e\n+#include \u003cnet/page_pool/helpers.h\u003e\n \n #include \u003casm/processor.h\u003e\n #include \u003casm/io.h\u003e\n@@ -1020,10 +1021,30 @@ static int emac_set_mac_address(struct net_device *ndev, void *sa)\n \treturn 0;\n }\n \n+static void *emac_alloc_rx_buf(struct emac_instance *dev, unsigned int size,\n+\t\t\t       gfp_t gfp)\n+{\n+\treturn page_pool_alloc_va(dev-\u003erx_pool, \u0026size, gfp);\n+}\n+\n+static void emac_prepare_rx_buf(struct emac_instance *dev, int slot, void *va)\n+{\n+\tstruct page *page = virt_to_page(va);\n+\n+\tdev-\u003erx_buf[slot] = va;\n+\tdev-\u003erx_dma[slot] = page_pool_get_dma_addr(page) + offset_in_page(va) +\n+\t\t\t    NET_SKB_PAD;\n+\tdev-\u003erx_desc[slot].data_len = 0;\n+\tdev-\u003erx_desc[slot].data_ptr = dev-\u003erx_dma[slot] + NET_IP_ALIGN;\n+\t/* Descriptor fields must be visible before MAL sees it as empty */\n+\twmb();\n+\tdev-\u003erx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |\n+\t    (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);\n+}\n+\n static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)\n {\n-\tint rx_sync_size = emac_rx_sync_size(new_mtu);\n-\tint rx_skb_size = emac_rx_skb_size(new_mtu);\n+\tint rx_buf_size = emac_rx_buf_size(new_mtu);\n \tint i, ret = 0;\n \tint mr1_jumbo_bit_change = 0;\n \n@@ -1051,28 +1072,23 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)\n \t\t    (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);\n \t}\n \n-\t/* Reallocate RX ring only if bigger skb buffers are required */\n-\tif (rx_skb_size \u003c= dev-\u003erx_skb_size)\n+\t/* Reallocate RX ring only if bigger buffers are required */\n+\tif (rx_buf_size \u003c= dev-\u003erx_buf_size)\n \t\tgoto skip;\n \n-\t/* Second pass, allocate new skbs */\n+\t/* Second pass, allocate new buffers */\n \tfor (i = 0; i \u003c NUM_RX_BUFF; ++i) {\n-\t\tstruct sk_buff *skb;\n+\t\tvoid *va;\n \n-\t\tskb = netdev_alloc_skb_ip_align(dev-\u003endev, rx_skb_size);\n-\t\tif (!skb) {\n+\t\tBUG_ON(!dev-\u003erx_buf[i]);\n+\t\tva = emac_alloc_rx_buf(dev, rx_buf_size, GFP_KERNEL);\n+\t\tif (!va) {\n \t\t\tret = -ENOMEM;\n \t\t\tgoto oom;\n \t\t}\n \n-\t\tBUG_ON(!dev-\u003erx_skb[i]);\n-\t\tdev_kfree_skb(dev-\u003erx_skb[i]);\n-\n-\t\tdev-\u003erx_desc[i].data_ptr =\n-\t\t    dma_map_single(\u0026dev-\u003eofdev-\u003edev, skb-\u003edata - NET_IP_ALIGN,\n-\t\t\t\t   rx_sync_size, DMA_FROM_DEVICE)\n-\t\t\t\t   + NET_IP_ALIGN;\n-\t\tdev-\u003erx_skb[i] = skb;\n+\t\tpage_pool_free_va(dev-\u003erx_pool, dev-\u003erx_buf[i], false);\n+\t\temac_prepare_rx_buf(dev, i, va);\n \t}\n  skip:\n \t/* Check if we need to change \"Jumbo\" bit in MR1 */\n@@ -1092,6 +1108,8 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)\n \t\temac_full_tx_reset(dev);\n \t}\n \n+\t/* Must be updated before RX restarts, NAPI refills with this size */\n+\tdev-\u003erx_buf_size = rx_buf_size;\n \tmal_set_rcbs(dev-\u003emal, dev-\u003emal_rx_chan, emac_rx_size(new_mtu));\n  oom:\n \t/* Restart RX */\n@@ -1117,15 +1135,14 @@ static int emac_change_mtu(struct net_device *ndev, int new_mtu)\n \t\t/* Check if we really need to reinitialize RX ring. The\n \t\t * jumbo frame settings are only updated by a resize.\n \t\t */\n-\t\tif (emac_rx_skb_size(ndev-\u003emtu) != emac_rx_skb_size(new_mtu) ||\n+\t\tif (emac_rx_buf_size(ndev-\u003emtu) != emac_rx_buf_size(new_mtu) ||\n \t\t    ndev-\u003emtu \u003e ETH_DATA_LEN || new_mtu \u003e ETH_DATA_LEN)\n \t\t\tret = emac_resize_rx_ring(dev, new_mtu);\n \t}\n \n \tif (!ret) {\n \t\tWRITE_ONCE(ndev-\u003emtu, new_mtu);\n-\t\tdev-\u003erx_skb_size = emac_rx_skb_size(new_mtu);\n-\t\tdev-\u003erx_sync_size = emac_rx_sync_size(new_mtu);\n+\t\tdev-\u003erx_buf_size = emac_rx_buf_size(new_mtu);\n \t}\n \n \treturn ret;\n@@ -1152,10 +1169,10 @@ static void emac_clean_rx_ring(struct emac_instance *dev)\n \tint i;\n \n \tfor (i = 0; i \u003c NUM_RX_BUFF; ++i)\n-\t\tif (dev-\u003erx_skb[i]) {\n+\t\tif (dev-\u003erx_buf[i]) {\n \t\t\tdev-\u003erx_desc[i].ctrl = 0;\n-\t\t\tdev_kfree_skb(dev-\u003erx_skb[i]);\n-\t\t\tdev-\u003erx_skb[i] = NULL;\n+\t\t\tpage_pool_free_va(dev-\u003erx_pool, dev-\u003erx_buf[i], false);\n+\t\t\tdev-\u003erx_buf[i] = NULL;\n \t\t\tdev-\u003erx_desc[i].data_ptr = 0;\n \t\t}\n \n@@ -1163,6 +1180,9 @@ static void emac_clean_rx_ring(struct emac_instance *dev)\n \t\tdev_kfree_skb(dev-\u003erx_sg_skb);\n \t\tdev-\u003erx_sg_skb = NULL;\n \t}\n+\n+\tmal_destroy_page_pool(dev-\u003emal, dev-\u003erx_pool);\n+\tdev-\u003erx_pool = NULL;\n }\n \n static void emac_clear_mal_desc(struct mal_descriptor *desc, int count)\n@@ -1176,44 +1196,20 @@ static void emac_clear_mal_desc(struct mal_descriptor *desc, int count)\n \t}\n }\n \n-static int\n-__emac_prepare_rx_skb(struct sk_buff *skb, struct emac_instance *dev, int slot)\n-{\n-\tif (unlikely(!skb))\n-\t\treturn -ENOMEM;\n-\n-\tdev-\u003erx_skb[slot] = skb;\n-\tdev-\u003erx_desc[slot].data_len = 0;\n-\n-\tdev-\u003erx_desc[slot].data_ptr =\n-\t    dma_map_single(\u0026dev-\u003eofdev-\u003edev, skb-\u003edata - NET_IP_ALIGN,\n-\t\t\t   dev-\u003erx_sync_size, DMA_FROM_DEVICE) + NET_IP_ALIGN;\n-\twmb();\n-\tdev-\u003erx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |\n-\t    (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);\n-\n-\treturn 0;\n-}\n-\n-static int\n-emac_alloc_rx_skb(struct emac_instance *dev, int slot)\n+static struct page_pool *emac_create_rx_pool(struct emac_instance *dev)\n {\n-\tstruct sk_buff *skb;\n-\n-\tskb = __netdev_alloc_skb_ip_align(dev-\u003endev, dev-\u003erx_skb_size,\n-\t\t\t\t\t  GFP_KERNEL);\n+\tstruct page_pool_params pp = {\n+\t\t.flags\t\t= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,\n+\t\t.pool_size\t= NUM_RX_BUFF,\n+\t\t.nid\t\t= NUMA_NO_NODE,\n+\t\t.dev\t\t= \u0026dev-\u003eofdev-\u003edev,\n+\t\t.napi\t\t= \u0026dev-\u003emal-\u003enapi,\n+\t\t.netdev\t\t= dev-\u003endev,\n+\t\t.dma_dir\t= DMA_FROM_DEVICE,\n+\t\t.max_len\t= PAGE_SIZE,\n+\t};\n \n-\treturn __emac_prepare_rx_skb(skb, dev, slot);\n-}\n-\n-static int\n-emac_alloc_rx_skb_napi(struct emac_instance *dev, int slot)\n-{\n-\tstruct sk_buff *skb;\n-\n-\tskb = napi_alloc_skb(\u0026dev-\u003emal-\u003enapi, dev-\u003erx_skb_size);\n-\n-\treturn __emac_prepare_rx_skb(skb, dev, slot);\n+\treturn page_pool_create(\u0026pp);\n }\n \n static void emac_print_link_status(struct emac_instance *dev)\n@@ -1232,17 +1228,27 @@ static void emac_print_link_status(struct emac_instance *dev)\n static int emac_open(struct net_device *ndev)\n {\n \tstruct emac_instance *dev = netdev_priv(ndev);\n+\tstruct page_pool *pool;\n \tint i;\n \n \tDBG(dev, \"open\" NL);\n \n+\tpool = emac_create_rx_pool(dev);\n+\tif (IS_ERR(pool))\n+\t\treturn PTR_ERR(pool);\n+\tdev-\u003erx_pool = pool;\n+\n \t/* Allocate RX ring */\n-\tfor (i = 0; i \u003c NUM_RX_BUFF; ++i)\n-\t\tif (emac_alloc_rx_skb(dev, i)) {\n+\tfor (i = 0; i \u003c NUM_RX_BUFF; ++i) {\n+\t\tvoid *va = emac_alloc_rx_buf(dev, dev-\u003erx_buf_size, GFP_KERNEL);\n+\n+\t\tif (!va) {\n \t\t\tprintk(KERN_ERR \"%s: failed to allocate RX ring\\n\",\n \t\t\t       ndev-\u003ename);\n \t\t\tgoto oom;\n \t\t}\n+\t\temac_prepare_rx_buf(dev, i, va);\n+\t}\n \n \tdev-\u003etx_cnt = dev-\u003etx_slot = dev-\u003eack_slot = dev-\u003erx_slot = 0;\n \tclear_bit(MAL_COMMAC_RX_STOPPED, \u0026dev-\u003ecommac.flags);\n@@ -1661,17 +1667,23 @@ static void emac_poll_tx(void *param)\n \tnetif_tx_unlock_bh(dev-\u003endev);\n }\n \n+static inline void emac_rx_sync_for_cpu(struct emac_instance *dev, int slot,\n+\t\t\t\t\tint len)\n+{\n+\tdma_sync_single_for_cpu(\u0026dev-\u003eofdev-\u003edev, dev-\u003erx_dma[slot],\n+\t\t\t\tSKB_DATA_ALIGN(len + NET_IP_ALIGN),\n+\t\t\t\tDMA_FROM_DEVICE);\n+}\n+\n static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot,\n \t\t\t\t       int len)\n {\n-\tstruct sk_buff *skb = dev-\u003erx_skb[slot];\n-\n \tDBG2(dev, \"recycle %d %d\" NL, slot, len);\n \n \tif (len)\n-\t\tdma_map_single(\u0026dev-\u003eofdev-\u003edev, skb-\u003edata - NET_IP_ALIGN,\n-\t\t\t       SKB_DATA_ALIGN(len + NET_IP_ALIGN),\n-\t\t\t       DMA_FROM_DEVICE);\n+\t\tdma_sync_single_for_device(\u0026dev-\u003eofdev-\u003edev, dev-\u003erx_dma[slot],\n+\t\t\t\t\t   SKB_DATA_ALIGN(len + NET_IP_ALIGN),\n+\t\t\t\t\t   DMA_FROM_DEVICE);\n \n \tdev-\u003erx_desc[slot].data_len = 0;\n \twmb();\n@@ -1717,23 +1729,69 @@ static inline void emac_rx_csum(struct emac_instance *dev,\n #endif\n }\n \n+/* Hand the buffer of the slot to a new skb and refill the slot */\n+static struct sk_buff *emac_build_rx_skb(struct emac_instance *dev, int slot,\n+\t\t\t\t\t int len)\n+{\n+\tstruct sk_buff *skb;\n+\tvoid *va;\n+\n+\tva = emac_alloc_rx_buf(dev, dev-\u003erx_buf_size,\n+\t\t\t       GFP_ATOMIC | __GFP_NOWARN);\n+\tif (unlikely(!va))\n+\t\treturn NULL;\n+\n+\t/* napi_build_skb() only writes the skb_shared_info, which is past the\n+\t * BD area, so the slot is synced for the CPU only once it is consumed.\n+\t */\n+\tskb = napi_build_skb(dev-\u003erx_buf[slot], dev-\u003erx_buf_size);\n+\tif (unlikely(!skb)) {\n+\t\tpage_pool_free_va(dev-\u003erx_pool, va, true);\n+\t\treturn NULL;\n+\t}\n+\n+\temac_rx_sync_for_cpu(dev, slot, len);\n+\tskb_mark_for_recycle(skb);\n+\tskb_reserve(skb, EMAC_RX_HEADROOM);\n+\tskb_put(skb, len);\n+\temac_prepare_rx_buf(dev, slot, va);\n+\n+\treturn skb;\n+}\n+\n static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)\n {\n-\tif (likely(dev-\u003erx_sg_skb != NULL)) {\n+\tstruct sk_buff *skb = dev-\u003erx_sg_skb;\n+\n+\tif (likely(skb)) {\n \t\tint len = dev-\u003erx_desc[slot].data_len;\n-\t\tint tot_len = dev-\u003erx_sg_skb-\u003elen + len;\n+\t\tvoid *buf = dev-\u003erx_buf[slot];\n+\t\tvoid *va;\n \n-\t\tif (unlikely(tot_len + NET_IP_ALIGN \u003e dev-\u003erx_skb_size)) {\n+\t\tif (unlikely(skb-\u003elen + len \u003e\n+\t\t\t     dev-\u003endev-\u003emtu + EMAC_MTU_OVERHEAD ||\n+\t\t\t     skb_shinfo(skb)-\u003enr_frags \u003e= MAX_SKB_FRAGS)) {\n \t\t\t++dev-\u003eestats.rx_dropped_mtu;\n-\t\t\tdev_kfree_skb(dev-\u003erx_sg_skb);\n-\t\t\tdev-\u003erx_sg_skb = NULL;\n-\t\t} else {\n-\t\t\tmemcpy(skb_tail_pointer(dev-\u003erx_sg_skb),\n-\t\t\t\t\t dev-\u003erx_skb[slot]-\u003edata, len);\n-\t\t\tskb_put(dev-\u003erx_sg_skb, len);\n-\t\t\temac_recycle_rx_skb(dev, slot, len);\n-\t\t\treturn 0;\n+\t\t\tgoto drop;\n \t\t}\n+\n+\t\tva = emac_alloc_rx_buf(dev, dev-\u003erx_buf_size,\n+\t\t\t\t       GFP_ATOMIC | __GFP_NOWARN);\n+\t\tif (unlikely(!va)) {\n+\t\t\t++dev-\u003eestats.rx_dropped_oom;\n+\t\t\tgoto drop;\n+\t\t}\n+\n+\t\temac_rx_sync_for_cpu(dev, slot, len);\n+\t\tskb_add_rx_frag(skb, skb_shinfo(skb)-\u003enr_frags,\n+\t\t\t\tvirt_to_page(buf),\n+\t\t\t\toffset_in_page(buf) + EMAC_RX_HEADROOM,\n+\t\t\t\tlen, dev-\u003erx_buf_size);\n+\t\temac_prepare_rx_buf(dev, slot, va);\n+\t\treturn 0;\n+ drop:\n+\t\tdev_kfree_skb(skb);\n+\t\tdev-\u003erx_sg_skb = NULL;\n \t}\n \temac_recycle_rx_skb(dev, slot, 0);\n \treturn -1;\n@@ -1756,7 +1814,6 @@ static int emac_poll_rx(void *param, int budget)\n \t\tif (ctrl \u0026 MAL_RX_CTRL_EMPTY)\n \t\t\tbreak;\n \n-\t\tskb = dev-\u003erx_skb[slot];\n \t\tmb();\n \t\tlen = dev-\u003erx_desc[slot].data_len;\n \n@@ -1785,15 +1842,19 @@ static int emac_poll_rx(void *param, int budget)\n \t\t\tif (unlikely(!copy_skb))\n \t\t\t\tgoto oom;\n \n+\t\t\temac_rx_sync_for_cpu(dev, slot, len);\n \t\t\tmemcpy(copy_skb-\u003edata - NET_IP_ALIGN,\n-\t\t\t       skb-\u003edata - NET_IP_ALIGN,\n+\t\t\t       dev-\u003erx_buf[slot] + NET_SKB_PAD,\n \t\t\t       len + NET_IP_ALIGN);\n \t\t\temac_recycle_rx_skb(dev, slot, len);\n \t\t\tskb = copy_skb;\n-\t\t} else if (unlikely(emac_alloc_rx_skb_napi(dev, slot)))\n-\t\t\tgoto oom;\n+\t\t\tskb_put(skb, len);\n+\t\t} else {\n+\t\t\tskb = emac_build_rx_skb(dev, slot, len);\n+\t\t\tif (unlikely(!skb))\n+\t\t\t\tgoto oom;\n+\t\t}\n \n-\t\tskb_put(skb, len);\n \tpush_packet:\n \t\tskb-\u003eprotocol = eth_type_trans(skb, dev-\u003endev);\n \t\temac_rx_csum(dev, skb, ctrl);\n@@ -1810,13 +1871,11 @@ static int emac_poll_rx(void *param, int budget)\n \tsg:\n \t\tif (ctrl \u0026 MAL_RX_CTRL_FIRST) {\n \t\t\tBUG_ON(dev-\u003erx_sg_skb);\n-\t\t\tif (unlikely(emac_alloc_rx_skb_napi(dev, slot))) {\n+\t\t\tdev-\u003erx_sg_skb = emac_build_rx_skb(dev, slot, len);\n+\t\t\tif (unlikely(!dev-\u003erx_sg_skb)) {\n \t\t\t\tDBG(dev, \"rx OOM %d\" NL, slot);\n \t\t\t\t++dev-\u003eestats.rx_dropped_oom;\n \t\t\t\temac_recycle_rx_skb(dev, slot, 0);\n-\t\t\t} else {\n-\t\t\t\tdev-\u003erx_sg_skb = skb;\n-\t\t\t\tskb_put(skb, len);\n \t\t\t}\n \t\t} else if (!emac_rx_sg_append(dev, slot) \u0026\u0026\n \t\t\t   (ctrl \u0026 MAL_RX_CTRL_LAST)) {\n@@ -3097,8 +3156,7 @@ static int emac_probe(struct platform_device *ofdev)\n \t\t       np, dev-\u003emal_dev-\u003edev.of_node);\n \t\tgoto err_rel_deps;\n \t}\n-\tdev-\u003erx_skb_size = emac_rx_skb_size(ndev-\u003emtu);\n-\tdev-\u003erx_sync_size = emac_rx_sync_size(ndev-\u003emtu);\n+\tdev-\u003erx_buf_size = emac_rx_buf_size(ndev-\u003emtu);\n \n \t/* Get pointers to BD rings */\n \tdev-\u003etx_desc =\n@@ -3113,7 +3171,7 @@ static int emac_probe(struct platform_device *ofdev)\n \temac_clear_mal_desc(dev-\u003etx_desc, NUM_TX_BUFF);\n \temac_clear_mal_desc(dev-\u003erx_desc, NUM_RX_BUFF);\n \tmemset(dev-\u003etx_skb, 0, NUM_TX_BUFF * sizeof(struct sk_buff *));\n-\tmemset(dev-\u003erx_skb, 0, NUM_RX_BUFF * sizeof(struct sk_buff *));\n+\tmemset(dev-\u003erx_buf, 0, sizeof(dev-\u003erx_buf));\n \n \t/* Attach to ZMII, if needed */\n \tif (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) \u0026\u0026\ndiff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h\nindex 43578fe97fb20e..d77ff352b957ad 100644\n--- a/drivers/net/ethernet/ibm/emac/core.h\n+++ b/drivers/net/ethernet/ibm/emac/core.h\n@@ -53,24 +53,31 @@\n /* Maximum L2 header length (VLAN tagged, no FCS) */\n #define EMAC_MTU_OVERHEAD\t\t(6 * 2 + 2 + 4)\n \n-/* RX BD size for the given MTU */\n-static inline int emac_rx_size(int mtu)\n-{\n-\treturn mal_rx_size(max(mtu, ETH_DATA_LEN) + EMAC_MTU_OVERHEAD);\n-}\n+/* Headroom in front of the received frame */\n+#define EMAC_RX_HEADROOM\t\t(NET_SKB_PAD + NET_IP_ALIGN)\n+\n+/* Largest RX BD size whose buffer still fits into one page */\n+#define EMAC_RX_MAX_SIZE \\\n+\tALIGN_DOWN(SKB_WITH_OVERHEAD(PAGE_SIZE) - EMAC_RX_HEADROOM, 16)\n \n-/* Size of RX skb for the given MTU */\n-static inline int emac_rx_skb_size(int mtu)\n+/* RX BD size for the given MTU, larger frames span several BDs */\n+static inline int emac_rx_size(int mtu)\n {\n-\tint size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));\n+\tint size = mal_rx_size(max(mtu, ETH_DATA_LEN) + EMAC_MTU_OVERHEAD);\n \n-\treturn SKB_DATA_ALIGN(size + NET_IP_ALIGN) + NET_SKB_PAD;\n+\treturn min_t(int, size, EMAC_RX_MAX_SIZE);\n }\n \n-/* RX DMA sync size */\n-static inline int emac_rx_sync_size(int mtu)\n+/* Size of an RX buffer for the given MTU, including the headroom and\n+ * the skb_shared_info. Buffers above half a page take a whole page.\n+ */\n+static inline int emac_rx_buf_size(int mtu)\n {\n-\treturn SKB_DATA_ALIGN(emac_rx_size(mtu) + NET_IP_ALIGN);\n+\tint size = SKB_HEAD_ALIGN(NET_SKB_PAD +\n+\t\t\t\t  SKB_DATA_ALIGN(emac_rx_size(mtu) +\n+\t\t\t\t\t\t NET_IP_ALIGN));\n+\n+\treturn size \u003e PAGE_SIZE / 2 ? PAGE_SIZE : size;\n }\n \n /* Driver statistcs is split into two parts to make it more cache friendly:\n@@ -238,11 +245,13 @@ struct emac_instance {\n \tstruct mal_descriptor\t\t*rx_desc;\n \tint\t\t\t\trx_slot;\n \tstruct sk_buff\t\t\t*rx_sg_skb;\t/* 1 */\n-\tint \t\t\t\trx_skb_size;\n-\tint\t\t\t\trx_sync_size;\n+\tint\t\t\t\trx_buf_size;\n+\tstruct page_pool\t\t*rx_pool;\n \n \tstruct sk_buff\t\t\t*tx_skb[NUM_TX_BUFF];\n-\tstruct sk_buff\t\t\t*rx_skb[NUM_RX_BUFF];\n+\tvoid\t\t\t\t*rx_buf[NUM_RX_BUFF];\n+\t/* DMA address of rx_buf + NET_SKB_PAD, cache line aligned */\n+\tdma_addr_t\t\t\trx_dma[NUM_RX_BUFF];\n \n \t/* Stats\n \t */\ndiff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c\nindex 236603a381bc2b..f1f7541379bc6a 100644\n--- a/drivers/net/ethernet/ibm/emac/mal.c\n+++ b/drivers/net/ethernet/ibm/emac/mal.c\n@@ -25,6 +25,7 @@\n #include \u003clinux/of.h\u003e\n #include \u003clinux/of_irq.h\u003e\n #include \u003clinux/platform_device.h\u003e\n+#include \u003cnet/page_pool/types.h\u003e\n \n #include \"core.h\"\n #include \u003casm/dcr-regs.h\u003e\n@@ -86,6 +87,23 @@ void mal_unregister_commac(struct mal_instance\t*mal,\n \tnetdev_unlock(mal-\u003enapi.dev);\n }\n \n+/* A page pool that recycles directly into the MAL NAPI instance can only be\n+ * destroyed while that instance is disabled.\n+ */\n+void mal_destroy_page_pool(struct mal_instance *mal, struct page_pool *pool)\n+{\n+\tbool enabled;\n+\n+\tnetdev_lock(mal-\u003enapi.dev);\n+\tenabled = !list_empty(\u0026mal-\u003elist);\n+\tif (enabled)\n+\t\tnapi_disable_locked(\u0026mal-\u003enapi);\n+\tpage_pool_destroy(pool);\n+\tif (enabled)\n+\t\tnapi_enable_locked(\u0026mal-\u003enapi);\n+\tnetdev_unlock(mal-\u003enapi.dev);\n+}\n+\n int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size)\n {\n \tBUG_ON(channel \u003c 0 || channel \u003e= mal-\u003enum_rx_chans ||\ndiff --git a/drivers/net/ethernet/ibm/emac/mal.h b/drivers/net/ethernet/ibm/emac/mal.h\nindex e0ddc41186a28b..8264e5f0c9c102 100644\n--- a/drivers/net/ethernet/ibm/emac/mal.h\n+++ b/drivers/net/ethernet/ibm/emac/mal.h\n@@ -276,6 +276,8 @@ void mal_disable_rx_channel(struct mal_instance *mal, int channel);\n void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac);\n void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac);\n \n+void mal_destroy_page_pool(struct mal_instance *mal, struct page_pool *pool);\n+\n /* Add/remove EMAC to/from MAL polling list */\n void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac);\n void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac);\n"
}

2/1 2026/11/02 10:03 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The changes in this patch series exclusively modify the IBM EMAC network device driver (drivers/net/ethernet/ibm/emac/), which depends on CONFIG_PPC_DCR (PowerPC Device Control Register support). This driver is specific to PowerPC architectures (IBM/AMCC PowerPC 4xx SoCs) and cannot be compiled or executed on the target architecture (amd64).",
  "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 dd7447ed502ea93ce17e6918a5f4a6795f95e347
Author: syz-cluster <triage@syzkaller.com>
Date:   Mon Nov 2 10:03:34 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/ethernet/ibm/emac/Kconfig b/drivers/net/ethernet/ibm/emac/Kconfig
index c8e5de5987ac60..8779c5b6a2c34f 100644
--- a/drivers/net/ethernet/ibm/emac/Kconfig
+++ b/drivers/net/ethernet/ibm/emac/Kconfig
@@ -3,6 +3,7 @@ config IBM_EMAC
 	tristate "IBM EMAC Ethernet support"
 	depends on PPC_DCR
 	select CRC32
+	select PAGE_POOL
 	select PHYLIB
 	help
 	  This driver supports the IBM EMAC family of Ethernet controllers
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 640618c0a09e9a..9496c09d7a7cfd 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -41,6 +41,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <net/page_pool/helpers.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -1020,10 +1021,30 @@ static int emac_set_mac_address(struct net_device *ndev, void *sa)
 	return 0;
 }
 
+static void *emac_alloc_rx_buf(struct emac_instance *dev, unsigned int size,
+			       gfp_t gfp)
+{
+	return page_pool_alloc_va(dev->rx_pool, &size, gfp);
+}
+
+static void emac_prepare_rx_buf(struct emac_instance *dev, int slot, void *va)
+{
+	struct page *page = virt_to_page(va);
+
+	dev->rx_buf[slot] = va;
+	dev->rx_dma[slot] = page_pool_get_dma_addr(page) + offset_in_page(va) +
+			    NET_SKB_PAD;
+	dev->rx_desc[slot].data_len = 0;
+	dev->rx_desc[slot].data_ptr = dev->rx_dma[slot] + NET_IP_ALIGN;
+	/* Descriptor fields must be visible before MAL sees it as empty */
+	wmb();
+	dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+	    (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+}
+
 static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
 {
-	int rx_sync_size = emac_rx_sync_size(new_mtu);
-	int rx_skb_size = emac_rx_skb_size(new_mtu);
+	int rx_buf_size = emac_rx_buf_size(new_mtu);
 	int i, ret = 0;
 	int mr1_jumbo_bit_change = 0;
 
@@ -1051,28 +1072,23 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
 		    (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
 	}
 
-	/* Reallocate RX ring only if bigger skb buffers are required */
-	if (rx_skb_size <= dev->rx_skb_size)
+	/* Reallocate RX ring only if bigger buffers are required */
+	if (rx_buf_size <= dev->rx_buf_size)
 		goto skip;
 
-	/* Second pass, allocate new skbs */
+	/* Second pass, allocate new buffers */
 	for (i = 0; i < NUM_RX_BUFF; ++i) {
-		struct sk_buff *skb;
+		void *va;
 
-		skb = netdev_alloc_skb_ip_align(dev->ndev, rx_skb_size);
-		if (!skb) {
+		BUG_ON(!dev->rx_buf[i]);
+		va = emac_alloc_rx_buf(dev, rx_buf_size, GFP_KERNEL);
+		if (!va) {
 			ret = -ENOMEM;
 			goto oom;
 		}
 
-		BUG_ON(!dev->rx_skb[i]);
-		dev_kfree_skb(dev->rx_skb[i]);
-
-		dev->rx_desc[i].data_ptr =
-		    dma_map_single(&dev->ofdev->dev, skb->data - NET_IP_ALIGN,
-				   rx_sync_size, DMA_FROM_DEVICE)
-				   + NET_IP_ALIGN;
-		dev->rx_skb[i] = skb;
+		page_pool_free_va(dev->rx_pool, dev->rx_buf[i], false);
+		emac_prepare_rx_buf(dev, i, va);
 	}
  skip:
 	/* Check if we need to change "Jumbo" bit in MR1 */
@@ -1092,6 +1108,8 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
 		emac_full_tx_reset(dev);
 	}
 
+	/* Must be updated before RX restarts, NAPI refills with this size */
+	dev->rx_buf_size = rx_buf_size;
 	mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu));
  oom:
 	/* Restart RX */
@@ -1117,15 +1135,14 @@ static int emac_change_mtu(struct net_device *ndev, int new_mtu)
 		/* Check if we really need to reinitialize RX ring. The
 		 * jumbo frame settings are only updated by a resize.
 		 */
-		if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu) ||
+		if (emac_rx_buf_size(ndev->mtu) != emac_rx_buf_size(new_mtu) ||
 		    ndev->mtu > ETH_DATA_LEN || new_mtu > ETH_DATA_LEN)
 			ret = emac_resize_rx_ring(dev, new_mtu);
 	}
 
 	if (!ret) {
 		WRITE_ONCE(ndev->mtu, new_mtu);
-		dev->rx_skb_size = emac_rx_skb_size(new_mtu);
-		dev->rx_sync_size = emac_rx_sync_size(new_mtu);
+		dev->rx_buf_size = emac_rx_buf_size(new_mtu);
 	}
 
 	return ret;
@@ -1152,10 +1169,10 @@ static void emac_clean_rx_ring(struct emac_instance *dev)
 	int i;
 
 	for (i = 0; i < NUM_RX_BUFF; ++i)
-		if (dev->rx_skb[i]) {
+		if (dev->rx_buf[i]) {
 			dev->rx_desc[i].ctrl = 0;
-			dev_kfree_skb(dev->rx_skb[i]);
-			dev->rx_skb[i] = NULL;
+			page_pool_free_va(dev->rx_pool, dev->rx_buf[i], false);
+			dev->rx_buf[i] = NULL;
 			dev->rx_desc[i].data_ptr = 0;
 		}
 
@@ -1163,6 +1180,9 @@ static void emac_clean_rx_ring(struct emac_instance *dev)
 		dev_kfree_skb(dev->rx_sg_skb);
 		dev->rx_sg_skb = NULL;
 	}
+
+	mal_destroy_page_pool(dev->mal, dev->rx_pool);
+	dev->rx_pool = NULL;
 }
 
 static void emac_clear_mal_desc(struct mal_descriptor *desc, int count)
@@ -1176,44 +1196,20 @@ static void emac_clear_mal_desc(struct mal_descriptor *desc, int count)
 	}
 }
 
-static int
-__emac_prepare_rx_skb(struct sk_buff *skb, struct emac_instance *dev, int slot)
-{
-	if (unlikely(!skb))
-		return -ENOMEM;
-
-	dev->rx_skb[slot] = skb;
-	dev->rx_desc[slot].data_len = 0;
-
-	dev->rx_desc[slot].data_ptr =
-	    dma_map_single(&dev->ofdev->dev, skb->data - NET_IP_ALIGN,
-			   dev->rx_sync_size, DMA_FROM_DEVICE) + NET_IP_ALIGN;
-	wmb();
-	dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
-	    (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
-
-	return 0;
-}
-
-static int
-emac_alloc_rx_skb(struct emac_instance *dev, int slot)
+static struct page_pool *emac_create_rx_pool(struct emac_instance *dev)
 {
-	struct sk_buff *skb;
-
-	skb = __netdev_alloc_skb_ip_align(dev->ndev, dev->rx_skb_size,
-					  GFP_KERNEL);
+	struct page_pool_params pp = {
+		.flags		= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
+		.pool_size	= NUM_RX_BUFF,
+		.nid		= NUMA_NO_NODE,
+		.dev		= &dev->ofdev->dev,
+		.napi		= &dev->mal->napi,
+		.netdev		= dev->ndev,
+		.dma_dir	= DMA_FROM_DEVICE,
+		.max_len	= PAGE_SIZE,
+	};
 
-	return __emac_prepare_rx_skb(skb, dev, slot);
-}
-
-static int
-emac_alloc_rx_skb_napi(struct emac_instance *dev, int slot)
-{
-	struct sk_buff *skb;
-
-	skb = napi_alloc_skb(&dev->mal->napi, dev->rx_skb_size);
-
-	return __emac_prepare_rx_skb(skb, dev, slot);
+	return page_pool_create(&pp);
 }
 
 static void emac_print_link_status(struct emac_instance *dev)
@@ -1232,17 +1228,27 @@ static void emac_print_link_status(struct emac_instance *dev)
 static int emac_open(struct net_device *ndev)
 {
 	struct emac_instance *dev = netdev_priv(ndev);
+	struct page_pool *pool;
 	int i;
 
 	DBG(dev, "open" NL);
 
+	pool = emac_create_rx_pool(dev);
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	dev->rx_pool = pool;
+
 	/* Allocate RX ring */
-	for (i = 0; i < NUM_RX_BUFF; ++i)
-		if (emac_alloc_rx_skb(dev, i)) {
+	for (i = 0; i < NUM_RX_BUFF; ++i) {
+		void *va = emac_alloc_rx_buf(dev, dev->rx_buf_size, GFP_KERNEL);
+
+		if (!va) {
 			printk(KERN_ERR "%s: failed to allocate RX ring\n",
 			       ndev->name);
 			goto oom;
 		}
+		emac_prepare_rx_buf(dev, i, va);
+	}
 
 	dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = 0;
 	clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
@@ -1661,17 +1667,23 @@ static void emac_poll_tx(void *param)
 	netif_tx_unlock_bh(dev->ndev);
 }
 
+static inline void emac_rx_sync_for_cpu(struct emac_instance *dev, int slot,
+					int len)
+{
+	dma_sync_single_for_cpu(&dev->ofdev->dev, dev->rx_dma[slot],
+				SKB_DATA_ALIGN(len + NET_IP_ALIGN),
+				DMA_FROM_DEVICE);
+}
+
 static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot,
 				       int len)
 {
-	struct sk_buff *skb = dev->rx_skb[slot];
-
 	DBG2(dev, "recycle %d %d" NL, slot, len);
 
 	if (len)
-		dma_map_single(&dev->ofdev->dev, skb->data - NET_IP_ALIGN,
-			       SKB_DATA_ALIGN(len + NET_IP_ALIGN),
-			       DMA_FROM_DEVICE);
+		dma_sync_single_for_device(&dev->ofdev->dev, dev->rx_dma[slot],
+					   SKB_DATA_ALIGN(len + NET_IP_ALIGN),
+					   DMA_FROM_DEVICE);
 
 	dev->rx_desc[slot].data_len = 0;
 	wmb();
@@ -1717,23 +1729,69 @@ static inline void emac_rx_csum(struct emac_instance *dev,
 #endif
 }
 
+/* Hand the buffer of the slot to a new skb and refill the slot */
+static struct sk_buff *emac_build_rx_skb(struct emac_instance *dev, int slot,
+					 int len)
+{
+	struct sk_buff *skb;
+	void *va;
+
+	va = emac_alloc_rx_buf(dev, dev->rx_buf_size,
+			       GFP_ATOMIC | __GFP_NOWARN);
+	if (unlikely(!va))
+		return NULL;
+
+	/* napi_build_skb() only writes the skb_shared_info, which is past the
+	 * BD area, so the slot is synced for the CPU only once it is consumed.
+	 */
+	skb = napi_build_skb(dev->rx_buf[slot], dev->rx_buf_size);
+	if (unlikely(!skb)) {
+		page_pool_free_va(dev->rx_pool, va, true);
+		return NULL;
+	}
+
+	emac_rx_sync_for_cpu(dev, slot, len);
+	skb_mark_for_recycle(skb);
+	skb_reserve(skb, EMAC_RX_HEADROOM);
+	skb_put(skb, len);
+	emac_prepare_rx_buf(dev, slot, va);
+
+	return skb;
+}
+
 static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
 {
-	if (likely(dev->rx_sg_skb != NULL)) {
+	struct sk_buff *skb = dev->rx_sg_skb;
+
+	if (likely(skb)) {
 		int len = dev->rx_desc[slot].data_len;
-		int tot_len = dev->rx_sg_skb->len + len;
+		void *buf = dev->rx_buf[slot];
+		void *va;
 
-		if (unlikely(tot_len + NET_IP_ALIGN > dev->rx_skb_size)) {
+		if (unlikely(skb->len + len >
+			     dev->ndev->mtu + EMAC_MTU_OVERHEAD ||
+			     skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
 			++dev->estats.rx_dropped_mtu;
-			dev_kfree_skb(dev->rx_sg_skb);
-			dev->rx_sg_skb = NULL;
-		} else {
-			memcpy(skb_tail_pointer(dev->rx_sg_skb),
-					 dev->rx_skb[slot]->data, len);
-			skb_put(dev->rx_sg_skb, len);
-			emac_recycle_rx_skb(dev, slot, len);
-			return 0;
+			goto drop;
 		}
+
+		va = emac_alloc_rx_buf(dev, dev->rx_buf_size,
+				       GFP_ATOMIC | __GFP_NOWARN);
+		if (unlikely(!va)) {
+			++dev->estats.rx_dropped_oom;
+			goto drop;
+		}
+
+		emac_rx_sync_for_cpu(dev, slot, len);
+		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+				virt_to_page(buf),
+				offset_in_page(buf) + EMAC_RX_HEADROOM,
+				len, dev->rx_buf_size);
+		emac_prepare_rx_buf(dev, slot, va);
+		return 0;
+ drop:
+		dev_kfree_skb(skb);
+		dev->rx_sg_skb = NULL;
 	}
 	emac_recycle_rx_skb(dev, slot, 0);
 	return -1;
@@ -1756,7 +1814,6 @@ static int emac_poll_rx(void *param, int budget)
 		if (ctrl & MAL_RX_CTRL_EMPTY)
 			break;
 
-		skb = dev->rx_skb[slot];
 		mb();
 		len = dev->rx_desc[slot].data_len;
 
@@ -1785,15 +1842,19 @@ static int emac_poll_rx(void *param, int budget)
 			if (unlikely(!copy_skb))
 				goto oom;
 
+			emac_rx_sync_for_cpu(dev, slot, len);
 			memcpy(copy_skb->data - NET_IP_ALIGN,
-			       skb->data - NET_IP_ALIGN,
+			       dev->rx_buf[slot] + NET_SKB_PAD,
 			       len + NET_IP_ALIGN);
 			emac_recycle_rx_skb(dev, slot, len);
 			skb = copy_skb;
-		} else if (unlikely(emac_alloc_rx_skb_napi(dev, slot)))
-			goto oom;
+			skb_put(skb, len);
+		} else {
+			skb = emac_build_rx_skb(dev, slot, len);
+			if (unlikely(!skb))
+				goto oom;
+		}
 
-		skb_put(skb, len);
 	push_packet:
 		skb->protocol = eth_type_trans(skb, dev->ndev);
 		emac_rx_csum(dev, skb, ctrl);
@@ -1810,13 +1871,11 @@ static int emac_poll_rx(void *param, int budget)
 	sg:
 		if (ctrl & MAL_RX_CTRL_FIRST) {
 			BUG_ON(dev->rx_sg_skb);
-			if (unlikely(emac_alloc_rx_skb_napi(dev, slot))) {
+			dev->rx_sg_skb = emac_build_rx_skb(dev, slot, len);
+			if (unlikely(!dev->rx_sg_skb)) {
 				DBG(dev, "rx OOM %d" NL, slot);
 				++dev->estats.rx_dropped_oom;
 				emac_recycle_rx_skb(dev, slot, 0);
-			} else {
-				dev->rx_sg_skb = skb;
-				skb_put(skb, len);
 			}
 		} else if (!emac_rx_sg_append(dev, slot) &&
 			   (ctrl & MAL_RX_CTRL_LAST)) {
@@ -3097,8 +3156,7 @@ static int emac_probe(struct platform_device *ofdev)
 		       np, dev->mal_dev->dev.of_node);
 		goto err_rel_deps;
 	}
-	dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);
-	dev->rx_sync_size = emac_rx_sync_size(ndev->mtu);
+	dev->rx_buf_size = emac_rx_buf_size(ndev->mtu);
 
 	/* Get pointers to BD rings */
 	dev->tx_desc =
@@ -3113,7 +3171,7 @@ static int emac_probe(struct platform_device *ofdev)
 	emac_clear_mal_desc(dev->tx_desc, NUM_TX_BUFF);
 	emac_clear_mal_desc(dev->rx_desc, NUM_RX_BUFF);
 	memset(dev->tx_skb, 0, NUM_TX_BUFF * sizeof(struct sk_buff *));
-	memset(dev->rx_skb, 0, NUM_RX_BUFF * sizeof(struct sk_buff *));
+	memset(dev->rx_buf, 0, sizeof(dev->rx_buf));
 
 	/* Attach to ZMII, if needed */
 	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 43578fe97fb20e..d77ff352b957ad 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -53,24 +53,31 @@
 /* Maximum L2 header length (VLAN tagged, no FCS) */
 #define EMAC_MTU_OVERHEAD		(6 * 2 + 2 + 4)
 
-/* RX BD size for the given MTU */
-static inline int emac_rx_size(int mtu)
-{
-	return mal_rx_size(max(mtu, ETH_DATA_LEN) + EMAC_MTU_OVERHEAD);
-}
+/* Headroom in front of the received frame */
+#define EMAC_RX_HEADROOM		(NET_SKB_PAD + NET_IP_ALIGN)
+
+/* Largest RX BD size whose buffer still fits into one page */
+#define EMAC_RX_MAX_SIZE \
+	ALIGN_DOWN(SKB_WITH_OVERHEAD(PAGE_SIZE) - EMAC_RX_HEADROOM, 16)
 
-/* Size of RX skb for the given MTU */
-static inline int emac_rx_skb_size(int mtu)
+/* RX BD size for the given MTU, larger frames span several BDs */
+static inline int emac_rx_size(int mtu)
 {
-	int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));
+	int size = mal_rx_size(max(mtu, ETH_DATA_LEN) + EMAC_MTU_OVERHEAD);
 
-	return SKB_DATA_ALIGN(size + NET_IP_ALIGN) + NET_SKB_PAD;
+	return min_t(int, size, EMAC_RX_MAX_SIZE);
 }
 
-/* RX DMA sync size */
-static inline int emac_rx_sync_size(int mtu)
+/* Size of an RX buffer for the given MTU, including the headroom and
+ * the skb_shared_info. Buffers above half a page take a whole page.
+ */
+static inline int emac_rx_buf_size(int mtu)
 {
-	return SKB_DATA_ALIGN(emac_rx_size(mtu) + NET_IP_ALIGN);
+	int size = SKB_HEAD_ALIGN(NET_SKB_PAD +
+				  SKB_DATA_ALIGN(emac_rx_size(mtu) +
+						 NET_IP_ALIGN));
+
+	return size > PAGE_SIZE / 2 ? PAGE_SIZE : size;
 }
 
 /* Driver statistcs is split into two parts to make it more cache friendly:
@@ -238,11 +245,13 @@ struct emac_instance {
 	struct mal_descriptor		*rx_desc;
 	int				rx_slot;
 	struct sk_buff			*rx_sg_skb;	/* 1 */
-	int 				rx_skb_size;
-	int				rx_sync_size;
+	int				rx_buf_size;
+	struct page_pool		*rx_pool;
 
 	struct sk_buff			*tx_skb[NUM_TX_BUFF];
-	struct sk_buff			*rx_skb[NUM_RX_BUFF];
+	void				*rx_buf[NUM_RX_BUFF];
+	/* DMA address of rx_buf + NET_SKB_PAD, cache line aligned */
+	dma_addr_t			rx_dma[NUM_RX_BUFF];
 
 	/* Stats
 	 */
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index 236603a381bc2b..f1f7541379bc6a 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#include <net/page_pool/types.h>
 
 #include "core.h"
 #include <asm/dcr-regs.h>
@@ -86,6 +87,23 @@ void mal_unregister_commac(struct mal_instance	*mal,
 	netdev_unlock(mal->napi.dev);
 }
 
+/* A page pool that recycles directly into the MAL NAPI instance can only be
+ * destroyed while that instance is disabled.
+ */
+void mal_destroy_page_pool(struct mal_instance *mal, struct page_pool *pool)
+{
+	bool enabled;
+
+	netdev_lock(mal->napi.dev);
+	enabled = !list_empty(&mal->list);
+	if (enabled)
+		napi_disable_locked(&mal->napi);
+	page_pool_destroy(pool);
+	if (enabled)
+		napi_enable_locked(&mal->napi);
+	netdev_unlock(mal->napi.dev);
+}
+
 int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size)
 {
 	BUG_ON(channel < 0 || channel >= mal->num_rx_chans ||
diff --git a/drivers/net/ethernet/ibm/emac/mal.h b/drivers/net/ethernet/ibm/emac/mal.h
index e0ddc41186a28b..8264e5f0c9c102 100644
--- a/drivers/net/ethernet/ibm/emac/mal.h
+++ b/drivers/net/ethernet/ibm/emac/mal.h
@@ -276,6 +276,8 @@ void mal_disable_rx_channel(struct mal_instance *mal, int channel);
 void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac);
 void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac);
 
+void mal_destroy_page_pool(struct mal_instance *mal, struct page_pool *pool);
+
 /* Add/remove EMAC to/from MAL polling list */
 void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac);
 void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac);

3/2 2026/11/02 10:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 10268
							output: 19
							thoughts: 229
						

Thoughts:
**Evaluating the Patch for Syzkaller Fuzzing**

Okay, here's what I'm thinking. The task is to decide if this patch series is a good candidate for syzkaller fuzzing, specifically on the amd64 architecture.

First, I need to really dig into this patch. I see it's touching these files: `drivers/net/ethernet/ibm/emac/Kconfig`, `drivers/net/ethernet/ibm/emac/core.c`, `drivers/net/ethernet/ibm/emac/core.h`, `drivers/net/ethernet/ibm/emac/mal.c`, and `drivers/net/ethernet/ibm/emac/mal.h`. That's a good starting point, gives me an idea of where this patch is heading.

Now, let's look at that `Kconfig` file because that often holds the keys. Ah, here it is: `config IBM_EMAC`. Tristate, depends on `PPC_DCR`, selects `CRC32`, `PAGE_POOL`, and `PHYLIB`. Wait, hold on. `depends on PPC_DCR`! That's a red flag. What is `PPC_DCR`? Does this mean this is only for PowerPC? I need to know for sure. I need to use `grepper` to see where `PPC_DCR` is defined in the kernel and get its implications. This dependence on PPC might seriously limit or eliminate the applicability of syzkaller fuzzing on amd64, if it's indeed PowerPC-specific.



4/2 2026/11/02 10:03 tool grepper
0m Args:
{
  "Expression": "config PPC_DCR"
}

Results:
{
  "Output": "arch/powerpc/Kconfig=411=config ARCH_HAS_ADD_PAGES\n--\narch/powerpc/Kconfig-414-\narch/powerpc/Kconfig:415:config PPC_DCR_NATIVE\narch/powerpc/Kconfig-416-\tbool\narch/powerpc/Kconfig-417-\narch/powerpc/Kconfig:418:config PPC_DCR\narch/powerpc/Kconfig-419-\tbool\n"
}

5/2 2026/11/02 10:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 10996
							output: 35
							thoughts: 20
						

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

**Diving into the PowerPC Configuration**

Okay, I need to investigate something related to the PowerPC architecture, specifically within the kernel configuration. My instinct says to look at `arch/powerpc/Kconfig`. That's where all the fundamental architecture-specific configuration options are defined. Given my current line of inquiry, line 418 feels like a good place to start. I'm expecting to find something relevant there, likely a feature or a dependency I need to understand better. Let's see what's lurking at that specific point in the configuration file.



6/2 2026/11/02 10:03 tool read-file
0m Args:
{
  "File": "arch/powerpc/Kconfig",
  "FirstLine": 410,
  "LineCount": 25
}

Results:
{
  "Contents": " 410:\t\n 411:\tconfig ARCH_HAS_ADD_PAGES\n 412:\t\tdef_bool y\n 413:\t\tdepends on ARCH_ENABLE_MEMORY_HOTPLUG\n 414:\t\n 415:\tconfig PPC_DCR_NATIVE\n 416:\t\tbool\n 417:\t\n 418:\tconfig PPC_DCR\n 419:\t\tbool\n 420:\t\tdepends on PPC_DCR_NATIVE\n 421:\t\tdefault y\n 422:\t\n 423:\tconfig PPC_PCI_OF_BUS_MAP\n 424:\t\tbool \"Use pci_to_OF_bus_map (deprecated)\"\n 425:\t\tdepends on PPC32\n 426:\t\tdepends on PPC_PMAC || PPC_CHRP\n 427:\t\thelp\n 428:\t\t  This option uses pci_to_OF_bus_map to map OF nodes to PCI devices, which\n 429:\t\t  restricts the system to only having 256 PCI buses. On CHRP it also causes\n 430:\t\t  the \"pci-OF-bus-map\" property to be created in the device tree.\n 431:\t\n 432:\t\t  If unsure, say \"N\".\n 433:\t\n 434:\tconfig PPC_PCI_BUS_NUM_DOMAIN_DEPENDENT\n"
}

7/2 2026/11/02 10:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 11556
							output: 33
							thoughts: 45
						

Thoughts:
Okay, let's see. My first thought is: **Can PPC_DCR or IBM_EMAC even be *built* on x86_64/amd64?** Seems like a straightforward enough question. Before diving into specifics, I think it makes sense to go straight to the source. The best way to answer this quickly is probably to see what the build system configuration files say. So, let's fire up a `grep` and search across all the Kconfig files for "PPC_DCR." That should give me a good initial sense of whether this is even remotely possible within the current codebase. That's the logical starting point, anyway.



8/2 2026/11/02 10:03 tool grepper
0m Args:
{
  "Expression": "PPC_DCR",
  "PathPrefixes": [
    "arch/",
    "drivers/"
  ]
}

Results:
{
  "Output": "arch/powerpc/Kconfig=411=config ARCH_HAS_ADD_PAGES\n--\narch/powerpc/Kconfig-414-\narch/powerpc/Kconfig:415:config PPC_DCR_NATIVE\narch/powerpc/Kconfig-416-\tbool\narch/powerpc/Kconfig-417-\narch/powerpc/Kconfig:418:config PPC_DCR\narch/powerpc/Kconfig-419-\tbool\narch/powerpc/Kconfig:420:\tdepends on PPC_DCR_NATIVE\narch/powerpc/Kconfig-421-\tdefault y\n--\narch/powerpc/include/asm/dcr.h-10-#ifndef __ASSEMBLER__\narch/powerpc/include/asm/dcr.h:11:#ifdef CONFIG_PPC_DCR\narch/powerpc/include/asm/dcr.h-12-\n--\narch/powerpc/include/asm/dcr.h=28=extern unsigned int dcr_resource_len(const struct device_node *np,\narch/powerpc/include/asm/dcr.h-29-\t\t\t\t     unsigned int index);\narch/powerpc/include/asm/dcr.h:30:#endif /* CONFIG_PPC_DCR */\narch/powerpc/include/asm/dcr.h-31-#endif /* __ASSEMBLER__ */\n--\narch/powerpc/include/asm/mpic.h=232=enum mpic_reg_type {\n--\narch/powerpc/include/asm/mpic.h-234-\tmpic_access_mmio_be,\narch/powerpc/include/asm/mpic.h:235:#ifdef CONFIG_PPC_DCR\narch/powerpc/include/asm/mpic.h-236-\tmpic_access_dcr\n--\narch/powerpc/include/asm/mpic.h=240=struct mpic_reg_bank {\narch/powerpc/include/asm/mpic.h-241-\tu32 __iomem\t*base;\narch/powerpc/include/asm/mpic.h:242:#ifdef CONFIG_PPC_DCR\narch/powerpc/include/asm/mpic.h-243-\tdcr_host_t\tdhost;\narch/powerpc/include/asm/mpic.h:244:#endif /* CONFIG_PPC_DCR */\narch/powerpc/include/asm/mpic.h-245-};\n--\narch/powerpc/platforms/Kconfig.cputype=46=config 44x\narch/powerpc/platforms/Kconfig.cputype-47-\tbool \"AMCC 44x, 46x or 47x\"\narch/powerpc/platforms/Kconfig.cputype:48:\tselect PPC_DCR_NATIVE\narch/powerpc/platforms/Kconfig.cputype-49-\tselect PPC_UDBG_16550\n--\narch/powerpc/sysdev/Makefile=13=obj-$(CONFIG_PPC_MPC106)\t+= grackle.o\narch/powerpc/sysdev/Makefile:14:obj-$(CONFIG_PPC_DCR_NATIVE)\t+= dcr-low.o\narch/powerpc/sysdev/Makefile-15-obj-$(CONFIG_U3_DART)\t\t+= dart_iommu.o\n--\narch/powerpc/sysdev/Makefile=35=obj-$(CONFIG_QUICC_ENGINE)\t+= cpm_common.o\narch/powerpc/sysdev/Makefile:36:obj-$(CONFIG_PPC_DCR)\t\t+= dcr.o\narch/powerpc/sysdev/Makefile-37-\n--\narch/powerpc/sysdev/mpic.c=176=static inline u32 _mpic_read(enum mpic_reg_type type,\n--\narch/powerpc/sysdev/mpic.c-180-\tswitch(type) {\narch/powerpc/sysdev/mpic.c:181:#ifdef CONFIG_PPC_DCR\narch/powerpc/sysdev/mpic.c-182-\tcase mpic_access_dcr:\n--\narch/powerpc/sysdev/mpic.c=193=static inline void _mpic_write(enum mpic_reg_type type,\n--\narch/powerpc/sysdev/mpic.c-197-\tswitch(type) {\narch/powerpc/sysdev/mpic.c:198:#ifdef CONFIG_PPC_DCR\narch/powerpc/sysdev/mpic.c-199-\tcase mpic_access_dcr:\n--\narch/powerpc/sysdev/mpic.c=317=static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr,\n--\narch/powerpc/sysdev/mpic.c-324-\narch/powerpc/sysdev/mpic.c:325:#ifdef CONFIG_PPC_DCR\narch/powerpc/sysdev/mpic.c-326-static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb,\n--\narch/powerpc/sysdev/mpic.c=334=static inline void mpic_map(struct mpic *mpic,\n--\narch/powerpc/sysdev/mpic.c-342-}\narch/powerpc/sysdev/mpic.c:343:#else /* CONFIG_PPC_DCR */\narch/powerpc/sysdev/mpic.c-344-#define mpic_map(m,p,b,o,s)\t_mpic_map_mmio(m,p,b,o,s)\narch/powerpc/sysdev/mpic.c:345:#endif /* !CONFIG_PPC_DCR */\narch/powerpc/sysdev/mpic.c-346-\n--\narch/powerpc/sysdev/mpic.c=1216=struct mpic * __init mpic_alloc(struct device_node *node,\n--\narch/powerpc/sysdev/mpic.c-1351-\t */\narch/powerpc/sysdev/mpic.c:1352:#ifdef CONFIG_PPC_DCR\narch/powerpc/sysdev/mpic.c-1353-\tif (mpic-\u003eflags \u0026 MPIC_USES_DCR)\n--\ndrivers/net/ethernet/ibm/Kconfig=6=config NET_VENDOR_IBM\n--\ndrivers/net/ethernet/ibm/Kconfig-8-\tdefault y\ndrivers/net/ethernet/ibm/Kconfig:9:\tdepends on PPC_PSERIES || PPC_DCR || (IBMEBUS \u0026\u0026 SPARSEMEM)\ndrivers/net/ethernet/ibm/Kconfig-10-\thelp\n--\ndrivers/net/ethernet/ibm/emac/Kconfig=2=config IBM_EMAC\ndrivers/net/ethernet/ibm/emac/Kconfig-3-\ttristate \"IBM EMAC Ethernet support\"\ndrivers/net/ethernet/ibm/emac/Kconfig:4:\tdepends on PPC_DCR\ndrivers/net/ethernet/ibm/emac/Kconfig-5-\tselect CRC32\n--\ndrivers/net/ethernet/ibm/emac/core.c=133=static inline void emac_rx_clk_tx(struct emac_instance *dev)\ndrivers/net/ethernet/ibm/emac/core.c-134-{\ndrivers/net/ethernet/ibm/emac/core.c:135:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-136-\tif (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))\n--\ndrivers/net/ethernet/ibm/emac/core.c=142=static inline void emac_rx_clk_default(struct emac_instance *dev)\ndrivers/net/ethernet/ibm/emac/core.c-143-{\ndrivers/net/ethernet/ibm/emac/core.c:144:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-145-\tif (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))\n--\ndrivers/net/ethernet/ibm/emac/core.c=331=static int emac_reset(struct emac_instance *dev)\n--\ndrivers/net/ethernet/ibm/emac/core.c-346-\ndrivers/net/ethernet/ibm/emac/core.c:347:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-348-do_retry:\n--\ndrivers/net/ethernet/ibm/emac/core.c-383-\ndrivers/net/ethernet/ibm/emac/core.c:384:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-385-\tif (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {\n--\ndrivers/net/ethernet/ibm/emac/core.c=2705=static int emac_init_phy(struct emac_instance *dev)\n--\ndrivers/net/ethernet/ibm/emac/core.c-2753-\t/* Enable internal clock source */\ndrivers/net/ethernet/ibm/emac/core.c:2754:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-2755-\tif (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))\n--\ndrivers/net/ethernet/ibm/emac/core.c-2761-\t/* Enable internal clock source on 440GX*/\ndrivers/net/ethernet/ibm/emac/core.c:2762:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-2763-\tif (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))\n--\ndrivers/net/ethernet/ibm/emac/core.c-2824-\t/* Enable external clock source */\ndrivers/net/ethernet/ibm/emac/core.c:2825:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/core.c-2826-\tif (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))\n--\ndrivers/net/ethernet/ibm/emac/mal.c=297=static irqreturn_t mal_txeob(int irq, void *dev_instance)\n--\ndrivers/net/ethernet/ibm/emac/mal.c-307-\ndrivers/net/ethernet/ibm/emac/mal.c:308:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/mal.c-309-\tif (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))\n--\ndrivers/net/ethernet/ibm/emac/mal.c=317=static irqreturn_t mal_rxeob(int irq, void *dev_instance)\n--\ndrivers/net/ethernet/ibm/emac/mal.c-327-\ndrivers/net/ethernet/ibm/emac/mal.c:328:#ifdef CONFIG_PPC_DCR_NATIVE\ndrivers/net/ethernet/ibm/emac/mal.c-329-\tif (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))\n--\ndrivers/net/ethernet/xilinx/ll_temac.h-10-\ndrivers/net/ethernet/xilinx/ll_temac.h:11:#ifdef CONFIG_PPC_DCR\ndrivers/net/ethernet/xilinx/ll_temac.h-12-#include \u003casm/dcr.h\u003e\n--\ndrivers/net/ethernet/xilinx/ll_temac.h=341=struct temac_local {\n--\ndrivers/net/ethernet/xilinx/ll_temac.h-356-\tvoid __iomem *sdma_regs;\ndrivers/net/ethernet/xilinx/ll_temac.h:357:#ifdef CONFIG_PPC_DCR\ndrivers/net/ethernet/xilinx/ll_temac.h-358-\tdcr_host_t sdma_dcrs;\n--\ndrivers/net/ethernet/xilinx/ll_temac_main.c=230=static void temac_dma_out32_le(struct temac_local *lp, int reg, u32 value)\n--\ndrivers/net/ethernet/xilinx/ll_temac_main.c-238- */\ndrivers/net/ethernet/xilinx/ll_temac_main.c:239:#ifdef CONFIG_PPC_DCR\ndrivers/net/ethernet/xilinx/ll_temac_main.c-240-\n--\ndrivers/video/fbdev/xilinxfb.c-36-\ndrivers/video/fbdev/xilinxfb.c:37:#ifdef CONFIG_PPC_DCR\ndrivers/video/fbdev/xilinxfb.c-38-#include \u003casm/dcr.h\u003e\n--\ndrivers/video/fbdev/xilinxfb.c=133=struct xilinxfb_drvdata {\n--\ndrivers/video/fbdev/xilinxfb.c-141-\t\t\t\t\t */\ndrivers/video/fbdev/xilinxfb.c:142:#ifdef CONFIG_PPC_DCR\ndrivers/video/fbdev/xilinxfb.c-143-\tdcr_host_t      dcr_host;\n--\ndrivers/video/fbdev/xilinxfb.c=166=static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset,\n--\ndrivers/video/fbdev/xilinxfb.c-174-\t}\ndrivers/video/fbdev/xilinxfb.c:175:#ifdef CONFIG_PPC_DCR\ndrivers/video/fbdev/xilinxfb.c-176-\telse\n--\ndrivers/video/fbdev/xilinxfb.c=181=static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset)\n--\ndrivers/video/fbdev/xilinxfb.c-188-\t}\ndrivers/video/fbdev/xilinxfb.c:189:#ifdef CONFIG_PPC_DCR\ndrivers/video/fbdev/xilinxfb.c-190-\telse\n--\ndrivers/video/fbdev/xilinxfb.c=374=static void xilinxfb_release(struct device *dev)\n--\ndrivers/video/fbdev/xilinxfb.c-394-\ndrivers/video/fbdev/xilinxfb.c:395:#ifdef CONFIG_PPC_DCR\ndrivers/video/fbdev/xilinxfb.c-396-\t/* Release the resources, as allocated based on interface */\n--\ndrivers/video/fbdev/xilinxfb.c=406=static int xilinxfb_of_probe(struct platform_device *pdev)\n--\ndrivers/video/fbdev/xilinxfb.c-434-\t\tdrvdata-\u003eflags |= BUS_ACCESS_FLAG;\ndrivers/video/fbdev/xilinxfb.c:435:#ifdef CONFIG_PPC_DCR\ndrivers/video/fbdev/xilinxfb.c-436-\telse {\n"
}

9/2 2026/11/02 10:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 15819
							output: 20
							thoughts: 621
						

Thoughts:
**Analyzing the Feasibility of IBM_EMAC on amd64**

Okay, so I'm looking at this patch and immediately, `CONFIG_IBM_EMAC` raises a red flag because it depends on `PPC_DCR`. My expert intuition kicks in, and I know that `PPC_DCR` is specifically defined within the PowerPC architecture's configuration files. Specifically, it relies on `PPC_DCR_NATIVE`, which, as the Kconfig files show, is only selected on PowerPC platforms.

Given that the target architecture is amd64, I need to figure out if there's any way this `IBM_EMAC` can *ever* be enabled. Let me go through the instructions. Section 2 talks about unreachable execution paths. Specifically, "Code paths exclusive to architectures other than the target architecture." Bingo. Is `IBM_EMAC` one of those?

Let's dive into `drivers/net/ethernet/ibm/emac/Kconfig`. Yup, there it is: `config IBM_EMAC` and the dreaded `depends on PPC_DCR`. It also selects a few other things, but that's irrelevant here. I also need to make sure that the patch itself doesn't introduce changes *outside* that directory. I check the diff, and the changed files are only within `drivers/net/ethernet/ibm/emac/`. All good there. So, `IBM_EMAC` *directly* depends on `PPC_DCR`.

So, the critical question: is there *any* possible path for `IBM_EMAC` to be enabled on amd64? I need to check if there is anything that is included to make it work. Let's look at the headers. `include/asm/dcr.h` or `#include <asm/dcr-regs.h>`. Looking at `core.c`, I see `#include <asm/processor.h>` and `#include <asm/io.h>`. In `mal.c` I see `#include <asm/dcr-regs.h>`.

Now I need to check the critical point: does `asm/dcr-regs.h` even *exist* on an amd64 system? I should use `grepper` or check the file system. If it *doesn't* exist, then the answer is a clear no.



10/2 2026/11/02 10:04 tool grepper
0m Args:
{
  "Expression": "dcr-regs.h"
}

Results:
{
  "Output": "arch/powerpc/platforms/44x/pci.c-32-#include \u003casm/dcr.h\u003e\narch/powerpc/platforms/44x/pci.c:33:#include \u003casm/dcr-regs.h\u003e\narch/powerpc/platforms/44x/pci.c-34-#include \u003cmm/mmu_decl.h\u003e\n--\narch/powerpc/platforms/44x/soc.c-21-#include \u003casm/dcr.h\u003e\narch/powerpc/platforms/44x/soc.c:22:#include \u003casm/dcr-regs.h\u003e\narch/powerpc/platforms/44x/soc.c-23-#include \u003casm/reg.h\u003e\n--\ndrivers/crypto/amcc/crypto4xx_core.c-26-#include \u003casm/dcr.h\u003e\ndrivers/crypto/amcc/crypto4xx_core.c:27:#include \u003casm/dcr-regs.h\u003e\ndrivers/crypto/amcc/crypto4xx_core.c-28-#include \u003casm/cacheflush.h\u003e\n--\ndrivers/dma/ppc4xx/adma.c-32-#include \u003casm/dcr.h\u003e\ndrivers/dma/ppc4xx/adma.c:33:#include \u003casm/dcr-regs.h\u003e\ndrivers/dma/ppc4xx/adma.c-34-#include \"adma.h\"\n--\ndrivers/net/ethernet/ibm/emac/core.c-50-#include \u003casm/dcr.h\u003e\ndrivers/net/ethernet/ibm/emac/core.c:51:#include \u003casm/dcr-regs.h\u003e\ndrivers/net/ethernet/ibm/emac/core.c-52-\n--\ndrivers/net/ethernet/ibm/emac/mal.c-30-#include \"core.h\"\ndrivers/net/ethernet/ibm/emac/mal.c:31:#include \u003casm/dcr-regs.h\u003e\ndrivers/net/ethernet/ibm/emac/mal.c-32-\n--\ndrivers/net/ethernet/xilinx/ll_temac.h-12-#include \u003casm/dcr.h\u003e\ndrivers/net/ethernet/xilinx/ll_temac.h:13:#include \u003casm/dcr-regs.h\u003e\ndrivers/net/ethernet/xilinx/ll_temac.h-14-#endif\n--\ndrivers/spi/spi-ppc4xx.c-38-#include \u003casm/dcr.h\u003e\ndrivers/spi/spi-ppc4xx.c:39:#include \u003casm/dcr-regs.h\u003e\ndrivers/spi/spi-ppc4xx.c-40-\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 17662
							output: 113
							thoughts: 765
						

Thoughts:
**Analysis of IBM EMAC and WorthFuzzing**

Okay, here's the situation. I've examined the code and the dependencies. `asm/dcr-regs.h` only exists within the PowerPC architecture's include directory, specifically `arch/powerpc/include/asm/dcr-regs.h`. There's no equivalent in `arch/x86/include/asm/`. Furthermore, the `Kconfig` file for the IBM EMAC driver (`drivers/net/ethernet/ibm/emac/Kconfig`) declares that `config IBM_EMAC` depends on `PPC_DCR`. And, importantly, `PPC_DCR` is *only* defined within `arch/powerpc/Kconfig`. This immediately tells me that `IBM_EMAC` is inherently tied to the PowerPC architecture. The IBM EMAC driver is specifically designed for IBM/AMCC PowerPC 4xx embedded SoCs, utilizing Device Control Registers (DCR) and the Memory Access Layer (MAL) DMA engine. It requires PPC hardware.

Now, I need to apply this to the fuzzing guidelines. Let's re-read the relevant section for negative criteria. Specifically, the "Unreachable execution paths" category. It clearly states that `WorthFuzzing` should be false if the code path is "exclusive to architectures other than the target architecture." Our target architecture is `amd64`. The modified code, namely the IBM EMAC driver, *is* exclusive to the PowerPC architecture, as demonstrated by the `PPC_DCR` dependency. It can't be compiled or executed on `amd64`.

Therefore, based on the triage guidelines, `WorthFuzzing` must be set to `false`. There's no other logical conclusion.

For the `set-results` fields, I'll need to populate:

*   `WorthFuzzing`: `false`
*   `Reasoning`: Explicitly state that IBM EMAC depends on `PPC_DCR`, which is exclusive to the PowerPC architecture (IBM/AMCC PowerPC 4xx SoCs). This means the driver cannot be compiled or executed on the target `amd64` architecture.
*   `FocusSymbols`: `[]` (empty list, as there are no specific symbols of interest to focus on.)
*   `EnableConfigs`: `[]` (empty list, as there are no configurations to enable.)

I'm double-checking everything to ensure I've adhered to the "Unreachable execution paths" guideline, the target architecture, and the architectural dependency of the code, and everything aligns. This conclusion is definitive. I am now ready to proceed and call `set-results`.



12/2 2026/11/02 10:04 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The changes in this patch series exclusively modify the IBM EMAC network device driver (drivers/net/ethernet/ibm/emac/), which depends on CONFIG_PPC_DCR (PowerPC Device Control Register support). This driver is specific to PowerPC architectures (IBM/AMCC PowerPC 4xx SoCs) and cannot be compiled or executed on the target architecture (amd64).",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The changes in this patch series exclusively modify the IBM EMAC network device driver (drivers/net/ethernet/ibm/emac/), which depends on CONFIG_PPC_DCR (PowerPC Device Control Register support). This driver is specific to PowerPC architectures (IBM/AMCC PowerPC 4xx SoCs) and cannot be compiled or executed on the target architecture (amd64).",
  "WorthFuzzing": false
}

13/1 2026/11/02 10:04 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)