| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/10 19:37 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"NET",
"ETHTOOL_NETLINK"
],
"FocusSymbols": [
"netdev_reconfig_start",
"netdev_queue_config_revalidate",
"netdev_alloc_config",
"netdev_free_config",
"ethtool_ringparam_set_cfg",
"ethtool_set_ringparam",
"ethnl_set_rings"
],
"KMSANReasoning": "The patch series adds netdev queue configuration tracking for ring sizes (storing accepted ring sizes in dev-\u003ecfg/dev-\u003ecfg_pending and validating queue configurations upon ring changes) and implements multi-page RX buffer descriptor support in the Meta fbnic driver.\n\n- Memory Initialization: All newly allocated kernel objects (dev-\u003ecfg via kzalloc_obj in netdev_alloc_config and cloned via kmemdup in netdev_reconfig_start) and stack structures (qcfg in __netdev_queue_config) are explicitly zero-initialized using kzalloc/kmemdup/memset prior to usage.\n- User-Kernel Boundary: No uninitialized kernel struct fields or padding bytes are exposed to user space. Ethtool notifications and ioctls use existing initialized data paths.\n- Driver Logic: Changes in fbnic modify descriptor indexing, page offset calculations, and ring sizing logic based on bd_page_shift. Any boundary or calculation errors here would involve out-of-bounds ring accesses or DMA descriptor management, which are detectable by KASAN or hardware/driver assertions, rather than reads of uninitialized memory.\n\nBecause no uninitialized memory risks or info-leaks are introduced or exposed, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch series modifies core networking configuration logic (net/core/dev.c, net/core/netdev_config.c) and ethtool ring parameter interfaces (net/ethtool/ioctl.c, net/ethtool/rings.c, net/ethtool/common.c) in addition to the fbnic driver. It refactors ring and queue configuration lifecycle management, adds transaction-based configuration validation helpers (netdev_reconfig_start, netdev_queue_config_revalidate), and includes state assertions (WARN_ON). These code paths are directly reachable from userspace via SIOCETHTOOL ioctl commands and Ethtool generic Netlink messages on any netdevice, making them worth fuzzing.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/10 19:37 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 99bc766fcd57eaf682f9ea8903f89d67ab31862b\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Sep 10 19:37:00 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h\nindex 64b958df77744..2b9f8644b132d 100644\n--- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h\n+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h\n@@ -109,34 +109,19 @@ enum {\n \n /* Rx Buffer Descriptor Format\n *\n- * The layout of this can vary depending on the page size of the system.\n+ * Buffer descriptors describe 4 KiB device pages. A posted page larger than\n+ * 4 KiB is represented by consecutive device-page descriptors.\n *\n- * If the page size is 4K then the layout will simply consist of ID for\n- * the 16 most significant bits, and the lower 46 are essentially the page\n- * address with the lowest 12 bits being reserved 0 due to the fact that\n- * a page will be aligned.\n- *\n- * If the page size is larger than 4K then the lower n bits of the ID and\n- * page address will be reserved for the fragment ID. This fragment will\n- * be 4K in size and will be used to index both the DMA address and the ID\n- * by the same amount.\n+ * The address field stores the 4 KiB-aligned DMA address. The ID field stores\n+ * the software page ID, with the low n bits used as the device-page ID when a\n+ * posted page spans multiple device pages. The driver increments both the\n+ * address and ID by one device page for each descriptor belonging to a posted\n+ * page.\n */\n #define FBNIC_BD_DESC_ADDR_MASK\t\t\tDESC_GENMASK(45, 12)\n #define FBNIC_BD_DESC_ID_MASK\t\t\tDESC_GENMASK(63, 48)\n-#define FBNIC_BD_FRAG_SIZE \\\n+#define FBNIC_BD_PAGE_SIZE \\\n \t(FBNIC_BD_DESC_ADDR_MASK \u0026 ~(FBNIC_BD_DESC_ADDR_MASK - 1))\n-#define FBNIC_BD_FRAG_COUNT \\\n-\t(PAGE_SIZE / FBNIC_BD_FRAG_SIZE)\n-#define FBNIC_BD_FRAG_ADDR_MASK \\\n-\t(FBNIC_BD_DESC_ADDR_MASK \u0026 \\\n-\t ~(FBNIC_BD_DESC_ADDR_MASK * FBNIC_BD_FRAG_COUNT))\n-#define FBNIC_BD_FRAG_ID_MASK \\\n-\t(FBNIC_BD_DESC_ID_MASK \u0026 \\\n-\t ~(FBNIC_BD_DESC_ID_MASK * FBNIC_BD_FRAG_COUNT))\n-#define FBNIC_BD_PAGE_ADDR_MASK \\\n-\t(FBNIC_BD_DESC_ADDR_MASK \u0026 ~FBNIC_BD_FRAG_ADDR_MASK)\n-#define FBNIC_BD_PAGE_ID_MASK \\\n-\t(FBNIC_BD_DESC_ID_MASK \u0026 ~FBNIC_BD_FRAG_ID_MASK)\n \n /* Rx Completion Queue Descriptors */\n #define FBNIC_RCD_TYPE_MASK\t\t\tDESC_GENMASK(62, 61)\n@@ -151,9 +136,6 @@ enum {\n \n /* Address/Length Completion Descriptors */\n #define FBNIC_RCD_AL_BUFF_ID_MASK\t\tDESC_GENMASK(15, 0)\n-#define FBNIC_RCD_AL_BUFF_FRAG_MASK\t\t(FBNIC_BD_FRAG_COUNT - 1)\n-#define FBNIC_RCD_AL_BUFF_PAGE_MASK \\\n-\t(FBNIC_RCD_AL_BUFF_ID_MASK \u0026 ~FBNIC_RCD_AL_BUFF_FRAG_MASK)\n #define FBNIC_RCD_AL_BUFF_LEN_MASK\t\tDESC_GENMASK(28, 16)\n #define FBNIC_RCD_AL_BUFF_OFF_MASK\t\tDESC_GENMASK(43, 32)\n #define FBNIC_RCD_AL_PAGE_FIN\t\t\tDESC_BIT(60)\ndiff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c\nindex 3c4563c8f403f..7f23a0f97e637 100644\n--- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c\n+++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c\n@@ -181,8 +181,8 @@ static int fbnic_dbg_tcq_desc_seq_show(struct seq_file *s, void *v)\n static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)\n {\n \tstruct fbnic_ring *ring = s-\u003eprivate;\n+\tunsigned int i, desc_count;\n \tchar hdr[80];\n-\tint i;\n \n \t/* Generate header on first entry */\n \tfbnic_dbg_ring_show(s);\n@@ -197,7 +197,8 @@ static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)\n \t\treturn 0;\n \t}\n \n-\tfor (i = 0; i \u003c (ring-\u003esize_mask + 1) * FBNIC_BD_FRAG_COUNT; i++) {\n+\tdesc_count = (ring-\u003esize_mask + 1) * fbnic_bd_page_count(ring);\n+\tfor (i = 0; i \u003c desc_count; i++) {\n \t\tu64 bd = le64_to_cpu(ring-\u003edesc[i]);\n \n \t\tseq_printf(s, \"%04x %#04llx %#014llx\\n\", i,\ndiff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c\nindex 0e47088ec44ba..2def4c26207d1 100644\n--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c\n+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c\n@@ -334,10 +334,10 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,\n \tstruct fbnic_net *clone;\n \tint err;\n \n-\tring-\u003erx_pending\t= roundup_pow_of_two(ring-\u003erx_pending);\n-\tring-\u003erx_mini_pending\t= roundup_pow_of_two(ring-\u003erx_mini_pending);\n-\tring-\u003erx_jumbo_pending\t= roundup_pow_of_two(ring-\u003erx_jumbo_pending);\n-\tring-\u003etx_pending\t= roundup_pow_of_two(ring-\u003etx_pending);\n+\tring-\u003erx_pending\t= fbnic_ring_size_pow2(ring-\u003erx_pending);\n+\tring-\u003erx_mini_pending\t= fbnic_ring_size_pow2(ring-\u003erx_mini_pending);\n+\tring-\u003erx_jumbo_pending\t= fbnic_ring_size_pow2(ring-\u003erx_jumbo_pending);\n+\tring-\u003etx_pending\t= fbnic_ring_size_pow2(ring-\u003etx_pending);\n \n \t/* These are absolute minimums allowing the device and driver to operate\n \t * but not necessarily guarantee reasonable performance. Settings below\ndiff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c\nindex 10bf99be3f244..8bc5e6e5c59e8 100644\n--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c\n+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c\n@@ -773,6 +773,11 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)\n \tfbn-\u003eppq_size = FBNIC_PPQ_SIZE_DEFAULT;\n \tfbn-\u003ercq_size = FBNIC_RCQ_SIZE_DEFAULT;\n \n+\tnetdev-\u003ecfg-\u003erings.rx_pending = fbn-\u003ercq_size;\n+\tnetdev-\u003ecfg-\u003erings.rx_mini_pending = fbn-\u003ehpq_size;\n+\tnetdev-\u003ecfg-\u003erings.rx_jumbo_pending = fbn-\u003eppq_size;\n+\tnetdev-\u003ecfg-\u003erings.tx_pending = fbn-\u003etxq_size;\n+\n \tfbn-\u003etx_usecs = FBNIC_TX_USECS_DEFAULT;\n \tfbn-\u003erx_usecs = FBNIC_RX_USECS_DEFAULT;\n \tfbn-\u003erx_max_frames = FBNIC_RX_FRAMES_DEFAULT;\ndiff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c\nindex 401f8b8ae1cae..5e22905a63739 100644\n--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c\n+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c\n@@ -871,19 +871,31 @@ static void fbnic_clean_bdq(struct fbnic_ring *ring, unsigned int hw_head,\n \tring-\u003ehead = head;\n }\n \n+static u16 fbnic_rcd_bd_idx(const struct fbnic_ring *bdq, u64 rcd)\n+{\n+\treturn FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd) \u003e\u003e bdq-\u003ebd_page_shift;\n+}\n+\n+static unsigned int fbnic_rcd_bd_page_offset(const struct fbnic_ring *bdq,\n+\t\t\t\t\t u64 rcd)\n+{\n+\tu16 id = FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd);\n+\tu16 page_id = id \u0026 (fbnic_bd_page_count(bdq) - 1);\n+\n+\treturn page_id * FBNIC_BD_PAGE_SIZE;\n+}\n+\n static void fbnic_bd_prep(struct fbnic_ring *bdq, u16 id, netmem_ref netmem)\n {\n-\t__le64 *bdq_desc = \u0026bdq-\u003edesc[id * FBNIC_BD_FRAG_COUNT];\n+\t__le64 *bdq_desc = \u0026bdq-\u003edesc[id * fbnic_bd_page_count(bdq)];\n \tdma_addr_t dma = page_pool_get_dma_addr_netmem(netmem);\n-\tu64 bd, i = FBNIC_BD_FRAG_COUNT;\n+\tu64 bd, i = fbnic_bd_page_count(bdq);\n \n-\tbd = (FBNIC_BD_PAGE_ADDR_MASK \u0026 dma) |\n-\t FIELD_PREP(FBNIC_BD_PAGE_ID_MASK, id);\n+\tbd = (FBNIC_BD_DESC_ADDR_MASK \u0026 dma) |\n+\t FIELD_PREP(FBNIC_BD_DESC_ID_MASK, (u64)id \u003c\u003c bdq-\u003ebd_page_shift);\n \n-\t/* In the case that a page size is larger than 4K we will map a\n-\t * single page to multiple fragments. The fragments will be\n-\t * FBNIC_BD_FRAG_COUNT in size and the lower n bits will be use\n-\t * to indicate the individual fragment IDs.\n+\t/* Posted pages larger than 4 KiB use consecutive device-page IDs in\n+\t * the low bits of the software page ID.\n \t */\n \tdo {\n \t\t*bdq_desc = cpu_to_le64(bd);\n@@ -928,7 +940,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq)\n \t\t/* Force DMA writes to flush before writing to tail */\n \t\tdma_wmb();\n \n-\t\twritel(i * FBNIC_BD_FRAG_COUNT, bdq-\u003edoorbell);\n+\t\twritel(i * fbnic_bd_page_count(bdq), bdq-\u003edoorbell);\n \t}\n }\n \n@@ -959,26 +971,27 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd,\n \t\t\t struct fbnic_pkt_buff *pkt,\n \t\t\t struct fbnic_q_triad *qt)\n {\n-\tunsigned int hdr_pg_idx = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);\n \tunsigned int hdr_pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd);\n-\tstruct page *page = fbnic_page_pool_get_head(qt, hdr_pg_idx);\n \tunsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd);\n+\tunsigned int hdr_pg_idx = fbnic_rcd_bd_idx(\u0026qt-\u003esub0, rcd);\n \tunsigned int frame_sz, hdr_pg_start, hdr_pg_end, headroom;\n \tunsigned char *hdr_start;\n+\tstruct page *page;\n \n \t/* data_hard_start should always be NULL when this is called */\n \tWARN_ON_ONCE(pkt-\u003ebuff.data_hard_start);\n \n+\tpage = fbnic_page_pool_get_head(qt, hdr_pg_idx);\n+\n \t/* Short-cut the end calculation if we know page is fully consumed */\n \thdr_pg_end = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ?\n-\t\t FBNIC_BD_FRAG_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len);\n+\t\t FBNIC_BD_PAGE_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len);\n \thdr_pg_start = fbnic_hdr_pg_start(hdr_pg_off);\n \n \theadroom = hdr_pg_off - hdr_pg_start + FBNIC_RX_PAD;\n \tframe_sz = hdr_pg_end - hdr_pg_start;\n \txdp_init_buff(\u0026pkt-\u003ebuff, frame_sz, \u0026qt-\u003exdp_rxq);\n-\thdr_pg_start += (FBNIC_RCD_AL_BUFF_FRAG_MASK \u0026 rcd) *\n-\t\t\tFBNIC_BD_FRAG_SIZE;\n+\thdr_pg_start += fbnic_rcd_bd_page_offset(\u0026qt-\u003esub0, rcd);\n \n \t/* Sync DMA buffer */\n \tdma_sync_single_range_for_cpu(nv-\u003edev, page_pool_get_dma_addr(page),\n@@ -999,23 +1012,28 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vector *nv, u64 rcd,\n \t\t\t struct fbnic_pkt_buff *pkt,\n \t\t\t struct fbnic_q_triad *qt)\n {\n-\tunsigned int pg_idx = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);\n \tunsigned int pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd);\n \tunsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd);\n-\tnetmem_ref netmem = fbnic_page_pool_get_data(qt, pg_idx);\n+\tunsigned int pg_idx = fbnic_rcd_bd_idx(\u0026qt-\u003esub1, rcd);\n \tunsigned int truesize;\n+\tnetmem_ref netmem;\n \tbool added;\n \n+\tnetmem = fbnic_page_pool_get_data(qt, pg_idx);\n+\n \ttruesize = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ?\n-\t\t FBNIC_BD_FRAG_SIZE - pg_off : ALIGN(len, 128);\n+\t\t FBNIC_BD_PAGE_SIZE - pg_off :\n+\t\t ALIGN(len, FBNIC_RX_PAYLD_ALIGN);\n \n-\tpg_off += (FBNIC_RCD_AL_BUFF_FRAG_MASK \u0026 rcd) *\n-\t\t FBNIC_BD_FRAG_SIZE;\n+\tpg_off += fbnic_rcd_bd_page_offset(\u0026qt-\u003esub1, rcd);\n \n \t/* Sync DMA buffer */\n \tpage_pool_dma_sync_netmem_for_cpu(qt-\u003esub1.page_pool, netmem,\n \t\t\t\t\t pg_off, truesize);\n \n+\t/* Consecutive device-page completions from one PPQ page are adjacent\n+\t * ranges in the same netmem.\n+\t */\n \tadded = xdp_buff_add_frag(\u0026pkt-\u003ebuff, netmem, pg_off, len, truesize);\n \tif (unlikely(!added)) {\n \t\tpkt-\u003eadd_frag_failed = true;\n@@ -1257,12 +1275,12 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv,\n \n \t\tswitch (FIELD_GET(FBNIC_RCD_TYPE_MASK, rcd)) {\n \t\tcase FBNIC_RCD_TYPE_HDR_AL:\n-\t\t\thead0 = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);\n+\t\t\thead0 = fbnic_rcd_bd_idx(\u0026qt-\u003esub0, rcd);\n \t\t\tfbnic_pkt_prepare(nv, rcd, pkt, qt);\n \n \t\t\tbreak;\n \t\tcase FBNIC_RCD_TYPE_PAY_AL:\n-\t\t\thead1 = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);\n+\t\t\thead1 = fbnic_rcd_bd_idx(\u0026qt-\u003esub1, rcd);\n \t\t\tfbnic_add_rx_frag(nv, rcd, pkt, qt);\n \n \t\t\tbreak;\n@@ -1550,7 +1568,7 @@ void fbnic_free_napi_vectors(struct fbnic_net *fbn)\n \n static int\n fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,\n-\t\t\t unsigned int rxq_idx)\n+\t\t\t unsigned int rxq_idx, u32 rx_page_size)\n {\n \tstruct page_pool_params pp_params = {\n \t\t.order = 0,\n@@ -1585,6 +1603,8 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,\n \n \tqt-\u003esub0.page_pool = pp;\n \tif (netif_rxq_has_unreadable_mp(fbn-\u003enetdev, rxq_idx)) {\n+\t\tpp_params.order = get_order(rx_page_size);\n+\t\tpp_params.max_len = rx_page_size;\n \t\tpp_params.flags |= PP_FLAG_ALLOW_UNREADABLE_NETMEM;\n \t\tpp_params.dma_dir = DMA_FROM_DEVICE;\n \n@@ -1603,6 +1623,16 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,\n \treturn PTR_ERR(pp);\n }\n \n+static u8 fbnic_bdq_page_shift(u32 page_size)\n+{\n+\treturn ilog2(page_size / FBNIC_BD_PAGE_SIZE);\n+}\n+\n+static void fbnic_bdq_set_page_size(struct fbnic_ring *bdq, u32 page_size)\n+{\n+\tbdq-\u003ebd_page_shift = fbnic_bdq_page_shift(page_size);\n+}\n+\n static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell,\n \t\t\t int q_idx, u8 flags)\n {\n@@ -1610,6 +1640,7 @@ static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell,\n \tring-\u003edoorbell = doorbell;\n \tring-\u003eq_idx = q_idx;\n \tring-\u003eflags = flags;\n+\tfbnic_bdq_set_page_size(ring, PAGE_SIZE);\n \tring-\u003edeferred_head = -1;\n }\n \n@@ -1894,12 +1925,12 @@ static int fbnic_alloc_rx_ring_desc(struct fbnic_net *fbn,\n \n \tswitch (rxr-\u003edoorbell - fbnic_ring_csr_base(rxr)) {\n \tcase FBNIC_QUEUE_BDQ_HPQ_TAIL:\n-\t\trxq_size = fbn-\u003ehpq_size / FBNIC_BD_FRAG_COUNT;\n-\t\tdesc_size *= FBNIC_BD_FRAG_COUNT;\n+\t\trxq_size = fbn-\u003ehpq_size / fbnic_bd_page_count(rxr);\n+\t\tdesc_size *= fbnic_bd_page_count(rxr);\n \t\tbreak;\n \tcase FBNIC_QUEUE_BDQ_PPQ_TAIL:\n-\t\trxq_size = fbn-\u003eppq_size / FBNIC_BD_FRAG_COUNT;\n-\t\tdesc_size *= FBNIC_BD_FRAG_COUNT;\n+\t\trxq_size = fbn-\u003eppq_size / fbnic_bd_page_count(rxr);\n+\t\tdesc_size *= fbnic_bd_page_count(rxr);\n \t\tbreak;\n \tcase FBNIC_QUEUE_RCQ_HEAD:\n \t\trxq_size = fbn-\u003ercq_size;\n@@ -2003,15 +2034,18 @@ static int fbnic_alloc_tx_qt_resources(struct fbnic_net *fbn,\n \n static int fbnic_alloc_rx_qt_resources(struct fbnic_net *fbn,\n \t\t\t\t struct fbnic_napi_vector *nv,\n-\t\t\t\t struct fbnic_q_triad *qt)\n+\t\t\t\t struct fbnic_q_triad *qt,\n+\t\t\t\t u32 rx_page_size)\n {\n \tstruct device *dev = fbn-\u003enetdev-\u003edev.parent;\n \tint err;\n \n-\terr = fbnic_alloc_qt_page_pools(fbn, qt, qt-\u003ecmpl.q_idx);\n+\terr = fbnic_alloc_qt_page_pools(fbn, qt, qt-\u003ecmpl.q_idx, rx_page_size);\n \tif (err)\n \t\treturn err;\n \n+\tfbnic_bdq_set_page_size(\u0026qt-\u003esub1, rx_page_size);\n+\n \terr = xdp_rxq_info_reg(\u0026qt-\u003exdp_rxq, fbn-\u003enetdev, qt-\u003esub0.q_idx,\n \t\t\t nv-\u003enapi.napi_id);\n \tif (err)\n@@ -2072,7 +2106,11 @@ static int fbnic_alloc_nv_resources(struct fbnic_net *fbn,\n \n \t/* Allocate Rx Resources */\n \tfor (j = 0; j \u003c nv-\u003erxt_count; j++, i++) {\n-\t\terr = fbnic_alloc_rx_qt_resources(fbn, nv, \u0026nv-\u003eqt[i]);\n+\t\tstruct netdev_queue_config qcfg;\n+\n+\t\tnetdev_queue_config(fbn-\u003enetdev, nv-\u003eqt[i].cmpl.q_idx, \u0026qcfg);\n+\t\terr = fbnic_alloc_rx_qt_resources(fbn, nv, \u0026nv-\u003eqt[i],\n+\t\t\t\t\t\t qcfg.rx_page_size);\n \t\tif (err)\n \t\t\tgoto free_qt_resources;\n \t}\n@@ -2565,7 +2603,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)\n \thpq-\u003etail = 0;\n \thpq-\u003ehead = 0;\n \n-\tlog_size = fls(hpq-\u003esize_mask) + ilog2(FBNIC_BD_FRAG_COUNT);\n+\tlog_size = fls(hpq-\u003esize_mask) + hpq-\u003ebd_page_shift;\n \n \t/* Store descriptor ring address and size */\n \tfbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq-\u003edma));\n@@ -2577,7 +2615,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)\n \tif (!ppq-\u003esize_mask)\n \t\tgoto write_ctl;\n \n-\tlog_size = fls(ppq-\u003esize_mask) + ilog2(FBNIC_BD_FRAG_COUNT);\n+\tlog_size = fls(ppq-\u003esize_mask) + ppq-\u003ebd_page_shift;\n \n \t/* Add enabling of PPQ to BDQ control */\n \tbdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;\n@@ -2839,7 +2877,8 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,\n \tstruct fbnic_napi_vector *nv;\n \n \tif (!netif_running(dev))\n-\t\treturn fbnic_alloc_qt_page_pools(fbn, qt, idx);\n+\t\treturn fbnic_alloc_qt_page_pools(fbn, qt, idx,\n+\t\t\t\t\t\t qcfg-\u003erx_page_size);\n \n \treal = container_of(fbn-\u003erx[idx], struct fbnic_q_triad, cmpl);\n \tnv = fbn-\u003enapi[idx % fbn-\u003enum_napi];\n@@ -2851,7 +2890,62 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,\n \tfbnic_ring_init(\u0026qt-\u003ecmpl, real-\u003ecmpl.doorbell, real-\u003ecmpl.q_idx,\n \t\t\treal-\u003ecmpl.flags);\n \n-\treturn fbnic_alloc_rx_qt_resources(fbn, nv, qt);\n+\treturn fbnic_alloc_rx_qt_resources(fbn, nv, qt, qcfg-\u003erx_page_size);\n+}\n+\n+static void fbnic_default_qcfg(struct net_device *dev,\n+\t\t\t struct netdev_queue_config *qcfg)\n+{\n+\tqcfg-\u003erx_page_size = PAGE_SIZE;\n+}\n+\n+static int fbnic_validate_qcfg(struct net_device *dev,\n+\t\t\t struct netdev_queue_config *qcfg,\n+\t\t\t struct netlink_ext_ack *extack)\n+{\n+\tu32 ppq_size = fbnic_ring_size_pow2(qcfg-\u003erx_jumbo_ring_size);\n+\tu32 bd_page_count, ppq_entries, frag_count;\n+\tu32 rx_page_size = qcfg-\u003erx_page_size;\n+\n+\tif (!is_power_of_2(rx_page_size)) {\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"rx_page_size must be a power of 2\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (rx_page_size \u003c FBNIC_BD_PAGE_SIZE) {\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"rx_page_size must be at least 4K\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Payload fragments occupy multiples of FBNIC_RX_PAYLD_ALIGN bytes.\n+\t * Keep at least one reference in the bias until fbnic_clean_bdq()\n+\t * observes a completion from a subsequent allocation.\n+\t */\n+\tfrag_count = rx_page_size / FBNIC_RX_PAYLD_ALIGN;\n+\tif (frag_count \u003e= FBNIC_PAGECNT_BIAS_MAX) {\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"rx_page_size can produce too many fragments\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tbd_page_count = rx_page_size / FBNIC_BD_PAGE_SIZE;\n+\tppq_entries = ppq_size / bd_page_count;\n+\t/* The PPQ is sized in 4 KiB device pages. One software entry tracks\n+\t * each page-pool allocation. In addition to the unused entry for\n+\t * empty/full accounting, cleanup retains the current allocation\n+\t * until a completion identifies a subsequent allocation. A two-entry\n+\t * ring can only post one allocation and cannot make progress.\n+\t * Require at least four entries, since ring sizes are powers of two.\n+\t */\n+\tif (ppq_entries \u003c 4) {\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"rx-jumbo ring size too small for rx_page_size\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n }\n \n static void fbnic_queue_mem_free(struct net_device *dev, void *qmem)\n@@ -2953,4 +3047,7 @@ const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops = {\n \t.ndo_queue_mem_free\t= fbnic_queue_mem_free,\n \t.ndo_queue_start\t= fbnic_queue_start,\n \t.ndo_queue_stop\t\t= fbnic_queue_stop,\n+\t.ndo_default_qcfg\t= fbnic_default_qcfg,\n+\t.ndo_validate_qcfg\t= fbnic_validate_qcfg,\n+\t.supported_params\t= QCFG_RX_PAGE_SIZE,\n };\ndiff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h\nindex e03c9d2c38dca..12b3a684f4611 100644\n--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h\n+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h\n@@ -49,12 +49,18 @@ struct fbnic_net;\n #define FBNIC_RX_USECS_DEFAULT\t\t30\n #define FBNIC_RX_FRAMES_DEFAULT\t\t0\n \n+static inline u32 fbnic_ring_size_pow2(u32 size)\n+{\n+\treturn size ? roundup_pow_of_two(size) : 0;\n+}\n+\n #define FBNIC_RX_TROOM \\\n \tSKB_DATA_ALIGN(sizeof(struct skb_shared_info))\n #define FBNIC_RX_HROOM_PAD\t\t128\n #define FBNIC_RX_HROOM \\\n \t(ALIGN(FBNIC_RX_TROOM + FBNIC_RX_HROOM_PAD, 128) - FBNIC_RX_TROOM)\n #define FBNIC_RX_PAD\t\t\t0\n+#define FBNIC_RX_PAYLD_ALIGN\t\t128\n #define FBNIC_RX_PAYLD_OFFSET\t\t0\n #define FBNIC_RX_PAYLD_PG_CL\t\t0\n \n@@ -121,6 +127,7 @@ struct fbnic_ring {\n \tu16 size_mask;\t\t\t/* Size of ring in descriptors - 1 */\n \tu8 q_idx;\t\t\t/* Logical netdev ring index */\n \tu8 flags;\t\t\t/* Ring flags (FBNIC_RING_F_*) */\n+\tu8 bd_page_shift;\t\t/* BDQ: ilog2(page_size / 4096) */\n \n \tu32 head, tail;\t\t\t/* Head/Tail of ring */\n \n@@ -162,6 +169,11 @@ struct fbnic_napi_vector {\n \n extern const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops;\n \n+static inline u16 fbnic_bd_page_count(const struct fbnic_ring *bdq)\n+{\n+\treturn 1U \u003c\u003c bdq-\u003ebd_page_shift;\n+}\n+\n netdev_tx_t fbnic_xmit_frame(struct sk_buff *skb, struct net_device *dev);\n netdev_features_t\n fbnic_features_check(struct sk_buff *skb, struct net_device *dev,\ndiff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h\nindex 70c9fe9e83cc4..31121900aac88 100644\n--- a/include/net/netdev_queues.h\n+++ b/include/net/netdev_queues.h\n@@ -4,18 +4,59 @@\n \n #include \u003clinux/netdevice.h\u003e\n \n+/**\n+ * struct netdev_ring_config - accepted RX/TX ring depth configuration\n+ * @rx_pending:\t\tSize of the regular RX ring.\n+ * @rx_mini_pending:\tSize of the RX mini ring.\n+ * @rx_jumbo_pending:\tSize of the RX jumbo ring.\n+ * @tx_pending:\t\tSize of the TX ring.\n+ *\n+ * This stores only persistent configuration values. Capability fields,\n+ * such as max ring sizes, are reported by drivers but are not part of the\n+ * accepted configuration.\n+ *\n+ * Note: these values are only used for queue-configuration validation\n+ * today. Some drivers update their ring sizes without reflecting the change\n+ * in @cfg. Before using the stored values for anything else, those cases\n+ * need to be audited, and the core likely needs a driver notification API\n+ * similar to ethtool_rxfh_context_lost().\n+ */\n+struct netdev_ring_config {\n+\tu32\trx_pending;\n+\tu32\trx_mini_pending;\n+\tu32\trx_jumbo_pending;\n+\tu32\ttx_pending;\n+};\n+\n /**\n * struct netdev_config - queue-related configuration for a netdev\n * @hds_thresh:\t\tHDS Threshold value.\n * @hds_config:\t\tHDS value from userspace.\n+ * @rings:\t\tAccepted RX/TX ring depths.\n+ *\n+ * Direct values, such as @hds_thresh and @rings, hold the current\n+ * accepted configuration. Drivers which use them for queue rendering\n+ * must initialize them with their defaults.\n */\n struct netdev_config {\n \tu32\thds_thresh;\n \tu8\thds_config;\n+\n+\tstruct netdev_ring_config rings;\n };\n \n+/**\n+ * struct netdev_queue_config - rendered configuration for an RX queue\n+ * @rx_page_size:\tSize of one RX page-pool allocation.\n+ * @rx_ring_size:\tEffective size of the regular RX ring.\n+ * @rx_mini_ring_size:\tEffective size of the RX mini ring.\n+ * @rx_jumbo_ring_size:\tEffective size of the RX jumbo ring.\n+ */\n struct netdev_queue_config {\n \tu32\trx_page_size;\n+\tu32\trx_ring_size;\n+\tu32\trx_mini_ring_size;\n+\tu32\trx_jumbo_ring_size;\n };\n \n /* See the netdev.yaml spec for definition of each statistic */\n@@ -145,10 +186,9 @@ enum {\n *\n * @ndo_validate_qcfg: (Optional) Check if queue config is supported.\n *\t\t\tCalled when configuration affecting a queue may be\n- *\t\t\tchanging, either due to NIC-wide config, or config\n- *\t\t\tscoped to the queue at a specified index.\n- *\t\t\tWhen NIC-wide config is changed the callback will\n- *\t\t\tbe invoked for all queues.\n+ *\t\t\tchanging. When NIC-wide config is changed the\n+ *\t\t\tcallback will be invoked for the defaults and all\n+ *\t\t\tqueue overrides.\n *\n * @ndo_queue_create:\tCreate a new RX queue on a virtual device that will\n *\t\t\tbe paired with a physical device's queue via leasing.\ndiff --git a/net/core/dev.c b/net/core/dev.c\nindex 290e0f099e6bf..4a7c5a5e48e52 100644\n--- a/net/core/dev.c\n+++ b/net/core/dev.c\n@@ -12195,10 +12195,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,\n \tif (!dev-\u003eethtool)\n \t\tgoto free_all;\n \n-\tdev-\u003ecfg = kzalloc_obj(*dev-\u003ecfg, GFP_KERNEL_ACCOUNT);\n-\tif (!dev-\u003ecfg)\n+\tif (netdev_alloc_config(dev))\n \t\tgoto free_all;\n-\tdev-\u003ecfg_pending = dev-\u003ecfg;\n \n \tdev-\u003enum_napi_configs = maxqs;\n \tnapi_config_sz = array_size(maxqs, sizeof(*dev-\u003enapi_config));\n@@ -12270,8 +12268,7 @@ void free_netdev(struct net_device *dev)\n \t\treturn;\n \t}\n \n-\tWARN_ON(dev-\u003ecfg != dev-\u003ecfg_pending);\n-\tkfree(dev-\u003ecfg);\n+\tnetdev_free_config(dev);\n \tkfree(dev-\u003eethtool);\n \tnetif_free_tx_queues(dev);\n \tnetif_free_rx_queues(dev);\ndiff --git a/net/core/dev.h b/net/core/dev.h\nindex b757faead4d1a..567e7b82ef24b 100644\n--- a/net/core/dev.h\n+++ b/net/core/dev.h\n@@ -102,9 +102,16 @@ extern struct rw_semaphore dev_addr_sem;\n extern struct list_head net_todo_list;\n void netdev_run_todo(void);\n \n+int netdev_alloc_config(struct net_device *dev);\n+void __netdev_free_config(struct netdev_config *cfg);\n+void netdev_free_config(struct net_device *dev);\n+int netdev_reconfig_start(struct net_device *dev);\n+\n int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,\n \t\t\t\t struct netdev_queue_config *qcfg,\n \t\t\t\t struct netlink_ext_ack *extack);\n+int netdev_queue_config_revalidate(struct net_device *dev,\n+\t\t\t\t struct netlink_ext_ack *extack);\n \n bool netif_rxq_has_mp(struct net_device *dev, unsigned int rxq_idx);\n bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx);\ndiff --git a/net/core/netdev_config.c b/net/core/netdev_config.c\nindex f14af365d5cd7..1975de42a60d9 100644\n--- a/net/core/netdev_config.c\n+++ b/net/core/netdev_config.c\n@@ -6,6 +6,43 @@\n \n #include \"dev.h\"\n \n+int netdev_alloc_config(struct net_device *dev)\n+{\n+\tstruct netdev_config *cfg;\n+\n+\tcfg = kzalloc_obj(*dev-\u003ecfg, GFP_KERNEL_ACCOUNT);\n+\tif (!cfg)\n+\t\treturn -ENOMEM;\n+\n+\tdev-\u003ecfg = cfg;\n+\tdev-\u003ecfg_pending = cfg;\n+\treturn 0;\n+}\n+\n+void __netdev_free_config(struct netdev_config *cfg)\n+{\n+\tkfree(cfg);\n+}\n+\n+void netdev_free_config(struct net_device *dev)\n+{\n+\tWARN_ON(dev-\u003ecfg != dev-\u003ecfg_pending);\n+\t__netdev_free_config(dev-\u003ecfg);\n+}\n+\n+int netdev_reconfig_start(struct net_device *dev)\n+{\n+\tstruct netdev_config *cfg;\n+\n+\tWARN_ON(dev-\u003ecfg != dev-\u003ecfg_pending);\n+\tcfg = kmemdup(dev-\u003ecfg, sizeof(*dev-\u003ecfg), GFP_KERNEL_ACCOUNT);\n+\tif (!cfg)\n+\t\treturn -ENOMEM;\n+\n+\tdev-\u003ecfg_pending = cfg;\n+\treturn 0;\n+}\n+\n static int netdev_nop_validate_qcfg(struct net_device *dev,\n \t\t\t\t struct netdev_queue_config *qcfg,\n \t\t\t\t struct netlink_ext_ack *extack)\n@@ -13,6 +50,15 @@ static int netdev_nop_validate_qcfg(struct net_device *dev,\n \treturn 0;\n }\n \n+static void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg,\n+\t\t\t\t const struct netdev_config *cfg)\n+{\n+\t/* Device config overrides callback-provided fallbacks. */\n+\tqcfg-\u003erx_ring_size = cfg-\u003erings.rx_pending;\n+\tqcfg-\u003erx_mini_ring_size = cfg-\u003erings.rx_mini_pending;\n+\tqcfg-\u003erx_jumbo_ring_size = cfg-\u003erings.rx_jumbo_pending;\n+}\n+\n static int __netdev_queue_config(struct net_device *dev, int rxq_idx,\n \t\t\t\t struct netdev_queue_config *qcfg,\n \t\t\t\t struct netlink_ext_ack *extack,\n@@ -33,6 +79,7 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,\n \t/* Get defaults from the driver, in case user config not set */\n \tif (dev-\u003equeue_mgmt_ops-\u003endo_default_qcfg)\n \t\tdev-\u003equeue_mgmt_ops-\u003endo_default_qcfg(dev, qcfg);\n+\tnetdev_qcfg_apply_dev(qcfg, dev-\u003ecfg_pending);\n \terr = validate_cb(dev, qcfg, extack);\n \tif (err)\n \t\treturn err;\n@@ -54,9 +101,11 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,\n * @rxq_idx: index of the queue of interest\n * @qcfg: queue configuration struct (output)\n *\n- * Render the configuration for a given queue. This helper should be used\n- * by drivers which support queue configuration to retrieve config for\n- * a particular queue.\n+ * Render the configuration for a given queue. During a configuration\n+ * transaction this includes the proposed device-wide values in\n+ * @dev-\u003ecfg_pending; otherwise @dev-\u003ecfg_pending points to the accepted\n+ * configuration. This helper should be used by drivers which support queue\n+ * configuration to retrieve config for a particular queue.\n *\n * @qcfg is an output parameter and is always fully initialized by this\n * function. Some values may not be set by the user, drivers may either\n@@ -76,3 +125,23 @@ int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,\n {\n \treturn __netdev_queue_config(dev, rxq_idx, qcfg, extack, true);\n }\n+\n+int netdev_queue_config_revalidate(struct net_device *dev,\n+\t\t\t\t struct netlink_ext_ack *extack)\n+{\n+\tconst struct netdev_queue_mgmt_ops *qops = dev-\u003equeue_mgmt_ops;\n+\tstruct netdev_queue_config qcfg;\n+\tunsigned int i;\n+\tint err;\n+\n+\tif (!qops || !qops-\u003endo_validate_qcfg)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i \u003c dev-\u003ereal_num_rx_queues; i++) {\n+\t\terr = netdev_queue_config_validate(dev, i, \u0026qcfg, extack);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/net/ethtool/common.c b/net/ethtool/common.c\nindex 23db40618fed1..05ed22fd1f906 100644\n--- a/net/ethtool/common.c\n+++ b/net/ethtool/common.c\n@@ -956,6 +956,15 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,\n \tkparam-\u003ehds_thresh = dev-\u003ecfg-\u003ehds_thresh;\n }\n \n+void ethtool_ringparam_set_cfg(struct netdev_config *cfg,\n+\t\t\t const struct ethtool_ringparam *param)\n+{\n+\tcfg-\u003erings.rx_pending = param-\u003erx_pending;\n+\tcfg-\u003erings.rx_mini_pending = param-\u003erx_mini_pending;\n+\tcfg-\u003erings.rx_jumbo_pending = param-\u003erx_jumbo_pending;\n+\tcfg-\u003erings.tx_pending = param-\u003etx_pending;\n+}\n+\n static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)\n {\n \tmemset(info, 0, sizeof(*info));\ndiff --git a/net/ethtool/common.h b/net/ethtool/common.h\nindex 4e5356e26f400..a27944d4cbf83 100644\n--- a/net/ethtool/common.h\n+++ b/net/ethtool/common.h\n@@ -53,6 +53,8 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,\n \t\t\t struct ethtool_ringparam *param,\n \t\t\t struct kernel_ethtool_ringparam *kparam,\n \t\t\t struct netlink_ext_ack *extack);\n+void ethtool_ringparam_set_cfg(struct netdev_config *cfg,\n+\t\t\t const struct ethtool_ringparam *param);\n \n int ethtool_get_rx_ring_count(struct net_device *dev);\n \ndiff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c\nindex 4b0bc503f9307..1320289025b25 100644\n--- a/net/ethtool/ioctl.c\n+++ b/net/ethtool/ioctl.c\n@@ -35,6 +35,7 @@\n #include \u003cnet/netdev_queues.h\u003e\n \n #include \"common.h\"\n+#include \"../core/dev.h\"\n \n /* State held across locks and calls for commands which have devlink fallback */\n struct ethtool_devlink_compat {\n@@ -2239,10 +2240,29 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)\n \t ringparam.tx_pending \u003e max.tx_max_pending)\n \t\treturn -EINVAL;\n \n+\tret = netdev_reconfig_start(dev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tethtool_ringparam_set_cfg(dev-\u003ecfg_pending, \u0026ringparam);\n+\n+\tret = netdev_queue_config_revalidate(dev, NULL);\n+\tif (ret)\n+\t\tgoto out_free_cfg;\n+\n \tret = dev-\u003eethtool_ops-\u003eset_ringparam(dev, \u0026ringparam,\n \t\t\t\t\t \u0026kernel_ringparam, NULL);\n-\tif (!ret)\n-\t\tethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF);\n+\tif (ret)\n+\t\tgoto out_free_cfg;\n+\n+\t/* The driver may adjust the accepted ring depths. */\n+\tethtool_ringparam_set_cfg(dev-\u003ecfg_pending, \u0026ringparam);\n+\tswap(dev-\u003ecfg, dev-\u003ecfg_pending);\n+\tethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF);\n+\n+out_free_cfg:\n+\t__netdev_free_config(dev-\u003ecfg_pending);\n+\tdev-\u003ecfg_pending = dev-\u003ecfg;\n \treturn ret;\n }\n \ndiff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c\nindex 1af395b54330e..383e911f50f78 100644\n--- a/net/ethtool/netlink.c\n+++ b/net/ethtool/netlink.c\n@@ -11,6 +11,8 @@\n #include \"module_fw.h\"\n #include \"netlink.h\"\n \n+#include \"../core/dev.h\"\n+\n static struct genl_family ethtool_genl_family;\n \n static bool ethnl_ok __read_mostly;\n@@ -934,12 +936,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)\n \tif (need_rtnl)\n \t\trtnl_lock();\n \tnetdev_lock_ops(dev);\n-\tdev-\u003ecfg_pending = kmemdup(dev-\u003ecfg, sizeof(*dev-\u003ecfg),\n-\t\t\t\t GFP_KERNEL_ACCOUNT);\n-\tif (!dev-\u003ecfg_pending) {\n-\t\tret = -ENOMEM;\n-\t\tgoto out_tie_cfg;\n-\t}\n+\tret = netdev_reconfig_start(dev);\n+\tif (ret)\n+\t\tgoto out_unlock;\n \n \tret = ethnl_ops_begin(dev);\n \tif (ret \u003c 0)\n@@ -958,9 +957,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)\n out_ops:\n \tethnl_ops_complete(dev);\n out_free_cfg:\n-\tkfree(dev-\u003ecfg_pending);\n-out_tie_cfg:\n+\t__netdev_free_config(dev-\u003ecfg_pending);\n \tdev-\u003ecfg_pending = dev-\u003ecfg;\n+out_unlock:\n \tnetdev_unlock_ops(dev);\n \tif (need_rtnl)\n \t\trtnl_unlock();\ndiff --git a/net/ethtool/rings.c b/net/ethtool/rings.c\nindex 9054c89c5d7bb..c04312fc0d061 100644\n--- a/net/ethtool/rings.c\n+++ b/net/ethtool/rings.c\n@@ -4,6 +4,7 @@\n \n #include \"common.h\"\n #include \"netlink.h\"\n+#include \"../core/dev.h\"\n \n struct rings_req_info {\n \tstruct ethnl_req_info\t\tbase;\n@@ -299,10 +300,20 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)\n \n \tdev-\u003ecfg_pending-\u003ehds_config = kernel_ringparam.tcp_data_split;\n \tdev-\u003ecfg_pending-\u003ehds_thresh = kernel_ringparam.hds_thresh;\n+\tethtool_ringparam_set_cfg(dev-\u003ecfg_pending, \u0026ringparam);\n+\n+\tret = netdev_queue_config_revalidate(dev, info-\u003eextack);\n+\tif (ret)\n+\t\treturn ret;\n \n \tret = dev-\u003eethtool_ops-\u003eset_ringparam(dev, \u0026ringparam,\n \t\t\t\t\t \u0026kernel_ringparam, info-\u003eextack);\n-\treturn ret \u003c 0 ? ret : 1;\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\t/* The driver may adjust the accepted ring depths. */\n+\tethtool_ringparam_set_cfg(dev-\u003ecfg_pending, \u0026ringparam);\n+\treturn 1;\n }\n \n const struct ethnl_request_ops ethnl_rings_request_ops = {\ndiff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c\nindex f6a8fc5fac241..c0d9065b21030 100644\n--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c\n+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c\n@@ -84,6 +84,9 @@ static int cfg_oneshot_recvs;\n static int cfg_send_size = SEND_SIZE;\n static struct sockaddr_in6 cfg_addr;\n static unsigned int cfg_rx_buf_len;\n+static unsigned int cfg_min_data_end;\n+static bool cfg_check_data_end;\n+static bool seen_data_end;\n static bool cfg_dry_run;\n \n static char *payload;\n@@ -298,6 +301,15 @@ static void process_recvzc(struct io_uring *ring, struct io_uring_cqe *cqe)\n \tmask = (1ULL \u003c\u003c IORING_ZCRX_AREA_SHIFT) - 1;\n \tdata = (char *)area_ptr + (rcqe-\u003eoff \u0026 mask);\n \n+\tif (cfg_check_data_end) {\n+\t\tunsigned int rx_buf_len = cfg_rx_buf_len ?: page_size;\n+\t\tunsigned int data_end_off;\n+\n+\t\tdata_end_off = (rcqe-\u003eoff \u0026 mask) % rx_buf_len + n;\n+\t\tif (data_end_off \u003e cfg_min_data_end)\n+\t\t\tseen_data_end = true;\n+\t}\n+\n \tfor (i = 0; i \u003c n; i++) {\n \t\tif (*(data + i) != payload[(received + i)])\n \t\t\terror(1, 0, \"payload mismatch at %d\", i);\n@@ -373,7 +385,10 @@ static void run_server(void)\n \t\tserver_loop(\u0026ring);\n \n \tif (!stop)\n-\t\terror(1, 0, \"test failed\\n\");\n+\t\terror(1, 0, \"test failed after receiving %zu bytes\", received);\n+\tif (cfg_check_data_end \u0026\u0026 !seen_data_end)\n+\t\terror(1, 0, \"no payload CQE ending past offset %u\",\n+\t\t cfg_min_data_end);\n }\n \n static void run_client(void)\n@@ -406,8 +421,11 @@ static void run_client(void)\n \n static void usage(const char *filepath)\n {\n-\terror(1, 0, \"Usage: %s (-4|-6) (-s|-c) -h\u003cserver_ip\u003e -p\u003cport\u003e \"\n-\t\t \"-l\u003cpayload_size\u003e -i\u003cifname\u003e -q\u003crxq_id\u003e\", filepath);\n+\terror(1, 0,\n+\t \"Usage: %s (-4|-6) (-s|-c) -h\u003cserver_ip\u003e -p\u003cport\u003e\\n\"\n+\t \"\\t-l\u003cpayload_size\u003e -i\u003cifname\u003e -q\u003crxq_id\u003e\\n\"\n+\t \"\\t[-x\u003crx_buf_pages\u003e] [-E\u003cmin_data_end\u003e] [-d]\\n\",\n+\t filepath);\n }\n \n static void parse_opts(int argc, char **argv)\n@@ -425,7 +443,7 @@ static void parse_opts(int argc, char **argv)\n \t\tusage(argv[0]);\n \tcfg_payload_len = max_payload_len;\n \n-\twhile ((c = getopt(argc, argv, \"sch:p:l:i:q:o:z:x:d\")) != -1) {\n+\twhile ((c = getopt(argc, argv, \"sch:p:l:i:q:o:z:x:E:d\")) != -1) {\n \t\tswitch (c) {\n \t\tcase 's':\n \t\t\tif (cfg_client)\n@@ -463,6 +481,10 @@ static void parse_opts(int argc, char **argv)\n \t\tcase 'x':\n \t\t\tcfg_rx_buf_len = page_size * strtoul(optarg, NULL, 0);\n \t\t\tbreak;\n+\t\tcase 'E':\n+\t\t\tcfg_check_data_end = true;\n+\t\t\tcfg_min_data_end = strtoul(optarg, NULL, 0);\n+\t\t\tbreak;\n \t\tcase 'd':\n \t\t\tcfg_dry_run = true;\n \t\t\tbreak;\n@@ -484,6 +506,9 @@ static void parse_opts(int argc, char **argv)\n \n \tif (cfg_payload_len \u003e max_payload_len)\n \t\terror(1, 0, \"-l: payload exceeds max (%d)\", max_payload_len);\n+\tif (cfg_check_data_end \u0026\u0026\n+\t cfg_min_data_end \u003e= (cfg_rx_buf_len ?: page_size))\n+\t\terror(1, 0, \"-E: offset outside rx_buf_len\");\n }\n \n int main(int argc, char **argv)\ndiff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py\nindex b7a225fe4beae..a9f62c6b950bb 100755\n--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py\n+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py\n@@ -175,9 +175,13 @@ def test_zcrx_large_chunks(cfg) -\u003e None:\n \n single(cfg)\n page_size = resource.getpagesize()\n+ mtu = cfg.dev[\"mtu\"]\n nr_pages = 2\n+ while nr_pages * page_size \u003c= 2 * mtu:\n+ nr_pages *= 2\n rx_buf_len = nr_pages * page_size\n- rx_cmd = f\"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.target} -x {nr_pages}\"\n+ rx_cmd = (f\"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} \"\n+ f\"-q {cfg.target} -x {nr_pages} -E {mtu}\")\n tx_cmd = f\"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 12840\"\n \n probe = cmd(rx_cmd + \" -d\", fail=False)\n"
} |
| 2/1 | 2026/09/10 19:37 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": [
"NET",
"ETHTOOL_NETLINK"
],
"FocusSymbols": [
"netdev_reconfig_start",
"netdev_queue_config_revalidate",
"netdev_alloc_config",
"netdev_free_config",
"ethtool_ringparam_set_cfg",
"ethtool_set_ringparam",
"ethnl_set_rings"
],
"Reasoning": "The patch series modifies core networking configuration logic (net/core/dev.c, net/core/netdev_config.c) and ethtool ring parameter interfaces (net/ethtool/ioctl.c, net/ethtool/rings.c, net/ethtool/common.c) in addition to the fbnic driver. It refactors ring and queue configuration lifecycle management, adds transaction-based configuration validation helpers (netdev_reconfig_start, netdev_queue_config_revalidate), and includes state assertions (WARN_ON). These code paths are directly reachable from userspace via SIOCETHTOOL ioctl commands and Ethtool generic Netlink messages on any netdevice, making them worth fuzzing.",
"WorthFuzzing": true
}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 99bc766fcd57eaf682f9ea8903f89d67ab31862b
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Sep 10 19:37:00 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
index 64b958df77744..2b9f8644b132d 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
@@ -109,34 +109,19 @@ enum {
/* Rx Buffer Descriptor Format
*
- * The layout of this can vary depending on the page size of the system.
+ * Buffer descriptors describe 4 KiB device pages. A posted page larger than
+ * 4 KiB is represented by consecutive device-page descriptors.
*
- * If the page size is 4K then the layout will simply consist of ID for
- * the 16 most significant bits, and the lower 46 are essentially the page
- * address with the lowest 12 bits being reserved 0 due to the fact that
- * a page will be aligned.
- *
- * If the page size is larger than 4K then the lower n bits of the ID and
- * page address will be reserved for the fragment ID. This fragment will
- * be 4K in size and will be used to index both the DMA address and the ID
- * by the same amount.
+ * The address field stores the 4 KiB-aligned DMA address. The ID field stores
+ * the software page ID, with the low n bits used as the device-page ID when a
+ * posted page spans multiple device pages. The driver increments both the
+ * address and ID by one device page for each descriptor belonging to a posted
+ * page.
*/
#define FBNIC_BD_DESC_ADDR_MASK DESC_GENMASK(45, 12)
#define FBNIC_BD_DESC_ID_MASK DESC_GENMASK(63, 48)
-#define FBNIC_BD_FRAG_SIZE \
+#define FBNIC_BD_PAGE_SIZE \
(FBNIC_BD_DESC_ADDR_MASK & ~(FBNIC_BD_DESC_ADDR_MASK - 1))
-#define FBNIC_BD_FRAG_COUNT \
- (PAGE_SIZE / FBNIC_BD_FRAG_SIZE)
-#define FBNIC_BD_FRAG_ADDR_MASK \
- (FBNIC_BD_DESC_ADDR_MASK & \
- ~(FBNIC_BD_DESC_ADDR_MASK * FBNIC_BD_FRAG_COUNT))
-#define FBNIC_BD_FRAG_ID_MASK \
- (FBNIC_BD_DESC_ID_MASK & \
- ~(FBNIC_BD_DESC_ID_MASK * FBNIC_BD_FRAG_COUNT))
-#define FBNIC_BD_PAGE_ADDR_MASK \
- (FBNIC_BD_DESC_ADDR_MASK & ~FBNIC_BD_FRAG_ADDR_MASK)
-#define FBNIC_BD_PAGE_ID_MASK \
- (FBNIC_BD_DESC_ID_MASK & ~FBNIC_BD_FRAG_ID_MASK)
/* Rx Completion Queue Descriptors */
#define FBNIC_RCD_TYPE_MASK DESC_GENMASK(62, 61)
@@ -151,9 +136,6 @@ enum {
/* Address/Length Completion Descriptors */
#define FBNIC_RCD_AL_BUFF_ID_MASK DESC_GENMASK(15, 0)
-#define FBNIC_RCD_AL_BUFF_FRAG_MASK (FBNIC_BD_FRAG_COUNT - 1)
-#define FBNIC_RCD_AL_BUFF_PAGE_MASK \
- (FBNIC_RCD_AL_BUFF_ID_MASK & ~FBNIC_RCD_AL_BUFF_FRAG_MASK)
#define FBNIC_RCD_AL_BUFF_LEN_MASK DESC_GENMASK(28, 16)
#define FBNIC_RCD_AL_BUFF_OFF_MASK DESC_GENMASK(43, 32)
#define FBNIC_RCD_AL_PAGE_FIN DESC_BIT(60)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
index 3c4563c8f403f..7f23a0f97e637 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
@@ -181,8 +181,8 @@ static int fbnic_dbg_tcq_desc_seq_show(struct seq_file *s, void *v)
static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)
{
struct fbnic_ring *ring = s->private;
+ unsigned int i, desc_count;
char hdr[80];
- int i;
/* Generate header on first entry */
fbnic_dbg_ring_show(s);
@@ -197,7 +197,8 @@ static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)
return 0;
}
- for (i = 0; i < (ring->size_mask + 1) * FBNIC_BD_FRAG_COUNT; i++) {
+ desc_count = (ring->size_mask + 1) * fbnic_bd_page_count(ring);
+ for (i = 0; i < desc_count; i++) {
u64 bd = le64_to_cpu(ring->desc[i]);
seq_printf(s, "%04x %#04llx %#014llx\n", i,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index 0e47088ec44ba..2def4c26207d1 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -334,10 +334,10 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
struct fbnic_net *clone;
int err;
- ring->rx_pending = roundup_pow_of_two(ring->rx_pending);
- ring->rx_mini_pending = roundup_pow_of_two(ring->rx_mini_pending);
- ring->rx_jumbo_pending = roundup_pow_of_two(ring->rx_jumbo_pending);
- ring->tx_pending = roundup_pow_of_two(ring->tx_pending);
+ ring->rx_pending = fbnic_ring_size_pow2(ring->rx_pending);
+ ring->rx_mini_pending = fbnic_ring_size_pow2(ring->rx_mini_pending);
+ ring->rx_jumbo_pending = fbnic_ring_size_pow2(ring->rx_jumbo_pending);
+ ring->tx_pending = fbnic_ring_size_pow2(ring->tx_pending);
/* These are absolute minimums allowing the device and driver to operate
* but not necessarily guarantee reasonable performance. Settings below
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index 10bf99be3f244..8bc5e6e5c59e8 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -773,6 +773,11 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
fbn->ppq_size = FBNIC_PPQ_SIZE_DEFAULT;
fbn->rcq_size = FBNIC_RCQ_SIZE_DEFAULT;
+ netdev->cfg->rings.rx_pending = fbn->rcq_size;
+ netdev->cfg->rings.rx_mini_pending = fbn->hpq_size;
+ netdev->cfg->rings.rx_jumbo_pending = fbn->ppq_size;
+ netdev->cfg->rings.tx_pending = fbn->txq_size;
+
fbn->tx_usecs = FBNIC_TX_USECS_DEFAULT;
fbn->rx_usecs = FBNIC_RX_USECS_DEFAULT;
fbn->rx_max_frames = FBNIC_RX_FRAMES_DEFAULT;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
index 401f8b8ae1cae..5e22905a63739 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
@@ -871,19 +871,31 @@ static void fbnic_clean_bdq(struct fbnic_ring *ring, unsigned int hw_head,
ring->head = head;
}
+static u16 fbnic_rcd_bd_idx(const struct fbnic_ring *bdq, u64 rcd)
+{
+ return FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd) >> bdq->bd_page_shift;
+}
+
+static unsigned int fbnic_rcd_bd_page_offset(const struct fbnic_ring *bdq,
+ u64 rcd)
+{
+ u16 id = FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd);
+ u16 page_id = id & (fbnic_bd_page_count(bdq) - 1);
+
+ return page_id * FBNIC_BD_PAGE_SIZE;
+}
+
static void fbnic_bd_prep(struct fbnic_ring *bdq, u16 id, netmem_ref netmem)
{
- __le64 *bdq_desc = &bdq->desc[id * FBNIC_BD_FRAG_COUNT];
+ __le64 *bdq_desc = &bdq->desc[id * fbnic_bd_page_count(bdq)];
dma_addr_t dma = page_pool_get_dma_addr_netmem(netmem);
- u64 bd, i = FBNIC_BD_FRAG_COUNT;
+ u64 bd, i = fbnic_bd_page_count(bdq);
- bd = (FBNIC_BD_PAGE_ADDR_MASK & dma) |
- FIELD_PREP(FBNIC_BD_PAGE_ID_MASK, id);
+ bd = (FBNIC_BD_DESC_ADDR_MASK & dma) |
+ FIELD_PREP(FBNIC_BD_DESC_ID_MASK, (u64)id << bdq->bd_page_shift);
- /* In the case that a page size is larger than 4K we will map a
- * single page to multiple fragments. The fragments will be
- * FBNIC_BD_FRAG_COUNT in size and the lower n bits will be use
- * to indicate the individual fragment IDs.
+ /* Posted pages larger than 4 KiB use consecutive device-page IDs in
+ * the low bits of the software page ID.
*/
do {
*bdq_desc = cpu_to_le64(bd);
@@ -928,7 +940,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq)
/* Force DMA writes to flush before writing to tail */
dma_wmb();
- writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell);
+ writel(i * fbnic_bd_page_count(bdq), bdq->doorbell);
}
}
@@ -959,26 +971,27 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd,
struct fbnic_pkt_buff *pkt,
struct fbnic_q_triad *qt)
{
- unsigned int hdr_pg_idx = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
unsigned int hdr_pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd);
- struct page *page = fbnic_page_pool_get_head(qt, hdr_pg_idx);
unsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd);
+ unsigned int hdr_pg_idx = fbnic_rcd_bd_idx(&qt->sub0, rcd);
unsigned int frame_sz, hdr_pg_start, hdr_pg_end, headroom;
unsigned char *hdr_start;
+ struct page *page;
/* data_hard_start should always be NULL when this is called */
WARN_ON_ONCE(pkt->buff.data_hard_start);
+ page = fbnic_page_pool_get_head(qt, hdr_pg_idx);
+
/* Short-cut the end calculation if we know page is fully consumed */
hdr_pg_end = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ?
- FBNIC_BD_FRAG_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len);
+ FBNIC_BD_PAGE_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len);
hdr_pg_start = fbnic_hdr_pg_start(hdr_pg_off);
headroom = hdr_pg_off - hdr_pg_start + FBNIC_RX_PAD;
frame_sz = hdr_pg_end - hdr_pg_start;
xdp_init_buff(&pkt->buff, frame_sz, &qt->xdp_rxq);
- hdr_pg_start += (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) *
- FBNIC_BD_FRAG_SIZE;
+ hdr_pg_start += fbnic_rcd_bd_page_offset(&qt->sub0, rcd);
/* Sync DMA buffer */
dma_sync_single_range_for_cpu(nv->dev, page_pool_get_dma_addr(page),
@@ -999,23 +1012,28 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vector *nv, u64 rcd,
struct fbnic_pkt_buff *pkt,
struct fbnic_q_triad *qt)
{
- unsigned int pg_idx = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
unsigned int pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd);
unsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd);
- netmem_ref netmem = fbnic_page_pool_get_data(qt, pg_idx);
+ unsigned int pg_idx = fbnic_rcd_bd_idx(&qt->sub1, rcd);
unsigned int truesize;
+ netmem_ref netmem;
bool added;
+ netmem = fbnic_page_pool_get_data(qt, pg_idx);
+
truesize = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ?
- FBNIC_BD_FRAG_SIZE - pg_off : ALIGN(len, 128);
+ FBNIC_BD_PAGE_SIZE - pg_off :
+ ALIGN(len, FBNIC_RX_PAYLD_ALIGN);
- pg_off += (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) *
- FBNIC_BD_FRAG_SIZE;
+ pg_off += fbnic_rcd_bd_page_offset(&qt->sub1, rcd);
/* Sync DMA buffer */
page_pool_dma_sync_netmem_for_cpu(qt->sub1.page_pool, netmem,
pg_off, truesize);
+ /* Consecutive device-page completions from one PPQ page are adjacent
+ * ranges in the same netmem.
+ */
added = xdp_buff_add_frag(&pkt->buff, netmem, pg_off, len, truesize);
if (unlikely(!added)) {
pkt->add_frag_failed = true;
@@ -1257,12 +1275,12 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv,
switch (FIELD_GET(FBNIC_RCD_TYPE_MASK, rcd)) {
case FBNIC_RCD_TYPE_HDR_AL:
- head0 = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
+ head0 = fbnic_rcd_bd_idx(&qt->sub0, rcd);
fbnic_pkt_prepare(nv, rcd, pkt, qt);
break;
case FBNIC_RCD_TYPE_PAY_AL:
- head1 = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
+ head1 = fbnic_rcd_bd_idx(&qt->sub1, rcd);
fbnic_add_rx_frag(nv, rcd, pkt, qt);
break;
@@ -1550,7 +1568,7 @@ void fbnic_free_napi_vectors(struct fbnic_net *fbn)
static int
fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
- unsigned int rxq_idx)
+ unsigned int rxq_idx, u32 rx_page_size)
{
struct page_pool_params pp_params = {
.order = 0,
@@ -1585,6 +1603,8 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
qt->sub0.page_pool = pp;
if (netif_rxq_has_unreadable_mp(fbn->netdev, rxq_idx)) {
+ pp_params.order = get_order(rx_page_size);
+ pp_params.max_len = rx_page_size;
pp_params.flags |= PP_FLAG_ALLOW_UNREADABLE_NETMEM;
pp_params.dma_dir = DMA_FROM_DEVICE;
@@ -1603,6 +1623,16 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
return PTR_ERR(pp);
}
+static u8 fbnic_bdq_page_shift(u32 page_size)
+{
+ return ilog2(page_size / FBNIC_BD_PAGE_SIZE);
+}
+
+static void fbnic_bdq_set_page_size(struct fbnic_ring *bdq, u32 page_size)
+{
+ bdq->bd_page_shift = fbnic_bdq_page_shift(page_size);
+}
+
static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell,
int q_idx, u8 flags)
{
@@ -1610,6 +1640,7 @@ static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell,
ring->doorbell = doorbell;
ring->q_idx = q_idx;
ring->flags = flags;
+ fbnic_bdq_set_page_size(ring, PAGE_SIZE);
ring->deferred_head = -1;
}
@@ -1894,12 +1925,12 @@ static int fbnic_alloc_rx_ring_desc(struct fbnic_net *fbn,
switch (rxr->doorbell - fbnic_ring_csr_base(rxr)) {
case FBNIC_QUEUE_BDQ_HPQ_TAIL:
- rxq_size = fbn->hpq_size / FBNIC_BD_FRAG_COUNT;
- desc_size *= FBNIC_BD_FRAG_COUNT;
+ rxq_size = fbn->hpq_size / fbnic_bd_page_count(rxr);
+ desc_size *= fbnic_bd_page_count(rxr);
break;
case FBNIC_QUEUE_BDQ_PPQ_TAIL:
- rxq_size = fbn->ppq_size / FBNIC_BD_FRAG_COUNT;
- desc_size *= FBNIC_BD_FRAG_COUNT;
+ rxq_size = fbn->ppq_size / fbnic_bd_page_count(rxr);
+ desc_size *= fbnic_bd_page_count(rxr);
break;
case FBNIC_QUEUE_RCQ_HEAD:
rxq_size = fbn->rcq_size;
@@ -2003,15 +2034,18 @@ static int fbnic_alloc_tx_qt_resources(struct fbnic_net *fbn,
static int fbnic_alloc_rx_qt_resources(struct fbnic_net *fbn,
struct fbnic_napi_vector *nv,
- struct fbnic_q_triad *qt)
+ struct fbnic_q_triad *qt,
+ u32 rx_page_size)
{
struct device *dev = fbn->netdev->dev.parent;
int err;
- err = fbnic_alloc_qt_page_pools(fbn, qt, qt->cmpl.q_idx);
+ err = fbnic_alloc_qt_page_pools(fbn, qt, qt->cmpl.q_idx, rx_page_size);
if (err)
return err;
+ fbnic_bdq_set_page_size(&qt->sub1, rx_page_size);
+
err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->sub0.q_idx,
nv->napi.napi_id);
if (err)
@@ -2072,7 +2106,11 @@ static int fbnic_alloc_nv_resources(struct fbnic_net *fbn,
/* Allocate Rx Resources */
for (j = 0; j < nv->rxt_count; j++, i++) {
- err = fbnic_alloc_rx_qt_resources(fbn, nv, &nv->qt[i]);
+ struct netdev_queue_config qcfg;
+
+ netdev_queue_config(fbn->netdev, nv->qt[i].cmpl.q_idx, &qcfg);
+ err = fbnic_alloc_rx_qt_resources(fbn, nv, &nv->qt[i],
+ qcfg.rx_page_size);
if (err)
goto free_qt_resources;
}
@@ -2565,7 +2603,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
hpq->tail = 0;
hpq->head = 0;
- log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+ log_size = fls(hpq->size_mask) + hpq->bd_page_shift;
/* Store descriptor ring address and size */
fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma));
@@ -2577,7 +2615,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
if (!ppq->size_mask)
goto write_ctl;
- log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+ log_size = fls(ppq->size_mask) + ppq->bd_page_shift;
/* Add enabling of PPQ to BDQ control */
bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;
@@ -2839,7 +2877,8 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,
struct fbnic_napi_vector *nv;
if (!netif_running(dev))
- return fbnic_alloc_qt_page_pools(fbn, qt, idx);
+ return fbnic_alloc_qt_page_pools(fbn, qt, idx,
+ qcfg->rx_page_size);
real = container_of(fbn->rx[idx], struct fbnic_q_triad, cmpl);
nv = fbn->napi[idx % fbn->num_napi];
@@ -2851,7 +2890,62 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,
fbnic_ring_init(&qt->cmpl, real->cmpl.doorbell, real->cmpl.q_idx,
real->cmpl.flags);
- return fbnic_alloc_rx_qt_resources(fbn, nv, qt);
+ return fbnic_alloc_rx_qt_resources(fbn, nv, qt, qcfg->rx_page_size);
+}
+
+static void fbnic_default_qcfg(struct net_device *dev,
+ struct netdev_queue_config *qcfg)
+{
+ qcfg->rx_page_size = PAGE_SIZE;
+}
+
+static int fbnic_validate_qcfg(struct net_device *dev,
+ struct netdev_queue_config *qcfg,
+ struct netlink_ext_ack *extack)
+{
+ u32 ppq_size = fbnic_ring_size_pow2(qcfg->rx_jumbo_ring_size);
+ u32 bd_page_count, ppq_entries, frag_count;
+ u32 rx_page_size = qcfg->rx_page_size;
+
+ if (!is_power_of_2(rx_page_size)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx_page_size must be a power of 2");
+ return -EINVAL;
+ }
+
+ if (rx_page_size < FBNIC_BD_PAGE_SIZE) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx_page_size must be at least 4K");
+ return -EINVAL;
+ }
+
+ /* Payload fragments occupy multiples of FBNIC_RX_PAYLD_ALIGN bytes.
+ * Keep at least one reference in the bias until fbnic_clean_bdq()
+ * observes a completion from a subsequent allocation.
+ */
+ frag_count = rx_page_size / FBNIC_RX_PAYLD_ALIGN;
+ if (frag_count >= FBNIC_PAGECNT_BIAS_MAX) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx_page_size can produce too many fragments");
+ return -EINVAL;
+ }
+
+ bd_page_count = rx_page_size / FBNIC_BD_PAGE_SIZE;
+ ppq_entries = ppq_size / bd_page_count;
+ /* The PPQ is sized in 4 KiB device pages. One software entry tracks
+ * each page-pool allocation. In addition to the unused entry for
+ * empty/full accounting, cleanup retains the current allocation
+ * until a completion identifies a subsequent allocation. A two-entry
+ * ring can only post one allocation and cannot make progress.
+ * Require at least four entries, since ring sizes are powers of two.
+ */
+ if (ppq_entries < 4) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx-jumbo ring size too small for rx_page_size");
+ return -EINVAL;
+ }
+
+ return 0;
}
static void fbnic_queue_mem_free(struct net_device *dev, void *qmem)
@@ -2953,4 +3047,7 @@ const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops = {
.ndo_queue_mem_free = fbnic_queue_mem_free,
.ndo_queue_start = fbnic_queue_start,
.ndo_queue_stop = fbnic_queue_stop,
+ .ndo_default_qcfg = fbnic_default_qcfg,
+ .ndo_validate_qcfg = fbnic_validate_qcfg,
+ .supported_params = QCFG_RX_PAGE_SIZE,
};
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
index e03c9d2c38dca..12b3a684f4611 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
@@ -49,12 +49,18 @@ struct fbnic_net;
#define FBNIC_RX_USECS_DEFAULT 30
#define FBNIC_RX_FRAMES_DEFAULT 0
+static inline u32 fbnic_ring_size_pow2(u32 size)
+{
+ return size ? roundup_pow_of_two(size) : 0;
+}
+
#define FBNIC_RX_TROOM \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
#define FBNIC_RX_HROOM_PAD 128
#define FBNIC_RX_HROOM \
(ALIGN(FBNIC_RX_TROOM + FBNIC_RX_HROOM_PAD, 128) - FBNIC_RX_TROOM)
#define FBNIC_RX_PAD 0
+#define FBNIC_RX_PAYLD_ALIGN 128
#define FBNIC_RX_PAYLD_OFFSET 0
#define FBNIC_RX_PAYLD_PG_CL 0
@@ -121,6 +127,7 @@ struct fbnic_ring {
u16 size_mask; /* Size of ring in descriptors - 1 */
u8 q_idx; /* Logical netdev ring index */
u8 flags; /* Ring flags (FBNIC_RING_F_*) */
+ u8 bd_page_shift; /* BDQ: ilog2(page_size / 4096) */
u32 head, tail; /* Head/Tail of ring */
@@ -162,6 +169,11 @@ struct fbnic_napi_vector {
extern const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops;
+static inline u16 fbnic_bd_page_count(const struct fbnic_ring *bdq)
+{
+ return 1U << bdq->bd_page_shift;
+}
+
netdev_tx_t fbnic_xmit_frame(struct sk_buff *skb, struct net_device *dev);
netdev_features_t
fbnic_features_check(struct sk_buff *skb, struct net_device *dev,
diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
index 70c9fe9e83cc4..31121900aac88 100644
--- a/include/net/netdev_queues.h
+++ b/include/net/netdev_queues.h
@@ -4,18 +4,59 @@
#include <linux/netdevice.h>
+/**
+ * struct netdev_ring_config - accepted RX/TX ring depth configuration
+ * @rx_pending: Size of the regular RX ring.
+ * @rx_mini_pending: Size of the RX mini ring.
+ * @rx_jumbo_pending: Size of the RX jumbo ring.
+ * @tx_pending: Size of the TX ring.
+ *
+ * This stores only persistent configuration values. Capability fields,
+ * such as max ring sizes, are reported by drivers but are not part of the
+ * accepted configuration.
+ *
+ * Note: these values are only used for queue-configuration validation
+ * today. Some drivers update their ring sizes without reflecting the change
+ * in @cfg. Before using the stored values for anything else, those cases
+ * need to be audited, and the core likely needs a driver notification API
+ * similar to ethtool_rxfh_context_lost().
+ */
+struct netdev_ring_config {
+ u32 rx_pending;
+ u32 rx_mini_pending;
+ u32 rx_jumbo_pending;
+ u32 tx_pending;
+};
+
/**
* struct netdev_config - queue-related configuration for a netdev
* @hds_thresh: HDS Threshold value.
* @hds_config: HDS value from userspace.
+ * @rings: Accepted RX/TX ring depths.
+ *
+ * Direct values, such as @hds_thresh and @rings, hold the current
+ * accepted configuration. Drivers which use them for queue rendering
+ * must initialize them with their defaults.
*/
struct netdev_config {
u32 hds_thresh;
u8 hds_config;
+
+ struct netdev_ring_config rings;
};
+/**
+ * struct netdev_queue_config - rendered configuration for an RX queue
+ * @rx_page_size: Size of one RX page-pool allocation.
+ * @rx_ring_size: Effective size of the regular RX ring.
+ * @rx_mini_ring_size: Effective size of the RX mini ring.
+ * @rx_jumbo_ring_size: Effective size of the RX jumbo ring.
+ */
struct netdev_queue_config {
u32 rx_page_size;
+ u32 rx_ring_size;
+ u32 rx_mini_ring_size;
+ u32 rx_jumbo_ring_size;
};
/* See the netdev.yaml spec for definition of each statistic */
@@ -145,10 +186,9 @@ enum {
*
* @ndo_validate_qcfg: (Optional) Check if queue config is supported.
* Called when configuration affecting a queue may be
- * changing, either due to NIC-wide config, or config
- * scoped to the queue at a specified index.
- * When NIC-wide config is changed the callback will
- * be invoked for all queues.
+ * changing. When NIC-wide config is changed the
+ * callback will be invoked for the defaults and all
+ * queue overrides.
*
* @ndo_queue_create: Create a new RX queue on a virtual device that will
* be paired with a physical device's queue via leasing.
diff --git a/net/core/dev.c b/net/core/dev.c
index 290e0f099e6bf..4a7c5a5e48e52 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12195,10 +12195,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
if (!dev->ethtool)
goto free_all;
- dev->cfg = kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT);
- if (!dev->cfg)
+ if (netdev_alloc_config(dev))
goto free_all;
- dev->cfg_pending = dev->cfg;
dev->num_napi_configs = maxqs;
napi_config_sz = array_size(maxqs, sizeof(*dev->napi_config));
@@ -12270,8 +12268,7 @@ void free_netdev(struct net_device *dev)
return;
}
- WARN_ON(dev->cfg != dev->cfg_pending);
- kfree(dev->cfg);
+ netdev_free_config(dev);
kfree(dev->ethtool);
netif_free_tx_queues(dev);
netif_free_rx_queues(dev);
diff --git a/net/core/dev.h b/net/core/dev.h
index b757faead4d1a..567e7b82ef24b 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -102,9 +102,16 @@ extern struct rw_semaphore dev_addr_sem;
extern struct list_head net_todo_list;
void netdev_run_todo(void);
+int netdev_alloc_config(struct net_device *dev);
+void __netdev_free_config(struct netdev_config *cfg);
+void netdev_free_config(struct net_device *dev);
+int netdev_reconfig_start(struct net_device *dev);
+
int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack);
+int netdev_queue_config_revalidate(struct net_device *dev,
+ struct netlink_ext_ack *extack);
bool netif_rxq_has_mp(struct net_device *dev, unsigned int rxq_idx);
bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx);
diff --git a/net/core/netdev_config.c b/net/core/netdev_config.c
index f14af365d5cd7..1975de42a60d9 100644
--- a/net/core/netdev_config.c
+++ b/net/core/netdev_config.c
@@ -6,6 +6,43 @@
#include "dev.h"
+int netdev_alloc_config(struct net_device *dev)
+{
+ struct netdev_config *cfg;
+
+ cfg = kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT);
+ if (!cfg)
+ return -ENOMEM;
+
+ dev->cfg = cfg;
+ dev->cfg_pending = cfg;
+ return 0;
+}
+
+void __netdev_free_config(struct netdev_config *cfg)
+{
+ kfree(cfg);
+}
+
+void netdev_free_config(struct net_device *dev)
+{
+ WARN_ON(dev->cfg != dev->cfg_pending);
+ __netdev_free_config(dev->cfg);
+}
+
+int netdev_reconfig_start(struct net_device *dev)
+{
+ struct netdev_config *cfg;
+
+ WARN_ON(dev->cfg != dev->cfg_pending);
+ cfg = kmemdup(dev->cfg, sizeof(*dev->cfg), GFP_KERNEL_ACCOUNT);
+ if (!cfg)
+ return -ENOMEM;
+
+ dev->cfg_pending = cfg;
+ return 0;
+}
+
static int netdev_nop_validate_qcfg(struct net_device *dev,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack)
@@ -13,6 +50,15 @@ static int netdev_nop_validate_qcfg(struct net_device *dev,
return 0;
}
+static void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg,
+ const struct netdev_config *cfg)
+{
+ /* Device config overrides callback-provided fallbacks. */
+ qcfg->rx_ring_size = cfg->rings.rx_pending;
+ qcfg->rx_mini_ring_size = cfg->rings.rx_mini_pending;
+ qcfg->rx_jumbo_ring_size = cfg->rings.rx_jumbo_pending;
+}
+
static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack,
@@ -33,6 +79,7 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
/* Get defaults from the driver, in case user config not set */
if (dev->queue_mgmt_ops->ndo_default_qcfg)
dev->queue_mgmt_ops->ndo_default_qcfg(dev, qcfg);
+ netdev_qcfg_apply_dev(qcfg, dev->cfg_pending);
err = validate_cb(dev, qcfg, extack);
if (err)
return err;
@@ -54,9 +101,11 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
* @rxq_idx: index of the queue of interest
* @qcfg: queue configuration struct (output)
*
- * Render the configuration for a given queue. This helper should be used
- * by drivers which support queue configuration to retrieve config for
- * a particular queue.
+ * Render the configuration for a given queue. During a configuration
+ * transaction this includes the proposed device-wide values in
+ * @dev->cfg_pending; otherwise @dev->cfg_pending points to the accepted
+ * configuration. This helper should be used by drivers which support queue
+ * configuration to retrieve config for a particular queue.
*
* @qcfg is an output parameter and is always fully initialized by this
* function. Some values may not be set by the user, drivers may either
@@ -76,3 +125,23 @@ int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,
{
return __netdev_queue_config(dev, rxq_idx, qcfg, extack, true);
}
+
+int netdev_queue_config_revalidate(struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops;
+ struct netdev_queue_config qcfg;
+ unsigned int i;
+ int err;
+
+ if (!qops || !qops->ndo_validate_qcfg)
+ return 0;
+
+ for (i = 0; i < dev->real_num_rx_queues; i++) {
+ err = netdev_queue_config_validate(dev, i, &qcfg, extack);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 23db40618fed1..05ed22fd1f906 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -956,6 +956,15 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,
kparam->hds_thresh = dev->cfg->hds_thresh;
}
+void ethtool_ringparam_set_cfg(struct netdev_config *cfg,
+ const struct ethtool_ringparam *param)
+{
+ cfg->rings.rx_pending = param->rx_pending;
+ cfg->rings.rx_mini_pending = param->rx_mini_pending;
+ cfg->rings.rx_jumbo_pending = param->rx_jumbo_pending;
+ cfg->rings.tx_pending = param->tx_pending;
+}
+
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
{
memset(info, 0, sizeof(*info));
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 4e5356e26f400..a27944d4cbf83 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -53,6 +53,8 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,
struct ethtool_ringparam *param,
struct kernel_ethtool_ringparam *kparam,
struct netlink_ext_ack *extack);
+void ethtool_ringparam_set_cfg(struct netdev_config *cfg,
+ const struct ethtool_ringparam *param);
int ethtool_get_rx_ring_count(struct net_device *dev);
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 4b0bc503f9307..1320289025b25 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -35,6 +35,7 @@
#include <net/netdev_queues.h>
#include "common.h"
+#include "../core/dev.h"
/* State held across locks and calls for commands which have devlink fallback */
struct ethtool_devlink_compat {
@@ -2239,10 +2240,29 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
ringparam.tx_pending > max.tx_max_pending)
return -EINVAL;
+ ret = netdev_reconfig_start(dev);
+ if (ret)
+ return ret;
+
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+
+ ret = netdev_queue_config_revalidate(dev, NULL);
+ if (ret)
+ goto out_free_cfg;
+
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
&kernel_ringparam, NULL);
- if (!ret)
- ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF);
+ if (ret)
+ goto out_free_cfg;
+
+ /* The driver may adjust the accepted ring depths. */
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+ swap(dev->cfg, dev->cfg_pending);
+ ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF);
+
+out_free_cfg:
+ __netdev_free_config(dev->cfg_pending);
+ dev->cfg_pending = dev->cfg;
return ret;
}
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1af395b54330e..383e911f50f78 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -11,6 +11,8 @@
#include "module_fw.h"
#include "netlink.h"
+#include "../core/dev.h"
+
static struct genl_family ethtool_genl_family;
static bool ethnl_ok __read_mostly;
@@ -934,12 +936,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
if (need_rtnl)
rtnl_lock();
netdev_lock_ops(dev);
- dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
- GFP_KERNEL_ACCOUNT);
- if (!dev->cfg_pending) {
- ret = -ENOMEM;
- goto out_tie_cfg;
- }
+ ret = netdev_reconfig_start(dev);
+ if (ret)
+ goto out_unlock;
ret = ethnl_ops_begin(dev);
if (ret < 0)
@@ -958,9 +957,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
out_ops:
ethnl_ops_complete(dev);
out_free_cfg:
- kfree(dev->cfg_pending);
-out_tie_cfg:
+ __netdev_free_config(dev->cfg_pending);
dev->cfg_pending = dev->cfg;
+out_unlock:
netdev_unlock_ops(dev);
if (need_rtnl)
rtnl_unlock();
diff --git a/net/ethtool/rings.c b/net/ethtool/rings.c
index 9054c89c5d7bb..c04312fc0d061 100644
--- a/net/ethtool/rings.c
+++ b/net/ethtool/rings.c
@@ -4,6 +4,7 @@
#include "common.h"
#include "netlink.h"
+#include "../core/dev.h"
struct rings_req_info {
struct ethnl_req_info base;
@@ -299,10 +300,20 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
dev->cfg_pending->hds_config = kernel_ringparam.tcp_data_split;
dev->cfg_pending->hds_thresh = kernel_ringparam.hds_thresh;
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+
+ ret = netdev_queue_config_revalidate(dev, info->extack);
+ if (ret)
+ return ret;
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
&kernel_ringparam, info->extack);
- return ret < 0 ? ret : 1;
+ if (ret < 0)
+ return ret;
+
+ /* The driver may adjust the accepted ring depths. */
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+ return 1;
}
const struct ethnl_request_ops ethnl_rings_request_ops = {
diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
index f6a8fc5fac241..c0d9065b21030 100644
--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
@@ -84,6 +84,9 @@ static int cfg_oneshot_recvs;
static int cfg_send_size = SEND_SIZE;
static struct sockaddr_in6 cfg_addr;
static unsigned int cfg_rx_buf_len;
+static unsigned int cfg_min_data_end;
+static bool cfg_check_data_end;
+static bool seen_data_end;
static bool cfg_dry_run;
static char *payload;
@@ -298,6 +301,15 @@ static void process_recvzc(struct io_uring *ring, struct io_uring_cqe *cqe)
mask = (1ULL << IORING_ZCRX_AREA_SHIFT) - 1;
data = (char *)area_ptr + (rcqe->off & mask);
+ if (cfg_check_data_end) {
+ unsigned int rx_buf_len = cfg_rx_buf_len ?: page_size;
+ unsigned int data_end_off;
+
+ data_end_off = (rcqe->off & mask) % rx_buf_len + n;
+ if (data_end_off > cfg_min_data_end)
+ seen_data_end = true;
+ }
+
for (i = 0; i < n; i++) {
if (*(data + i) != payload[(received + i)])
error(1, 0, "payload mismatch at %d", i);
@@ -373,7 +385,10 @@ static void run_server(void)
server_loop(&ring);
if (!stop)
- error(1, 0, "test failed\n");
+ error(1, 0, "test failed after receiving %zu bytes", received);
+ if (cfg_check_data_end && !seen_data_end)
+ error(1, 0, "no payload CQE ending past offset %u",
+ cfg_min_data_end);
}
static void run_client(void)
@@ -406,8 +421,11 @@ static void run_client(void)
static void usage(const char *filepath)
{
- error(1, 0, "Usage: %s (-4|-6) (-s|-c) -h<server_ip> -p<port> "
- "-l<payload_size> -i<ifname> -q<rxq_id>", filepath);
+ error(1, 0,
+ "Usage: %s (-4|-6) (-s|-c) -h<server_ip> -p<port>\n"
+ "\t-l<payload_size> -i<ifname> -q<rxq_id>\n"
+ "\t[-x<rx_buf_pages>] [-E<min_data_end>] [-d]\n",
+ filepath);
}
static void parse_opts(int argc, char **argv)
@@ -425,7 +443,7 @@ static void parse_opts(int argc, char **argv)
usage(argv[0]);
cfg_payload_len = max_payload_len;
- while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:x:d")) != -1) {
+ while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:x:E:d")) != -1) {
switch (c) {
case 's':
if (cfg_client)
@@ -463,6 +481,10 @@ static void parse_opts(int argc, char **argv)
case 'x':
cfg_rx_buf_len = page_size * strtoul(optarg, NULL, 0);
break;
+ case 'E':
+ cfg_check_data_end = true;
+ cfg_min_data_end = strtoul(optarg, NULL, 0);
+ break;
case 'd':
cfg_dry_run = true;
break;
@@ -484,6 +506,9 @@ static void parse_opts(int argc, char **argv)
if (cfg_payload_len > max_payload_len)
error(1, 0, "-l: payload exceeds max (%d)", max_payload_len);
+ if (cfg_check_data_end &&
+ cfg_min_data_end >= (cfg_rx_buf_len ?: page_size))
+ error(1, 0, "-E: offset outside rx_buf_len");
}
int main(int argc, char **argv)
diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
index b7a225fe4beae..a9f62c6b950bb 100755
--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
@@ -175,9 +175,13 @@ def test_zcrx_large_chunks(cfg) -> None:
single(cfg)
page_size = resource.getpagesize()
+ mtu = cfg.dev["mtu"]
nr_pages = 2
+ while nr_pages * page_size <= 2 * mtu:
+ nr_pages *= 2
rx_buf_len = nr_pages * page_size
- rx_cmd = f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.target} -x {nr_pages}"
+ rx_cmd = (f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} "
+ f"-q {cfg.target} -x {nr_pages} -E {mtu}")
tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 12840"
probe = cmd(rx_cmd + " -d", fail=False)
|
| 3/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 17856 output: 29 thoughts: 906 Thoughts: **WorthFuzzing Analysis: Network Core & ethtool Changes** Okay, let's dive into this patch series. My initial thought is to figure out if this is something we should be fuzzing. Looking at the files, it's hitting the `fbnic` driver, but more importantly, it's touching core networking code in `net/core/` and `net/ethtool/`. This is interesting because changes in these areas are likely to be widely applicable, and therefore a good target for fuzzing based on our rules. Specifically, I'm seeing modifications in `fbnic_csr.h`, `fbnic_debugfs.c`, `fbnic_ethtool.c`, `fbnic_netdev.c`, `fbnic_txrx.c`, `fbnic_txrx.h`, `net/netdev_queues.h`, `net/core/dev.c`, `net/core/dev.h`, `net/core/netdev_config.c`, `net/ethtool/common.c`, `net/ethtool/common.h`, `net/ethtool/ioctl.c`, `net/ethtool/netlink.c`, `net/ethtool/rings.c`, and even some selftests. The question is, are these core changes reachable and worth targeting? According to our criteria, anything in core networking is a potential win, particularly if it involves logic changes, data structure refactoring, or defensive checks. Now, let's trace the execution paths. I need to see how these core changes are triggered. From a quick glance, I can see that `alloc_netdev_mqs` calls `netdev_alloc_config`, and `free_netdev` calls `netdev_free_config`. Also, I'm seeing interactions with functions like `netdev_reconfig_start`, `netdev_queue_config_revalidate`, and `ethtool_ringparam_set_cfg`. It looks like the changes in `net/core/` and `net/ethtool/` are reachable via standard operations. Every netdev allocation calls `netdev_alloc_config(dev)`, and every ring parameter change through ethtool (both ioctl and netlink) triggers the `netdev_reconfig_start` sequence. This is good news, as these are common operations. So, even though `fbnic` is a Meta PCIe NIC driver, and might require physical hardware for some testing, the core network and ethtool changes are generic and executed for *all* network devices, and any device using ethtool or queue configurations. Therefore, this looks like a promising patch series to investigate further. It's time to inspect the files in detail and check for any Kconfig requirements to finalize my decision. |
| 4/2 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "netdev_alloc_config",
"PathPrefix": "net/core"
}Results: {
"Output": "net/core/dev.c=12094=struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,\n--\nnet/core/dev.c-12197-\nnet/core/dev.c:12198:\tif (netdev_alloc_config(dev))\nnet/core/dev.c-12199-\t\tgoto free_all;\n--\nnet/core/dev.h=103=void netdev_run_todo(void);\nnet/core/dev.h-104-\nnet/core/dev.h:105:int netdev_alloc_config(struct net_device *dev);\nnet/core/dev.h-106-void __netdev_free_config(struct netdev_config *cfg);\n--\nnet/core/netdev_config.c-8-\nnet/core/netdev_config.c:9:int netdev_alloc_config(struct net_device *dev)\nnet/core/netdev_config.c-10-{\n"
} |
| 5/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 19672 output: 27 thoughts: 52 Thoughts: **Investigating Compilation Dependencies** Okay, so I need to figure out the Kconfig options controlling the build of `net/core/netdev_config.c` and everything in `net/ethtool/`. Since these are core networking components, there's likely some fairly granular control over their inclusion. My first step is to dig into the Makefiles. Specifically, I'm going to check out `net/core/Makefile` and `net/ethtool/Makefile`. These are the obvious places to find the conditional compilation logic based on Kconfig settings. I'm expecting to see things like `ifdef` blocks or similar constructs that determine whether specific source files or entire directories are included in the build based on the values of different Kconfig symbols. Let's see what these files tell me. |
| 6/2 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "netdev_config",
"PathPrefix": "net/core"
}Results: {
"Output": "net/core/Makefile=21=obj-y += hotdata.o\nnet/core/Makefile:22:obj-y += netdev_config.o\nnet/core/Makefile-23-obj-y += netdev_rx_queue.o\n--\nnet/core/dev.h=105=int netdev_alloc_config(struct net_device *dev);\nnet/core/dev.h:106:void __netdev_free_config(struct netdev_config *cfg);\nnet/core/dev.h-107-void netdev_free_config(struct net_device *dev);\n--\nnet/core/netdev_config.c=9=int netdev_alloc_config(struct net_device *dev)\nnet/core/netdev_config.c-10-{\nnet/core/netdev_config.c:11:\tstruct netdev_config *cfg;\nnet/core/netdev_config.c-12-\n--\nnet/core/netdev_config.c-21-\nnet/core/netdev_config.c:22:void __netdev_free_config(struct netdev_config *cfg)\nnet/core/netdev_config.c-23-{\n--\nnet/core/netdev_config.c=33=int netdev_reconfig_start(struct net_device *dev)\nnet/core/netdev_config.c-34-{\nnet/core/netdev_config.c:35:\tstruct netdev_config *cfg;\nnet/core/netdev_config.c-36-\n--\nnet/core/netdev_config.c=53=static void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg,\nnet/core/netdev_config.c:54:\t\t\t\t const struct netdev_config *cfg)\nnet/core/netdev_config.c-55-{\n"
} |
| 7/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 20397 output: 26 thoughts: 16 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Examining the `ethtool` Build Process** Okay, so we need to make sure we haven't overlooked any changes that impact the build process for `ethtool`. My initial focus was on the usual suspects, but a nagging thought tells me we should double-check the `net/ethtool/Makefile`. It's possible some subtle dependency or flag configuration within that specific makefile is the root cause, or at least a secondary factor. It’s always best practice to cover all the bases when dealing with network device drivers and their tooling. Better to be thorough now and avoid wasted time later. |
| 8/2 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "rings",
"PathPrefix": "net/ethtool"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 587 lines.\nUse more precise expression if possible.\n\nnet/ethtool/Makefile=7=ethtool_nl-y\t:= netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \\\nnet/ethtool/Makefile:8:\t\t linkstate.o debug.o wol.o features.o privflags.o rings.o \\\nnet/ethtool/Makefile-9-\t\t channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \\\n--\nnet/ethtool/bitset.c=329=int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact)\n--\nnet/ethtool/bitset.c-353- * ethnl_name_to_idx() - look up string index for a name\nnet/ethtool/bitset.c:354: * @names: array of ETH_GSTRING_LEN sized strings\nnet/ethtool/bitset.c:355: * @n_names: number of strings in the array\nnet/ethtool/bitset.c-356- * @name: name to look up\n--\nnet/ethtool/common.c-15-\nnet/ethtool/common.c:16:const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {\nnet/ethtool/common.c-17-\t[NETIF_F_SG_BIT] = \"tx-scatter-gather\",\n--\nnet/ethtool/common.c=81=const char\nnet/ethtool/common.c:82:rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {\nnet/ethtool/common.c-83-\t[ETH_RSS_HASH_TOP_BIT] =\t\"toeplitz\",\n--\nnet/ethtool/common.c=88=const char\nnet/ethtool/common.c:89:tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {\nnet/ethtool/common.c-90-\t[ETHTOOL_ID_UNSPEC] = \"Unspec\",\n--\nnet/ethtool/common.c=97=const char\nnet/ethtool/common.c:98:phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {\nnet/ethtool/common.c-99-\t[ETHTOOL_ID_UNSPEC] = \"Unspec\",\n--\nnet/ethtool/common.c=959=void ethtool_ringparam_set_cfg(struct netdev_config *cfg,\n--\nnet/ethtool/common.c-961-{\nnet/ethtool/common.c:962:\tcfg-\u003erings.rx_pending = param-\u003erx_pending;\nnet/ethtool/common.c:963:\tcfg-\u003erings.rx_mini_pending = param-\u003erx_mini_pending;\nnet/ethtool/common.c:964:\tcfg-\u003erings.rx_jumbo_pending = param-\u003erx_jumbo_pending;\nnet/ethtool/common.c:965:\tcfg-\u003erings.tx_pending = param-\u003etx_pending;\nnet/ethtool/common.c-966-}\n--\nnet/ethtool/common.h=21=extern const char\nnet/ethtool/common.h:22:netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];\nnet/ethtool/common.h-23-extern const char\nnet/ethtool/common.h:24:rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN];\nnet/ethtool/common.h-25-extern const char\nnet/ethtool/common.h:26:tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];\nnet/ethtool/common.h-27-extern const char\nnet/ethtool/common.h:28:phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];\nnet/ethtool/common.h-29-extern const char link_mode_names[][ETH_GSTRING_LEN];\n--\nnet/ethtool/features.c=56=static int features_reply_size(const struct ethnl_req_info *req_base,\n--\nnet/ethtool/features.c-64-\tret = ethnl_bitset32_size(data-\u003ehw, data-\u003eall, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:65:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-66-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-69-\tret = ethnl_bitset32_size(data-\u003ewanted, NULL, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:70:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-71-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-74-\tret = ethnl_bitset32_size(data-\u003eactive, NULL, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:75:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-76-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-79-\tret = ethnl_bitset32_size(data-\u003enochange, NULL, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:80:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-81-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c=88=static int features_fill_reply(struct sk_buff *skb,\n--\nnet/ethtool/features.c-97-\t\t\t\t data-\u003eall, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:98:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-99-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-102-\t\t\t\t NULL, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:103:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-104-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-107-\t\t\t\t NULL, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:108:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-109-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-112-\t\t\t\t data-\u003enochange, NULL, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:113:\t\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-114-}\n--\nnet/ethtool/features.c=158=static int features_send_reply(struct net_device *dev, struct genl_info *info,\n--\nnet/ethtool/features.c-170-\tret = ethnl_bitset_size(wanted, wanted_mask, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:171:\t\t\t\tnetdev_features_strings, compact);\nnet/ethtool/features.c-172-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-175-\tret = ethnl_bitset_size(active, active_mask, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:176:\t\t\t\tnetdev_features_strings, compact);\nnet/ethtool/features.c-177-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-189-\t\t\t wanted_mask, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:190:\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-191-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c-194-\t\t\t active_mask, NETDEV_FEATURE_COUNT,\nnet/ethtool/features.c:195:\t\t\t netdev_features_strings, compact);\nnet/ethtool/features.c-196-\tif (ret \u003c 0)\n--\nnet/ethtool/features.c=212=int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)\n--\nnet/ethtool/features.c-246-\t\t\t\t tb[ETHTOOL_A_FEATURES_WANTED],\nnet/ethtool/features.c:247:\t\t\t\t netdev_features_strings, info-\u003eextack);\nnet/ethtool/features.c-248-\tif (ret \u003c 0)\n--\nnet/ethtool/ioctl.c=164=static int __ethtool_get_sset_count(struct net_device *dev, int sset)\n--\nnet/ethtool/ioctl.c-169-\tif (sset == ETH_SS_FEATURES)\nnet/ethtool/ioctl.c:170:\t\treturn ARRAY_SIZE(netdev_features_strings);\nnet/ethtool/ioctl.c-171-\nnet/ethtool/ioctl.c-172-\tif (sset == ETH_SS_RSS_HASH_FUNCS)\nnet/ethtool/ioctl.c:173:\t\treturn ARRAY_SIZE(rss_hash_func_strings);\nnet/ethtool/ioctl.c-174-\nnet/ethtool/ioctl.c-175-\tif (sset == ETH_SS_TUNABLES)\nnet/ethtool/ioctl.c:176:\t\treturn ARRAY_SIZE(tunable_strings);\nnet/ethtool/ioctl.c-177-\nnet/ethtool/ioctl.c-178-\tif (sset == ETH_SS_PHY_TUNABLES)\nnet/ethtool/ioctl.c:179:\t\treturn ARRAY_SIZE(phy_tunable_strings);\nnet/ethtool/ioctl.c-180-\n--\nnet/ethtool/ioctl.c-188-\nnet/ethtool/ioctl.c:189:\tif (ops-\u003eget_sset_count \u0026\u0026 ops-\u003eget_strings)\nnet/ethtool/ioctl.c-190-\t\treturn ops-\u003eget_sset_count(dev, sset);\n--\nnet/ethtool/ioctl.c-194-\nnet/ethtool/ioctl.c:195:static void __ethtool_get_strings(struct net_device *dev,\nnet/ethtool/ioctl.c:196:\tu32 stringset, u8 *data)\nnet/ethtool/ioctl.c-197-{\n--\nnet/ethtool/ioctl.c-200-\nnet/ethtool/ioctl.c:201:\tif (stringset == ETH_SS_FEATURES)\nnet/ethtool/ioctl.c:202:\t\tmemcpy(data, netdev_features_strings,\nnet/ethtool/ioctl.c:203:\t\t\tsizeof(netdev_features_strings));\nnet/ethtool/ioctl.c:204:\telse if (stringset == ETH_SS_RSS_HASH_FUNCS)\nnet/ethtool/ioctl.c:205:\t\tmemcpy(data, rss_hash_func_strings,\nnet/ethtool/ioctl.c:206:\t\t sizeof(rss_hash_func_strings));\nnet/ethtool/ioctl.c:207:\telse if (stringset == ETH_SS_TUNABLES)\nnet/ethtool/ioctl.c:208:\t\tmemcpy(data, tunable_strings, sizeof(tunable_strings));\nnet/ethtool/ioctl.c:209:\telse if (stringset == ETH_SS_PHY_TUNABLES)\nnet/ethtool/ioctl.c:210:\t\tmemcpy(data, phy_tunable_strings, sizeof(phy_tunable_strings));\nnet/ethtool/ioctl.c:211:\telse if (stringset == ETH_SS_PHY_STATS \u0026\u0026 dev-\u003ephydev \u0026\u0026\nnet/ethtool/ioctl.c-212-\t\t !ops-\u003eget_ethtool_phy_stats \u0026\u0026 phy_ops \u0026\u0026\nnet/ethtool/ioctl.c:213:\t\t phy_ops-\u003eget_strings)\nnet/ethtool/ioctl.c:214:\t\tphy_ops-\u003eget_strings(dev-\u003ephydev, data);\nnet/ethtool/ioctl.c:215:\telse if (stringset == ETH_SS_LINK_MODES)\nnet/ethtool/ioctl.c-216-\t\tmemcpy(data, link_mode_names,\n--\nnet/ethtool/ioctl.c-218-\telse\nnet/ethtool/ioctl.c:219:\t\t/* ops-\u003eget_strings is valid because checked earlier */\nnet/ethtool/ioctl.c:220:\t\tops-\u003eget_strings(dev, stringset, data);\nnet/ethtool/ioctl.c-221-}\n--\nnet/ethtool/ioctl.c=1189=static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,\n--\nnet/ethtool/ioctl.c-1227-\nnet/ethtool/ioctl.c:1228:static noinline_for_stack int ethtool_get_rxrings(struct net_device *dev,\nnet/ethtool/ioctl.c-1229-\t\t\t\t\t\t u32 cmd,\n--\nnet/ethtool/ioctl.c=1288=static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,\nnet/ethtool/ioctl.c:1289:\t\t\t\t int num_rx_rings,\nnet/ethtool/ioctl.c-1290-\t\t\t\t u32 size)\n--\nnet/ethtool/ioctl.c-1298-\tfor (i = 0; i \u003c size; i++)\nnet/ethtool/ioctl.c:1299:\t\tif (indir[i] \u003e= num_rx_rings)\nnet/ethtool/ioctl.c-1300-\t\t\treturn -EINVAL;\n--\nnet/ethtool/ioctl.c=1364=static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,\n--\nnet/ethtool/ioctl.c-1369-\tstruct netlink_ext_ack *extack = NULL;\nnet/ethtool/ioctl.c:1370:\tint num_rx_rings;\nnet/ethtool/ioctl.c-1371-\tu32 user_size, i;\n--\nnet/ethtool/ioctl.c-1394-\nnet/ethtool/ioctl.c:1395:\tnum_rx_rings = ethtool_get_rx_ring_count(dev);\nnet/ethtool/ioctl.c:1396:\tif (num_rx_rings \u003c 0) {\nnet/ethtool/ioctl.c:1397:\t\tret = num_rx_rings;\nnet/ethtool/ioctl.c-1398-\t\tgoto out;\n--\nnet/ethtool/ioctl.c-1404-\t\tfor (i = 0; i \u003c rxfh_dev.indir_size; i++)\nnet/ethtool/ioctl.c:1405:\t\t\tindir[i] = ethtool_rxfh_indir_default(i, num_rx_rings);\nnet/ethtool/ioctl.c-1406-\t} else {\n--\nnet/ethtool/ioctl.c-1408-\t\t\t\t\t\t useraddr + ringidx_offset,\nnet/ethtool/ioctl.c:1409:\t\t\t\t\t\t num_rx_rings,\nnet/ethtool/ioctl.c-1410-\t\t\t\t\t\t rxfh_dev.indir_size);\n--\nnet/ethtool/ioctl.c=1541=static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,\n--\nnet/ethtool/ioctl.c-1552-\tbool create = false;\nnet/ethtool/ioctl.c:1553:\tint num_rx_rings;\nnet/ethtool/ioctl.c-1554-\tu8 *rss_config;\n--\nnet/ethtool/ioctl.c-1613-\nnet/ethtool/ioctl.c:1614:\tnum_rx_rings = ethtool_get_rx_ring_count(dev);\nnet/ethtool/ioctl.c:1615:\tif (num_rx_rings \u003c 0) {\nnet/ethtool/ioctl.c:1616:\t\tret = num_rx_rings;\nnet/ethtool/ioctl.c-1617-\t\tgoto out_free;\n--\nnet/ethtool/ioctl.c-1630-\t\t\t\t\t\t useraddr + rss_cfg_offset,\nnet/ethtool/ioctl.c:1631:\t\t\t\t\t\t num_rx_rings,\nnet/ethtool/ioctl.c-1632-\t\t\t\t\t\t rxfh.indir_size);\n--\nnet/ethtool/ioctl.c-1643-\t\t\t\tindir[i] =\nnet/ethtool/ioctl.c:1644:\t\t\t\t\tethtool_rxfh_indir_default(i, num_rx_rings);\nnet/ethtool/ioctl.c-1645-\t\t} else {\n--\nnet/ethtool/ioctl.c=2370=static int ethtool_self_test(struct net_device *dev, char __user *useraddr)\n--\nnet/ethtool/ioctl.c-2409-\nnet/ethtool/ioctl.c:2410:static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)\nnet/ethtool/ioctl.c-2411-{\nnet/ethtool/ioctl.c:2412:\tstruct ethtool_gstrings gstrings;\nnet/ethtool/ioctl.c-2413-\tu8 *data;\n--\nnet/ethtool/ioctl.c-2415-\nnet/ethtool/ioctl.c:2416:\tif (copy_from_user(\u0026gstrings, useraddr, sizeof(gstrings)))\nnet/ethtool/ioctl.c-2417-\t\treturn -EFAULT;\nnet/ethtool/ioctl.c-2418-\nnet/ethtool/ioctl.c:2419:\tret = __ethtool_get_sset_count(dev, gstrings.string_set);\nnet/ethtool/ioctl.c-2420-\tif (ret \u003c 0)\n--\nnet/ethtool/ioctl.c-2425-\nnet/ethtool/ioctl.c:2426:\tif (gstrings.len \u0026\u0026 gstrings.len != ret)\nnet/ethtool/ioctl.c:2427:\t\tgstrings.len = 0;\nnet/ethtool/ioctl.c-2428-\telse\nnet/ethtool/ioctl.c:2429:\t\tgstrings.len = ret;\nnet/ethtool/ioctl.c-2430-\nnet/ethtool/ioctl.c:2431:\tif (gstrings.len) {\nnet/ethtool/ioctl.c:2432:\t\tdata = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN));\nnet/ethtool/ioctl.c-2433-\t\tif (!data)\n--\nnet/ethtool/ioctl.c-2435-\nnet/ethtool/ioctl.c:2436:\t\t__ethtool_get_strings(dev, gstrings.string_set, data);\nnet/ethtool/ioctl.c-2437-\t} else {\n--\nnet/ethtool/ioctl.c-2441-\tret = -EFAULT;\nnet/ethtool/ioctl.c:2442:\tif (copy_to_user(useraddr, \u0026gstrings, sizeof(gstrings)))\nnet/ethtool/ioctl.c-2443-\t\tgoto out;\nnet/ethtool/ioctl.c:2444:\tuseraddr += sizeof(gstrings);\nnet/ethtool/ioctl.c:2445:\tif (gstrings.len \u0026\u0026\nnet/ethtool/ioctl.c-2446-\t copy_to_user(useraddr, data,\nnet/ethtool/ioctl.c:2447:\t\t\t array_size(gstrings.len, ETH_GSTRING_LEN)))\nnet/ethtool/ioctl.c-2448-\t\tgoto out;\n--\nnet/ethtool/ioctl.c=3292=dev_ethtool_locked(struct net *net, struct net_device *dev,\n--\nnet/ethtool/ioctl.c-3436-\tcase ETHTOOL_GSTRINGS:\nnet/ethtool/ioctl.c:3437:\t\trc = ethtool_get_strings(dev, useraddr);\nnet/ethtool/ioctl.c-3438-\t\tbreak;\n--\nnet/ethtool/ioctl.c-3471-\tcase ETHTOOL_GRXRINGS:\nnet/ethtool/ioctl.c:3472:\t\trc = ethtool_get_rxrings(dev, ethcmd, useraddr);\nnet/ethtool/ioctl.c-3473-\t\tbreak;\n--\nnet/ethtool/netlink.c=391=ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {\n--\nnet/ethtool/netlink.c-404-\t[ETHTOOL_MSG_PRIVFLAGS_SET]\t= \u0026ethnl_privflags_request_ops,\nnet/ethtool/netlink.c:405:\t[ETHTOOL_MSG_RINGS_GET]\t\t= \u0026ethnl_rings_request_ops,\nnet/ethtool/netlink.c:406:\t[ETHTOOL_MSG_RINGS_SET]\t\t= \u0026ethnl_rings_request_ops,\nnet/ethtool/netlink.c-407-\t[ETHTOOL_MSG_CHANNELS_GET]\t= \u0026ethnl_channels_request_ops,\n--\nnet/ethtool/netlink.c=974=ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {\n--\nnet/ethtool/netlink.c-980-\t[ETHTOOL_MSG_PRIVFLAGS_NTF]\t= \u0026ethnl_privflags_request_ops,\nnet/ethtool/netlink.c:981:\t[ETHTOOL_MSG_RINGS_NTF]\t\t= \u0026ethnl_rings_request_ops,\nnet/ethtool/netlink.c-982-\t[ETHTOOL_MSG_CHANNELS_NTF]\t= \u0026ethnl_channels_request_ops,\n--\nnet/ethtool/netlink.c=1160=static const struct genl_ops ethtool_genl_ops[] = {\n--\nnet/ethtool/netlink.c-1281-\t\t.done\t= ethnl_default_done,\nnet/ethtool/netlink.c:1282:\t\t.policy = ethnl_rings_get_policy,\nnet/ethtool/netlink.c:1283:\t\t.maxattr = ARRAY_SIZE(ethnl_rings_get_policy) - 1,\nnet/ethtool/netlink.c-1284-\t},\n--\nnet/ethtool/netlink.c-1288-\t\t.doit\t= ethnl_default_set_doit,\nnet/ethtool/netlink.c:1289:\t\t.policy = ethnl_rings_set_policy,\nnet/ethtool/netlink.c:1290:\t\t.maxattr = ARRAY_SIZE(ethnl_rings_set_policy) - 1,\nnet/ethtool/netlink.c-1291-\t},\n--\nnet/ethtool/netlink.h=457=extern const struct ethnl_request_ops ethnl_privflags_request_ops;\nnet/ethtool/netlink.h:458:extern const struct ethnl_request_ops ethnl_rings_request_ops;\nnet/ethtool/netlink.h-459-extern const struct ethnl_request_ops ethnl_channels_request_ops;\n--\nnet/ethtool/netlink.h=495=extern const struct nla_policy ethnl_privflags_set_policy[ETHTOOL_A_PRIVFLAGS_FLAGS + 1];\nnet/ethtool/netlink.h:496:extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_HEADER + 1];\nnet/ethtool/netlink.h:497:extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_HDS_THRESH_MAX + 1];\nnet/ethtool/netlink.h-498-extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1];\n--\nnet/ethtool/privflags.c=26=static int ethnl_get_priv_flags_info(struct net_device *dev,\n--\nnet/ethtool/privflags.c-40-\t\t\treturn -ENOMEM;\nnet/ethtool/privflags.c:41:\t\tops-\u003eget_strings(dev, ETH_SS_PRIV_FLAGS, (u8 *)*names);\nnet/ethtool/privflags.c-42-\t}\n--\nnet/ethtool/privflags.c=58=static int privflags_prepare_data(const struct ethnl_req_info *req_base,\n--\nnet/ethtool/privflags.c-69-\tops = dev-\u003eethtool_ops;\nnet/ethtool/privflags.c:70:\tif (!ops-\u003eget_priv_flags || !ops-\u003eget_sset_count || !ops-\u003eget_strings)\nnet/ethtool/privflags.c-71-\t\treturn -EOPNOTSUPP;\n--\nnet/ethtool/privflags.c=130=ethnl_set_privflags_validate(struct ethnl_req_info *req_info,\n--\nnet/ethtool/privflags.c-138-\tif (!ops-\u003eget_priv_flags || !ops-\u003eset_priv_flags ||\nnet/ethtool/privflags.c:139:\t !ops-\u003eget_sset_count || !ops-\u003eget_strings)\nnet/ethtool/privflags.c-140-\t\treturn -EOPNOTSUPP;\n--\nnet/ethtool/rings.c-8-\nnet/ethtool/rings.c:9:struct rings_req_info {\nnet/ethtool/rings.c-10-\tstruct ethnl_req_info\t\tbase;\n--\nnet/ethtool/rings.c-12-\nnet/ethtool/rings.c:13:struct rings_reply_data {\nnet/ethtool/rings.c-14-\tstruct ethnl_reply_data\t\tbase;\n--\nnet/ethtool/rings.c-20-#define RINGS_REPDATA(__reply_base) \\\nnet/ethtool/rings.c:21:\tcontainer_of(__reply_base, struct rings_reply_data, base)\nnet/ethtool/rings.c-22-\nnet/ethtool/rings.c:23:const struct nla_policy ethnl_rings_get_policy[] = {\nnet/ethtool/rings.c-24-\t[ETHTOOL_A_RINGS_HEADER]\t\t=\n--\nnet/ethtool/rings.c-27-\nnet/ethtool/rings.c:28:static int rings_prepare_data(const struct ethnl_req_info *req_base,\nnet/ethtool/rings.c-29-\t\t\t struct ethnl_reply_data *reply_base,\n--\nnet/ethtool/rings.c-31-{\nnet/ethtool/rings.c:32:\tstruct rings_reply_data *data = RINGS_REPDATA(reply_base);\nnet/ethtool/rings.c-33-\tstruct net_device *dev = reply_base-\u003edev;\n--\nnet/ethtool/rings.c-53-\nnet/ethtool/rings.c:54:static int rings_reply_size(const struct ethnl_req_info *req_base,\nnet/ethtool/rings.c-55-\t\t\t const struct ethnl_reply_data *reply_base)\n--\nnet/ethtool/rings.c-75-\nnet/ethtool/rings.c:76:static int rings_fill_reply(struct sk_buff *skb,\nnet/ethtool/rings.c-77-\t\t\t const struct ethnl_req_info *req_base,\n--\nnet/ethtool/rings.c-79-{\nnet/ethtool/rings.c:80:\tconst struct rings_reply_data *data = RINGS_REPDATA(reply_base);\nnet/ethtool/rings.c-81-\tconst struct kernel_ethtool_ringparam *kr = \u0026data-\u003ekernel_ringparam;\n--\nnet/ethtool/rings.c-132-\nnet/ethtool/rings.c:133:const struct nla_policy ethnl_rings_set_policy[] = {\nnet/ethtool/rings.c-134-\t[ETHTOOL_A_RINGS_HEADER]\t\t=\n--\nnet/ethtool/rings.c=150=static int\nnet/ethtool/rings.c:151:ethnl_set_rings_validate(struct ethnl_req_info *req_info,\nnet/ethtool/rings.c-152-\t\t\t struct genl_info *info)\n--\nnet/ethtool/rings.c=216=static int\nnet/ethtool/rings.c:217:ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)\nnet/ethtool/rings.c-218-{\n--\nnet/ethtool/rings.c-318-\nnet/ethtool/rings.c:319:const struct ethnl_request_ops ethnl_rings_request_ops = {\nnet/ethtool/rings.c-320-\t.request_cmd\t\t= ETHTOOL_MSG_RINGS_GET,\n--\nnet/ethtool/rings.c-322-\t.hdr_attr\t\t= ETHTOOL_A_RINGS_HEADER,\nnet/ethtool/rings.c:323:\t.req_info_size\t\t= sizeof(struct rings_req_info),\nnet/ethtool/rings.c:324:\t.reply_data_size\t= sizeof(struct rings_reply_data),\nnet/ethtool/rings.c-325-\nnet/ethtool/rings.c:326:\t.prepare_data\t\t= rings_prepare_data,\nnet/ethtool/rings.c:327:\t.reply_size\t\t= rings_reply_size,\nnet/ethtool/rings.c:328:\t.fill_reply\t\t= rings_fill_reply,\nnet/ethtool/rings.c-329-\nnet/ethtool/rings.c:330:\t.set_validate\t\t= ethnl_set_rings_validate,\nnet/ethtool/rings.c:331:\t.set\t\t\t= ethnl_set_rings,\nnet/ethtool/rings.c-332-\t.set_ntf_cmd\t\t= ETHTOOL_MSG_RINGS_NTF,\n--\nnet/ethtool/rss.c=618=rss_set_prep_indir(struct net_device *dev, struct genl_info *info,\n--\nnet/ethtool/rss.c-624-\tsize_t alloc_size;\nnet/ethtool/rss.c:625:\tint num_rx_rings;\nnet/ethtool/rss.c-626-\tu32 user_size;\n--\nnet/ethtool/rss.c-636-\t\treturn err;\nnet/ethtool/rss.c:637:\tnum_rx_rings = err;\nnet/ethtool/rss.c-638-\n--\nnet/ethtool/rss.c-665-\tfor (i = 0; i \u003c user_size; i++) {\nnet/ethtool/rss.c:666:\t\tif (rxfh-\u003eindir[i] \u003c num_rx_rings)\nnet/ethtool/rss.c-667-\t\t\tcontinue;\n--\nnet/ethtool/rss.c-682-\t\t\trxfh-\u003eindir[i] =\nnet/ethtool/rss.c:683:\t\t\t\tethtool_rxfh_indir_default(i, num_rx_rings);\nnet/ethtool/rss.c-684-\t}\n--\nnet/ethtool/strset.c=9=struct strset_info {\nnet/ethtool/strset.c-10-\tbool per_dev;\nnet/ethtool/strset.c:11:\tbool free_strings;\nnet/ethtool/strset.c-12-\tunsigned int count;\nnet/ethtool/strset.c:13:\tconst char (*strings)[ETH_GSTRING_LEN];\nnet/ethtool/strset.c-14-};\n--\nnet/ethtool/strset.c=16=static const struct strset_info info_template[] = {\n--\nnet/ethtool/strset.c-27-\t\t.per_dev\t= false,\nnet/ethtool/strset.c:28:\t\t.count\t\t= ARRAY_SIZE(netdev_features_strings),\nnet/ethtool/strset.c:29:\t\t.strings\t= netdev_features_strings,\nnet/ethtool/strset.c-30-\t},\n--\nnet/ethtool/strset.c-32-\t\t.per_dev\t= false,\nnet/ethtool/strset.c:33:\t\t.count\t\t= ARRAY_SIZE(rss_hash_func_strings),\nnet/ethtool/strset.c:34:\t\t.strings\t= rss_hash_func_strings,\nnet/ethtool/strset.c-35-\t},\n--\nnet/ethtool/strset.c-37-\t\t.per_dev\t= false,\nnet/ethtool/strset.c:38:\t\t.count\t\t= ARRAY_SIZE(tunable_strings),\nnet/ethtool/strset.c:39:\t\t.strings\t= tunable_strings,\nnet/ethtool/strset.c-40-\t},\n--\nnet/ethtool/strset.c-45-\t\t.per_dev\t= false,\nnet/ethtool/strset.c:46:\t\t.count\t\t= ARRAY_SIZE(phy_tunable_strings),\nnet/ethtool/strset.c:47:\t\t.strings\t= phy_tunable_strings,\nnet/ethtool/strset.c-48-\t},\n--\nnet/ethtool/strset.c-51-\t\t.count\t\t= __ETHTOOL_LINK_MODE_MASK_NBITS,\nnet/ethtool/strset.c:52:\t\t.strings\t= link_mode_names,\nnet/ethtool/strset.c-53-\t},\n--\nnet/ethtool/strset.c-56-\t\t.count\t\t= NETIF_MSG_CLASS_COUNT,\nnet/ethtool/strset.c:57:\t\t.strings\t= netif_msg_class_names,\nnet/ethtool/strset.c-58-\t},\n--\nnet/ethtool/strset.c-61-\t\t.count\t\t= WOL_MODE_COUNT,\nnet/ethtool/strset.c:62:\t\t.strings\t= wol_mode_names,\nnet/ethtool/strset.c-63-\t},\n--\nnet/ethtool/strset.c-66-\t\t.count\t\t= __SOF_TIMESTAMPING_CNT,\nnet/ethtool/strset.c:67:\t\t.strings\t= sof_timestamping_names,\nnet/ethtool/strset.c-68-\t},\n--\nnet/ethtool/strset.c-71-\t\t.count\t\t= __HWTSTAMP_TX_CNT,\nnet/ethtool/strset.c:72:\t\t.strings\t= ts_tx_type_names,\nnet/ethtool/strset.c-73-\t},\n--\nnet/ethtool/strset.c-76-\t\t.count\t\t= __HWTSTAMP_FILTER_CNT,\nnet/ethtool/strset.c:77:\t\t.strings\t= ts_rx_filter_names,\nnet/ethtool/strset.c-78-\t},\n--\nnet/ethtool/strset.c-81-\t\t.count\t\t= __HWTSTAMP_FLAG_CNT,\nnet/ethtool/strset.c:82:\t\t.strings\t= ts_flags_names,\nnet/ethtool/strset.c-83-\t},\n--\nnet/ethtool/strset.c-86-\t\t.count\t\t= __ETHTOOL_UDP_TUNNEL_TYPE_CNT,\nnet/ethtool/strset.c:87:\t\t.strings\t= udp_tunnel_type_names,\nnet/ethtool/strset.c-88-\t},\n--\nnet/ethtool/strset.c-91-\t\t.count\t\t= __ETHTOOL_STATS_CNT,\nnet/ethtool/strset.c:92:\t\t.strings\t= stats_std_names,\nnet/ethtool/strset.c-93-\t},\n--\nnet/ethtool/strset.c-96-\t\t.count\t\t= __ETHTOOL_A_STATS_ETH_PHY_CNT,\nnet/ethtool/strset.c:97:\t\t.strings\t= stats_eth_phy_names,\nnet/ethtool/strset.c-98-\t},\n--\nnet/ethtool/strset.c-101-\t\t.count\t\t= __ETHTOOL_A_STATS_ETH_MAC_CNT,\nnet/ethtool/strset.c:102:\t\t.strings\t= stats_eth_mac_names,\nnet/ethtool/strset.c-103-\t},\n--\nnet/ethtool/strset.c-106-\t\t.count\t\t= __ETHTOOL_A_STATS_ETH_CTRL_CNT,\nnet/ethtool/strset.c:107:\t\t.strings\t= stats_eth_ctrl_names,\nnet/ethtool/strset.c-108-\t},\n--\nnet/ethtool/strset.c-111-\t\t.count\t\t= __ETHTOOL_A_STATS_RMON_CNT,\nnet/ethtool/strset.c:112:\t\t.strings\t= stats_rmon_names,\nnet/ethtool/strset.c-113-\t},\n--\nnet/ethtool/strset.c-116-\t\t.count\t\t= __ETHTOOL_A_STATS_PHY_CNT,\nnet/ethtool/strset.c:117:\t\t.strings\t= stats_phy_names,\nnet/ethtool/strset.c-118-\t},\n--\nnet/ethtool/strset.c=138=const struct nla_policy ethnl_strset_get_policy[] = {\n--\nnet/ethtool/strset.c-144-\nnet/ethtool/strset.c:145:static const struct nla_policy get_stringset_policy[] = {\nnet/ethtool/strset.c-146-\t[ETHTOOL_A_STRINGSET_ID]\t= { .type = NLA_U32 },\n--\nnet/ethtool/strset.c=155=static bool strset_include(const struct strset_req_info *info,\n--\nnet/ethtool/strset.c-164-\tper_dev = data-\u003esets[id].per_dev;\nnet/ethtool/strset.c:165:\tif (!per_dev \u0026\u0026 !data-\u003esets[id].strings)\nnet/ethtool/strset.c-166-\t\treturn false;\n--\nnet/ethtool/strset.c=171=static int strset_get_id(const struct nlattr *nest, u32 *val,\n--\nnet/ethtool/strset.c-173-{\nnet/ethtool/strset.c:174:\tstruct nlattr *tb[ARRAY_SIZE(get_stringset_policy)];\nnet/ethtool/strset.c-175-\tint ret;\nnet/ethtool/strset.c-176-\nnet/ethtool/strset.c:177:\tret = nla_parse_nested(tb, ARRAY_SIZE(get_stringset_policy) - 1, nest,\nnet/ethtool/strset.c:178:\t\t\t get_stringset_policy, extack);\nnet/ethtool/strset.c-179-\tif (ret \u003c 0)\n--\nnet/ethtool/strset.c-187-\nnet/ethtool/strset.c:188:static const struct nla_policy strset_stringsets_policy[] = {\nnet/ethtool/strset.c-189-\t[ETHTOOL_A_STRINGSETS_STRINGSET]\t= { .type = NLA_NESTED },\n--\nnet/ethtool/strset.c=192=static int strset_parse_request(struct ethnl_req_info *req_base,\n--\n\n"
} |
| 9/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 31412 output: 35 thoughts: 1275 Thoughts: **Fuzzing Target Evaluation: Network Device Configuration Changes** Okay, let's break this down. My initial assessment is that these changes are indeed fuzz-worthy. Here's my thought process: First, I'm noting the specific code changes. The core of this patch series focuses on restructuring how network device configurations are handled. Specifically, I see shifts from direct `kzalloc_obj` calls to dedicated `netdev_alloc_config` and `netdev_free_config` functions. There's a new revalidation process with `netdev_reconfig_start` and `netdev_queue_config_revalidate`, suggesting a move towards a more robust and atomic configuration update mechanism. Notably, there are runtime assertions (`WARN_ON`) that can potentially be triggered during configuration, highlighting possible edge cases. The changes also touch the ethtool interface, involving ioctls and Netlink interfaces for ring parameter manipulation (`ethtool_set_ringparam`, `ethnl_set_rings`). Crucially, these changes permeate core networking code – `net/core/dev.c`, `net/core/netdev_config.c`, and the `net/ethtool/` subsystem. This makes them relevant to nearly all network interfaces. Any device allocation, from basic interfaces to virtual ones, uses the new configuration allocation scheme. The ethtool paths, in particular, provide standard avenues to exercise this new configuration logic. The fact that this is easily reachable in common environments like QEMU and Syzkaller further boosts the fuzzing potential. We don't need exotic hardware to trigger these. The runtime assertions add a layer of safety, as they can reveal any configuration inconsistencies at runtime. Given all this, the `WorthFuzzing` flag is definitely set to true. Now, let's determine the best FocusSymbols and EnableConfigs. We're going to examine the focus symbols: Within `net/core/netdev_config.c`, I'm particularly interested in `netdev_alloc_config`, `netdev_free_config`, `netdev_reconfig_start`, `netdev_queue_config_revalidate`, `__netdev_queue_config` and `netdev_qcfg_apply_dev`. These are all new functions directly related to configuration management. Then there's `ethtool_set_ringparam` from `net/ethtool/ioctl.c`, and `ethnl_set_rings` from `net/ethtool/rings.c`. I'm also including `ethtool_ringparam_set_cfg` from `net/ethtool/common.c`, and `ethnl_default_set_doit` from `net/ethtool/netlink.c`, as these are entrypoints to the interface. I also see modifications in the fbnic driver. Now, fbnic is a potentially hardware-specific driver, but it is calling a number of generic entrypoints that are being fuzzed. Therefore I am focusing on this as well. I'll need to double-check if it's a PCI driver to confirm its portability in the target environment. Regardless, focusing on core ethtool and network entrypoints, coupled with fbnic driver operations like `fbnic_validate_qcfg`, provides a good starting point. |
| 10/2 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "fbnic_driver",
"PathPrefix": "drivers/net/ethernet/meta/fbnic"
}Results: {
"Output": "drivers/net/ethernet/meta/fbnic/fbnic.h=166=static inline bool fbnic_init_failure(struct fbnic_dev *fbd)\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-170-\ndrivers/net/ethernet/meta/fbnic/fbnic.h:171:extern char fbnic_driver_name[];\ndrivers/net/ethernet/meta/fbnic/fbnic.h-172-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_debugfs.c=670=void fbnic_dbg_init(void)\ndrivers/net/ethernet/meta/fbnic/fbnic_debugfs.c-671-{\ndrivers/net/ethernet/meta/fbnic/fbnic_debugfs.c:672:\tfbnic_dbg_root = debugfs_create_dir(fbnic_driver_name, NULL);\ndrivers/net/ethernet/meta/fbnic/fbnic_debugfs.c-673-}\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-15-\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:16:char fbnic_driver_name[] = DRV_NAME;\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-17-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c=259=static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-283-\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:284:\terr = pcim_iomap_regions(pdev, info-\u003ebar_mask, fbnic_driver_name);\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-285-\tif (err) {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c=618=static const struct pci_error_handlers fbnic_err_handler = {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-623-\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:624:static struct pci_driver fbnic_driver = {\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:625:\t.name\t\t= fbnic_driver_name,\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-626-\t.id_table\t= fbnic_pci_tbl,\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c=642=static int __init fbnic_init_module(void)\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-647-\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:648:\terr = pci_register_driver(\u0026fbnic_driver);\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-649-\tif (err) {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-653-\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:654:\tpr_info(DRV_SUMMARY \" (%s)\", fbnic_driver.name);\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-655-out:\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c=665=static void __exit fbnic_exit_module(void)\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-666-{\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c:667:\tpci_unregister_driver(\u0026fbnic_driver);\ndrivers/net/ethernet/meta/fbnic/fbnic_pci.c-668-\n"
} |
| 11/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 34502 output: 24 thoughts: 113 Thoughts: **Analyzing the fbnic PCI Driver** Okay, so the fbnic driver, that's Meta's ASIC's PCI driver, got it. My focus right now is on understanding the core changes within the kernel code. The reachable parts appear to be within `net/core/netdev_config.c`, `net/ethtool/*`, and `net/core/dev.c`. My next step is to nail down the configuration requirements for `net/core/netdev_config.c` and everything under `net/ethtool/*`. I need to figure out the relevant Kconfig options. It looks like the place to start digging would be in `net/ethtool/Kconfig`, or maybe even back in `net/Kconfig` or `net/core/Kconfig`. Time to get into those Kconfig files and see what I can find. |
| 12/2 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "ETHTOOL",
"PathPrefix": "net"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 5655 lines.\nUse more precise expression if possible.\n\nnet/Kconfig=507=config FAILOVER\n--\nnet/Kconfig-519-\nnet/Kconfig:520:config ETHTOOL_NETLINK\nnet/Kconfig-521-\tbool \"Netlink interface for ethtool\"\n--\nnet/bluetooth/af_bluetooth.c=616=static int bt_ethtool_get_ts_info(struct sock *sk, unsigned int index,\n--\nnet/bluetooth/af_bluetooth.c-630-\nnet/bluetooth/af_bluetooth.c:631:\tinfo.cmd = ETHTOOL_GET_TS_INFO;\nnet/bluetooth/af_bluetooth.c-632-\tinfo.so_timestamping = ts_info.so_timestamping;\n--\nnet/bluetooth/af_bluetooth.c=643=static int bt_ethtool(struct sock *sk, const struct ifreq *ifr,\n--\nnet/bluetooth/af_bluetooth.c-657-\tswitch (ethcmd) {\nnet/bluetooth/af_bluetooth.c:658:\tcase ETHTOOL_GET_TS_INFO:\nnet/bluetooth/af_bluetooth.c-659-\t\treturn bt_ethtool_get_ts_info(sk, index, useraddr);\n--\nnet/bluetooth/af_bluetooth.c=665=static int bt_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg)\n--\nnet/bluetooth/af_bluetooth.c-681-\tswitch (cmd) {\nnet/bluetooth/af_bluetooth.c:682:\tcase SIOCETHTOOL:\nnet/bluetooth/af_bluetooth.c-683-\t\tret = bt_ethtool(sk, \u0026ifr, data);\n--\nnet/bluetooth/af_bluetooth.c=696=int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)\n--\nnet/bluetooth/af_bluetooth.c-727-\nnet/bluetooth/af_bluetooth.c:728:\tcase SIOCETHTOOL:\nnet/bluetooth/af_bluetooth.c-729-\t\terr = bt_dev_ioctl(sock, cmd, (void __user *)arg);\n--\nnet/core/dev.c=10334=int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)\n--\nnet/core/dev.c-10338-\nnet/core/dev.c:10339:\tif (dev-\u003ecfg-\u003ehds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED \u0026\u0026\nnet/core/dev.c-10340-\t bpf-\u003ecommand == XDP_SETUP_PROG \u0026\u0026\n--\nnet/core/dev.c=10377=static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,\n--\nnet/core/dev.c-10416-\nnet/core/dev.c:10417:\tif (dev-\u003ecfg-\u003ehds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED \u0026\u0026\nnet/core/dev.c-10418-\t prog \u0026\u0026 !prog-\u003eaux-\u003exdp_has_frags) {\n--\nnet/core/dev_ioctl.c=699=int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,\n--\nnet/core/dev_ioctl.c-748-\nnet/core/dev_ioctl.c:749:\tcase SIOCETHTOOL:\nnet/core/dev_ioctl.c-750-\t\tdev_load(net, ifr-\u003eifr_name);\n--\nnet/core/net-sysfs.c=121=static int sysfs_get_link_ksettings(struct device *dev,\n--\nnet/core/net-sysfs.c-137-\t\t (netdev-\u003eethtool_ops-\u003eop_needs_rtnl \u0026\nnet/core/net-sysfs.c:138:\t\t ETHTOOL_OP_NEEDS_RTNL_LINKSETTINGS);\nnet/core/net-sysfs.c-139-\tif (need_rtnl) {\n--\nnet/core/netdev_rx_queue.c=187=static int __netif_mp_open_rxq(struct net_device *dev, unsigned int rxq_idx,\n--\nnet/core/netdev_rx_queue.c-198-\nnet/core/netdev_rx_queue.c:199:\tif (dev-\u003ecfg-\u003ehds_config != ETHTOOL_TCP_DATA_SPLIT_ENABLED) {\nnet/core/netdev_rx_queue.c-200-\t\tNL_SET_ERR_MSG(extack, \"tcp-data-split is disabled\");\n--\nnet/ethtool/Makefile=3=obj-y\t\t\t\t+= ioctl.o common.o\nnet/ethtool/Makefile-4-\nnet/ethtool/Makefile:5:obj-$(CONFIG_ETHTOOL_NETLINK)\t+= ethtool_nl.o\nnet/ethtool/Makefile-6-\n--\nnet/ethtool/bitset.c=233=int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, const u32 *val,\n--\nnet/ethtool/bitset.c-243-\nnet/ethtool/bitset.c:244:\tif (!mask \u0026\u0026 nla_put_flag(skb, ETHTOOL_A_BITSET_NOMASK))\nnet/ethtool/bitset.c-245-\t\tgoto nla_put_failure;\nnet/ethtool/bitset.c:246:\tif (nla_put_u32(skb, ETHTOOL_A_BITSET_SIZE, nbits))\nnet/ethtool/bitset.c-247-\t\tgoto nla_put_failure;\n--\nnet/ethtool/bitset.c-252-\nnet/ethtool/bitset.c:253:\t\tattr = nla_reserve(skb, ETHTOOL_A_BITSET_VALUE, nbytes);\nnet/ethtool/bitset.c-254-\t\tif (!attr)\n--\nnet/ethtool/bitset.c-261-\t\tif (mask) {\nnet/ethtool/bitset.c:262:\t\t\tattr = nla_reserve(skb, ETHTOOL_A_BITSET_MASK, nbytes);\nnet/ethtool/bitset.c-263-\t\t\tif (!attr)\n--\nnet/ethtool/bitset.c-273-\nnet/ethtool/bitset.c:274:\t\tbits = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS);\nnet/ethtool/bitset.c-275-\t\tif (!bits)\n--\nnet/ethtool/bitset.c-281-\t\t\t\tcontinue;\nnet/ethtool/bitset.c:282:\t\t\tattr = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS_BIT);\nnet/ethtool/bitset.c-283-\t\t\tif (!attr)\nnet/ethtool/bitset.c-284-\t\t\t\tgoto nla_put_failure;\nnet/ethtool/bitset.c:285:\t\t\tif (nla_put_u32(skb, ETHTOOL_A_BITSET_BIT_INDEX, i))\nnet/ethtool/bitset.c-286-\t\t\t\tgoto nla_put_failure;\nnet/ethtool/bitset.c-287-\t\t\tif (name \u0026\u0026\nnet/ethtool/bitset.c:288:\t\t\t ethnl_put_strz(skb, ETHTOOL_A_BITSET_BIT_NAME, name))\nnet/ethtool/bitset.c-289-\t\t\t\tgoto nla_put_failure;\nnet/ethtool/bitset.c-290-\t\t\tif (mask \u0026\u0026 ethnl_bitmap32_test_bit(val, i) \u0026\u0026\nnet/ethtool/bitset.c:291:\t\t\t nla_put_flag(skb, ETHTOOL_A_BITSET_BIT_VALUE))\nnet/ethtool/bitset.c-292-\t\t\t\tgoto nla_put_failure;\n--\nnet/ethtool/bitset.c=306=static const struct nla_policy bitset_policy[] = {\nnet/ethtool/bitset.c:307:\t[ETHTOOL_A_BITSET_NOMASK]\t= { .type = NLA_FLAG },\nnet/ethtool/bitset.c:308:\t[ETHTOOL_A_BITSET_SIZE]\t\t= NLA_POLICY_MAX(NLA_U32,\nnet/ethtool/bitset.c-309-\t\t\t\t\t\t\t ETHNL_MAX_BITSET_SIZE),\nnet/ethtool/bitset.c:310:\t[ETHTOOL_A_BITSET_BITS]\t\t= { .type = NLA_NESTED },\nnet/ethtool/bitset.c:311:\t[ETHTOOL_A_BITSET_VALUE]\t= { .type = NLA_BINARY },\nnet/ethtool/bitset.c:312:\t[ETHTOOL_A_BITSET_MASK]\t\t= { .type = NLA_BINARY },\nnet/ethtool/bitset.c-313-};\n--\nnet/ethtool/bitset.c=315=static const struct nla_policy bit_policy[] = {\nnet/ethtool/bitset.c:316:\t[ETHTOOL_A_BITSET_BIT_INDEX]\t= { .type = NLA_U32 },\nnet/ethtool/bitset.c:317:\t[ETHTOOL_A_BITSET_BIT_NAME]\t= { .type = NLA_NUL_STRING },\nnet/ethtool/bitset.c:318:\t[ETHTOOL_A_BITSET_BIT_VALUE]\t= { .type = NLA_FLAG },\nnet/ethtool/bitset.c-319-};\n--\nnet/ethtool/bitset.c=329=int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact)\n--\nnet/ethtool/bitset.c-338-\nnet/ethtool/bitset.c:339:\tif (tb[ETHTOOL_A_BITSET_BITS]) {\nnet/ethtool/bitset.c:340:\t\tif (tb[ETHTOOL_A_BITSET_VALUE] || tb[ETHTOOL_A_BITSET_MASK])\nnet/ethtool/bitset.c-341-\t\t\treturn -EINVAL;\n--\nnet/ethtool/bitset.c-344-\t}\nnet/ethtool/bitset.c:345:\tif (!tb[ETHTOOL_A_BITSET_SIZE] || !tb[ETHTOOL_A_BITSET_VALUE])\nnet/ethtool/bitset.c-346-\t\treturn -EINVAL;\n--\nnet/ethtool/bitset.c=378=static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,\n--\nnet/ethtool/bitset.c-390-\nnet/ethtool/bitset.c:391:\tif (tb[ETHTOOL_A_BITSET_BIT_INDEX]) {\nnet/ethtool/bitset.c-392-\t\tconst char *name;\nnet/ethtool/bitset.c-393-\nnet/ethtool/bitset.c:394:\t\tidx = nla_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);\nnet/ethtool/bitset.c-395-\t\tif (idx \u003e= nbits) {\nnet/ethtool/bitset.c-396-\t\t\tNL_SET_ERR_MSG_ATTR(extack,\nnet/ethtool/bitset.c:397:\t\t\t\t\t tb[ETHTOOL_A_BITSET_BIT_INDEX],\nnet/ethtool/bitset.c-398-\t\t\t\t\t \"bit index too high\");\n--\nnet/ethtool/bitset.c-401-\t\tname = names ? names[idx] : NULL;\nnet/ethtool/bitset.c:402:\t\tif (tb[ETHTOOL_A_BITSET_BIT_NAME] \u0026\u0026 name \u0026\u0026\nnet/ethtool/bitset.c:403:\t\t strncmp(nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]), name,\nnet/ethtool/bitset.c:404:\t\t\t nla_len(tb[ETHTOOL_A_BITSET_BIT_NAME]))) {\nnet/ethtool/bitset.c-405-\t\t\tNL_SET_ERR_MSG_ATTR(extack, bit_attr,\n--\nnet/ethtool/bitset.c-408-\t\t}\nnet/ethtool/bitset.c:409:\t} else if (tb[ETHTOOL_A_BITSET_BIT_NAME]) {\nnet/ethtool/bitset.c-410-\t\tidx = ethnl_name_to_idx(names, nbits,\nnet/ethtool/bitset.c:411:\t\t\t\t\tnla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]));\nnet/ethtool/bitset.c-412-\t\tif (idx \u003c 0) {\nnet/ethtool/bitset.c-413-\t\t\tNL_SET_ERR_MSG_ATTR(extack,\nnet/ethtool/bitset.c:414:\t\t\t\t\t tb[ETHTOOL_A_BITSET_BIT_NAME],\nnet/ethtool/bitset.c-415-\t\t\t\t\t \"bit name not found\");\n--\nnet/ethtool/bitset.c-424-\t*index = idx;\nnet/ethtool/bitset.c:425:\t*val = no_mask || tb[ETHTOOL_A_BITSET_BIT_VALUE];\nnet/ethtool/bitset.c-426-\treturn 0;\n--\nnet/ethtool/bitset.c=449=ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,\n--\nnet/ethtool/bitset.c-459-\nnet/ethtool/bitset.c:460:\tif (tb[ETHTOOL_A_BITSET_VALUE]) {\nnet/ethtool/bitset.c:461:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],\nnet/ethtool/bitset.c-462-\t\t\t\t \"value only allowed in compact bitset\");\n--\nnet/ethtool/bitset.c-464-\t}\nnet/ethtool/bitset.c:465:\tif (tb[ETHTOOL_A_BITSET_MASK]) {\nnet/ethtool/bitset.c:466:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],\nnet/ethtool/bitset.c-467-\t\t\t\t \"mask only allowed in compact bitset\");\n--\nnet/ethtool/bitset.c-470-\nnet/ethtool/bitset.c:471:\tno_mask = tb[ETHTOOL_A_BITSET_NOMASK];\nnet/ethtool/bitset.c-472-\tif (no_mask) {\n--\nnet/ethtool/bitset.c-486-\nnet/ethtool/bitset.c:487:\tnla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {\nnet/ethtool/bitset.c-488-\t\tbool old_val, new_val;\n--\nnet/ethtool/bitset.c-490-\nnet/ethtool/bitset.c:491:\t\tif (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {\nnet/ethtool/bitset.c-492-\t\t\tNL_SET_ERR_MSG_ATTR(extack, bit_attr,\nnet/ethtool/bitset.c:493:\t\t\t\t\t \"only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS\");\nnet/ethtool/bitset.c-494-\t\t\tkfree(saved_bitmap);\n--\nnet/ethtool/bitset.c=521=static int ethnl_compact_sanity_checks(unsigned int nbits,\n--\nnet/ethtool/bitset.c-525-{\nnet/ethtool/bitset.c:526:\tbool no_mask = tb[ETHTOOL_A_BITSET_NOMASK];\nnet/ethtool/bitset.c-527-\tunsigned int attr_nbits, attr_nwords;\n--\nnet/ethtool/bitset.c-529-\nnet/ethtool/bitset.c:530:\tif (no_mask \u0026\u0026 tb[ETHTOOL_A_BITSET_MASK]) {\nnet/ethtool/bitset.c:531:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],\nnet/ethtool/bitset.c-532-\t\t\t\t \"mask not allowed in list bitset\");\n--\nnet/ethtool/bitset.c-534-\t}\nnet/ethtool/bitset.c:535:\tif (!tb[ETHTOOL_A_BITSET_SIZE]) {\nnet/ethtool/bitset.c-536-\t\tNL_SET_ERR_MSG_ATTR(extack, nest,\n--\nnet/ethtool/bitset.c-539-\t}\nnet/ethtool/bitset.c:540:\tif (!tb[ETHTOOL_A_BITSET_VALUE]) {\nnet/ethtool/bitset.c-541-\t\tNL_SET_ERR_MSG_ATTR(extack, nest,\n--\nnet/ethtool/bitset.c-544-\t}\nnet/ethtool/bitset.c:545:\tif (!no_mask \u0026\u0026 !tb[ETHTOOL_A_BITSET_MASK]) {\nnet/ethtool/bitset.c-546-\t\tNL_SET_ERR_MSG_ATTR(extack, nest,\n--\nnet/ethtool/bitset.c-550-\nnet/ethtool/bitset.c:551:\tattr_nbits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);\nnet/ethtool/bitset.c-552-\tattr_nwords = DIV_ROUND_UP(attr_nbits, 32);\nnet/ethtool/bitset.c:553:\tif (nla_len(tb[ETHTOOL_A_BITSET_VALUE]) != attr_nwords * sizeof(u32)) {\nnet/ethtool/bitset.c:554:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],\nnet/ethtool/bitset.c-555-\t\t\t\t \"bitset value length does not match size\");\n--\nnet/ethtool/bitset.c-557-\t}\nnet/ethtool/bitset.c:558:\tif (tb[ETHTOOL_A_BITSET_MASK] \u0026\u0026\nnet/ethtool/bitset.c:559:\t nla_len(tb[ETHTOOL_A_BITSET_MASK]) != attr_nwords * sizeof(u32)) {\nnet/ethtool/bitset.c:560:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],\nnet/ethtool/bitset.c-561-\t\t\t\t \"bitset mask length does not match size\");\n--\nnet/ethtool/bitset.c-566-\nnet/ethtool/bitset.c:567:\ttest_attr = no_mask ? tb[ETHTOOL_A_BITSET_VALUE] :\nnet/ethtool/bitset.c:568:\t\t\t tb[ETHTOOL_A_BITSET_MASK];\nnet/ethtool/bitset.c-569-\tif (ethnl_bitmap32_not_zero(nla_data(test_attr), nbits, attr_nbits)) {\n--\nnet/ethtool/bitset.c=593=int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,\n--\nnet/ethtool/bitset.c-608-\nnet/ethtool/bitset.c:609:\tif (tb[ETHTOOL_A_BITSET_BITS])\nnet/ethtool/bitset.c-610-\t\treturn ethnl_update_bitset32_verbose(bitmap, nbits, attr, tb,\n--\nnet/ethtool/bitset.c-615-\nnet/ethtool/bitset.c:616:\tno_mask = tb[ETHTOOL_A_BITSET_NOMASK];\nnet/ethtool/bitset.c-617-\tchange_bits = min_t(unsigned int,\nnet/ethtool/bitset.c:618:\t\t\t nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]), nbits);\nnet/ethtool/bitset.c-619-\tethnl_bitmap32_update(bitmap, change_bits,\nnet/ethtool/bitset.c:620:\t\t\t nla_data(tb[ETHTOOL_A_BITSET_VALUE]),\nnet/ethtool/bitset.c-621-\t\t\t no_mask ? NULL :\nnet/ethtool/bitset.c:622:\t\t\t\t\tnla_data(tb[ETHTOOL_A_BITSET_MASK]),\nnet/ethtool/bitset.c-623-\t\t\t mod);\n--\nnet/ethtool/bitset.c=645=int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,\n--\nnet/ethtool/bitset.c-661-\t\treturn ret;\nnet/ethtool/bitset.c:662:\tno_mask = tb[ETHTOOL_A_BITSET_NOMASK];\nnet/ethtool/bitset.c-663-\nnet/ethtool/bitset.c:664:\tif (!tb[ETHTOOL_A_BITSET_BITS]) {\nnet/ethtool/bitset.c-665-\t\tunsigned int change_bits;\n--\nnet/ethtool/bitset.c-670-\nnet/ethtool/bitset.c:671:\t\tchange_bits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);\nnet/ethtool/bitset.c-672-\t\tif (change_bits \u003e nbits)\nnet/ethtool/bitset.c-673-\t\t\tchange_bits = nbits;\nnet/ethtool/bitset.c:674:\t\tbitmap_from_arr32(val, nla_data(tb[ETHTOOL_A_BITSET_VALUE]),\nnet/ethtool/bitset.c-675-\t\t\t\t change_bits);\n--\nnet/ethtool/bitset.c-681-\t\t\tbitmap_from_arr32(mask,\nnet/ethtool/bitset.c:682:\t\t\t\t\t nla_data(tb[ETHTOOL_A_BITSET_MASK]),\nnet/ethtool/bitset.c-683-\t\t\t\t\t change_bits);\n--\nnet/ethtool/bitset.c-691-\nnet/ethtool/bitset.c:692:\tif (tb[ETHTOOL_A_BITSET_VALUE]) {\nnet/ethtool/bitset.c:693:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],\nnet/ethtool/bitset.c-694-\t\t\t\t \"value only allowed in compact bitset\");\n--\nnet/ethtool/bitset.c-696-\t}\nnet/ethtool/bitset.c:697:\tif (tb[ETHTOOL_A_BITSET_MASK]) {\nnet/ethtool/bitset.c:698:\t\tNL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],\nnet/ethtool/bitset.c-699-\t\t\t\t \"mask only allowed in compact bitset\");\n--\nnet/ethtool/bitset.c-708-\nnet/ethtool/bitset.c:709:\tnla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {\nnet/ethtool/bitset.c-710-\t\tunsigned int idx;\n--\nnet/ethtool/bitset.h-2-\nnet/ethtool/bitset.h:3:#ifndef _NET_ETHTOOL_BITSET_H\nnet/ethtool/bitset.h:4:#define _NET_ETHTOOL_BITSET_H\nnet/ethtool/bitset.h-5-\n--\nnet/ethtool/bitset.h=32=int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,\n--\nnet/ethtool/bitset.h-36-\nnet/ethtool/bitset.h:37:#endif /* _NET_ETHTOOL_BITSET_H */\n--\nnet/ethtool/cabletest.c=16=const struct nla_policy ethnl_cable_test_act_policy[] = {\nnet/ethtool/cabletest.c:17:\t[ETHTOOL_A_CABLE_TEST_HEADER]\t\t=\nnet/ethtool/cabletest.c-18-\t\tNLA_POLICY_NESTED(ethnl_header_policy_phy),\n--\nnet/ethtool/cabletest.c=21=static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)\n--\nnet/ethtool/cabletest.c-37-\terr = ethnl_fill_reply_header(skb, phydev-\u003eattached_dev,\nnet/ethtool/cabletest.c:38:\t\t\t\t ETHTOOL_A_CABLE_TEST_NTF_HEADER);\nnet/ethtool/cabletest.c-39-\tif (err)\n--\nnet/ethtool/cabletest.c-41-\nnet/ethtool/cabletest.c:42:\terr = nla_put_u8(skb, ETHTOOL_A_CABLE_TEST_NTF_STATUS,\nnet/ethtool/cabletest.c:43:\t\t\t ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED);\nnet/ethtool/cabletest.c-44-\tif (err)\n--\nnet/ethtool/cabletest.c=58=int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)\n--\nnet/ethtool/cabletest.c-67-\tret = ethnl_parse_header_dev_get(\u0026req_info,\nnet/ethtool/cabletest.c:68:\t\t\t\t\t tb[ETHTOOL_A_CABLE_TEST_HEADER],\nnet/ethtool/cabletest.c-69-\t\t\t\t\t genl_info_net(info), info-\u003eextack,\n--\nnet/ethtool/cabletest.c-77-\tphydev = ethnl_req_get_phydev(\u0026req_info, tb,\nnet/ethtool/cabletest.c:78:\t\t\t\t ETHTOOL_A_CABLE_TEST_HEADER,\nnet/ethtool/cabletest.c-79-\t\t\t\t info-\u003eextack);\n--\nnet/ethtool/cabletest.c-99-\tif (!ret)\nnet/ethtool/cabletest.c:100:\t\tethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);\nnet/ethtool/cabletest.c-101-\n--\nnet/ethtool/cabletest.c=108=int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)\n--\nnet/ethtool/cabletest.c-125-\terr = ethnl_fill_reply_header(phydev-\u003eskb, phydev-\u003eattached_dev,\nnet/ethtool/cabletest.c:126:\t\t\t\t ETHTOOL_A_CABLE_TEST_NTF_HEADER);\nnet/ethtool/cabletest.c-127-\tif (err)\n--\nnet/ethtool/cabletest.c-129-\nnet/ethtool/cabletest.c:130:\terr = nla_put_u8(phydev-\u003eskb, ETHTOOL_A_CABLE_TEST_NTF_STATUS,\nnet/ethtool/cabletest.c:131:\t\t\t ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED);\nnet/ethtool/cabletest.c-132-\tif (err)\n--\nnet/ethtool/cabletest.c-135-\tphydev-\u003enest = nla_nest_start(phydev-\u003eskb,\nnet/ethtool/cabletest.c:136:\t\t\t\t ETHTOOL_A_CABLE_TEST_NTF_NEST);\nnet/ethtool/cabletest.c-137-\tif (!phydev-\u003enest) {\n--\nnet/ethtool/cabletest.c=168=int ethnl_cable_test_result_with_src(struct phy_device *phydev, u8 pair,\n--\nnet/ethtool/cabletest.c-173-\nnet/ethtool/cabletest.c:174:\tnest = nla_nest_start(phydev-\u003eskb, ETHTOOL_A_CABLE_NEST_RESULT);\nnet/ethtool/cabletest.c-175-\tif (!nest)\n--\nnet/ethtool/cabletest.c-177-\nnet/ethtool/cabletest.c:178:\tif (nla_put_u8(phydev-\u003eskb, ETHTOOL_A_CABLE_RESULT_PAIR, pair))\nnet/ethtool/cabletest.c-179-\t\tgoto err;\nnet/ethtool/cabletest.c:180:\tif (nla_put_u8(phydev-\u003eskb, ETHTOOL_A_CABLE_RESULT_CODE, result))\nnet/ethtool/cabletest.c-181-\t\tgoto err;\nnet/ethtool/cabletest.c:182:\tif (src != ETHTOOL_A_CABLE_INF_SRC_UNSPEC) {\nnet/ethtool/cabletest.c:183:\t\tif (nla_put_u32(phydev-\u003eskb, ETHTOOL_A_CABLE_RESULT_SRC, src))\nnet/ethtool/cabletest.c-184-\t\t\tgoto err;\n--\nnet/ethtool/cabletest.c=196=int ethnl_cable_test_fault_length_with_src(struct phy_device *phydev, u8 pair,\n--\nnet/ethtool/cabletest.c-202-\tnest = nla_nest_start(phydev-\u003eskb,\nnet/ethtool/cabletest.c:203:\t\t\t ETHTOOL_A_CABLE_NEST_FAULT_LENGTH);\nnet/ethtool/cabletest.c-204-\tif (!nest)\n--\nnet/ethtool/cabletest.c-206-\nnet/ethtool/cabletest.c:207:\tif (nla_put_u8(phydev-\u003eskb, ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR, pair))\nnet/ethtool/cabletest.c-208-\t\tgoto err;\nnet/ethtool/cabletest.c:209:\tif (nla_put_u32(phydev-\u003eskb, ETHTOOL_A_CABLE_FAULT_LENGTH_CM, cm))\nnet/ethtool/cabletest.c-210-\t\tgoto err;\nnet/ethtool/cabletest.c:211:\tif (src != ETHTOOL_A_CABLE_INF_SRC_UNSPEC) {\nnet/ethtool/cabletest.c:212:\t\tif (nla_put_u32(phydev-\u003eskb, ETHTOOL_A_CABLE_FAULT_LENGTH_SRC,\nnet/ethtool/cabletest.c-213-\t\t\t\tsrc))\n--\nnet/ethtool/cabletest.c=226=static const struct nla_policy cable_test_tdr_act_cfg_policy[] = {\nnet/ethtool/cabletest.c:227:\t[ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST]\t= { .type = NLA_U32 },\nnet/ethtool/cabletest.c:228:\t[ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST]\t= { .type = NLA_U32 },\nnet/ethtool/cabletest.c:229:\t[ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP]\t= { .type = NLA_U32 },\nnet/ethtool/cabletest.c:230:\t[ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR]\t= { .type = NLA_U8 },\nnet/ethtool/cabletest.c-231-};\n--\nnet/ethtool/cabletest.c=233=const struct nla_policy ethnl_cable_test_tdr_act_policy[] = {\nnet/ethtool/cabletest.c:234:\t[ETHTOOL_A_CABLE_TEST_TDR_HEADER]\t=\nnet/ethtool/cabletest.c-235-\t\tNLA_POLICY_NESTED(ethnl_header_policy_phy),\nnet/ethtool/cabletest.c:236:\t[ETHTOOL_A_CABLE_TEST_TDR_CFG]\t\t= { .type = NLA_NESTED },\nnet/ethtool/cabletest.c-237-};\n--\nnet/ethtool/cabletest.c=240=static int ethnl_act_cable_test_tdr_cfg(const struct nlattr *nest,\n--\nnet/ethtool/cabletest.c-261-\nnet/ethtool/cabletest.c:262:\tif (tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST])\nnet/ethtool/cabletest.c-263-\t\tcfg-\u003efirst = nla_get_u32(\nnet/ethtool/cabletest.c:264:\t\t\ttb[ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST]);\nnet/ethtool/cabletest.c-265-\nnet/ethtool/cabletest.c:266:\tif (tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST])\nnet/ethtool/cabletest.c:267:\t\tcfg-\u003elast = nla_get_u32(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST]);\nnet/ethtool/cabletest.c-268-\nnet/ethtool/cabletest.c:269:\tif (tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP])\nnet/ethtool/cabletest.c:270:\t\tcfg-\u003estep = nla_get_u32(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP]);\nnet/ethtool/cabletest.c-271-\nnet/ethtool/cabletest.c:272:\tif (tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR]) {\nnet/ethtool/cabletest.c:273:\t\tcfg-\u003epair = nla_get_u8(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR]);\nnet/ethtool/cabletest.c:274:\t\tif (cfg-\u003epair \u003e ETHTOOL_A_CABLE_PAIR_D) {\nnet/ethtool/cabletest.c-275-\t\t\tNL_SET_ERR_MSG_ATTR(\nnet/ethtool/cabletest.c-276-\t\t\t\tinfo-\u003eextack,\nnet/ethtool/cabletest.c:277:\t\t\t\ttb[ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR],\nnet/ethtool/cabletest.c-278-\t\t\t\t\"invalid pair parameter\");\n--\nnet/ethtool/cabletest.c-284-\t\tNL_SET_ERR_MSG_ATTR(info-\u003eextack,\nnet/ethtool/cabletest.c:285:\t\t\t\t tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST],\nnet/ethtool/cabletest.c-286-\t\t\t\t \"invalid first parameter\");\n--\nnet/ethtool/cabletest.c-291-\t\tNL_SET_ERR_MSG_ATTR(info-\u003eextack,\nnet/ethtool/cabletest.c:292:\t\t\t\t tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST],\nnet/ethtool/cabletest.c-293-\t\t\t\t \"invalid last parameter\");\n--\nnet/ethtool/cabletest.c-303-\t\tNL_SET_ERR_MSG_ATTR(info-\u003eextack,\nnet/ethtool/cabletest.c:304:\t\t\t\t tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP],\nnet/ethtool/cabletest.c-305-\t\t\t\t \"invalid step parameter\");\n--\nnet/ethtool/cabletest.c-310-\t\tNL_SET_ERR_MSG_ATTR(info-\u003eextack,\nnet/ethtool/cabletest.c:311:\t\t\t\t tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP],\nnet/ethtool/cabletest.c-312-\t\t\t\t \"step parameter too big\");\n--\nnet/ethtool/cabletest.c=319=int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)\n--\nnet/ethtool/cabletest.c-329-\tret = ethnl_parse_header_dev_get(\u0026req_info,\nnet/ethtool/cabletest.c:330:\t\t\t\t\t tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],\nnet/ethtool/cabletest.c-331-\t\t\t\t\t genl_info_net(info), info-\u003eextack,\n--\nnet/ethtool/cabletest.c-337-\nnet/ethtool/cabletest.c:338:\tret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG],\nnet/ethtool/cabletest.c-339-\t\t\t\t\t info, \u0026cfg);\n--\nnet/ethtool/cabletest.c-344-\tphydev = ethnl_req_get_phydev(\u0026req_info, tb,\nnet/ethtool/cabletest.c:345:\t\t\t\t ETHTOOL_A_CABLE_TEST_TDR_HEADER,\nnet/ethtool/cabletest.c-346-\t\t\t\t info-\u003eextack);\n--\nnet/ethtool/cabletest.c-367-\t\tethnl_cable_test_started(phydev,\nnet/ethtool/cabletest.c:368:\t\t\t\t\t ETHTOOL_MSG_CABLE_TEST_TDR_NTF);\nnet/ethtool/cabletest.c-369-\n--\nnet/ethtool/cabletest.c=377=int ethnl_cable_test_amplitude(struct phy_device *phydev,\n--\nnet/ethtool/cabletest.c-383-\tnest = nla_nest_start(phydev-\u003eskb,\nnet/ethtool/cabletest.c:384:\t\t\t ETHTOOL_A_CABLE_TDR_NEST_AMPLITUDE);\nnet/ethtool/cabletest.c-385-\tif (!nest)\n--\nnet/ethtool/cabletest.c-387-\nnet/ethtool/cabletest.c:388:\tif (nla_put_u8(phydev-\u003eskb, ETHTOOL_A_CABLE_AMPLITUDE_PAIR, pair))\nnet/ethtool/cabletest.c-389-\t\tgoto err;\nnet/ethtool/cabletest.c:390:\tif (nla_put_u16(phydev-\u003eskb, ETHTOOL_A_CABLE_AMPLITUDE_mV, mV))\nnet/ethtool/cabletest.c-391-\t\tgoto err;\n--\nnet/ethtool/cabletest.c=402=int ethnl_cable_test_pulse(struct phy_device *phydev, u16 mV)\n--\nnet/ethtool/cabletest.c-406-\nnet/ethtool/cabletest.c:407:\tnest = nla_nest_start(phydev-\u003eskb, ETHTOOL_A_CABLE_TDR_NEST_PULSE);\nnet/ethtool/cabletest.c-408-\tif (!nest)\n--\nnet/ethtool/cabletest.c-410-\nnet/ethtool/cabletest.c:411:\tif (nla_put_u16(phydev-\u003eskb, ETHTOOL_A_CABLE_PULSE_mV, mV))\nnet/ethtool/cabletest.c-412-\t\tgoto err;\n--\nnet/ethtool/cabletest.c=423=int ethnl_cable_test_step(struct phy_device *phydev, u32 first, u32 last,\n--\nnet/ethtool/cabletest.c-428-\nnet/ethtool/cabletest.c:429:\tnest = nla_nest_start(phydev-\u003eskb, ETHTOOL_A_CABLE_TDR_NEST_STEP);\nnet/ethtool/cabletest.c-430-\tif (!nest)\n--\nnet/ethtool/cabletest.c-432-\nnet/ethtool/cabletest.c:433:\tif (nla_put_u32(phydev-\u003eskb, ETHTOOL_A_CABLE_STEP_FIRST_DISTANCE,\nnet/ethtool/cabletest.c-434-\t\t\tfirst))\n--\nnet/ethtool/cabletest.c-436-\nnet/ethtool/cabletest.c:437:\tif (nla_put_u32(phydev-\u003eskb, ETHTOOL_A_CABLE_STEP_LAST_DISTANCE, last))\nnet/ethtool/cabletest.c-438-\t\tgoto err;\nnet/ethtool/cabletest.c-439-\nnet/ethtool/cabletest.c:440:\tif (nla_put_u32(phydev-\u003eskb, ETHTOOL_A_CABLE_STEP_STEP_DISTANCE, step))\nnet/ethtool/cabletest.c-441-\t\tgoto err;\n--\nnet/ethtool/channels.c=20=const struct nla_policy ethnl_channels_get_policy[] = {\nnet/ethtool/channels.c:21:\t[ETHTOOL_A_CHANNELS_HEADER]\t\t=\nnet/ethtool/channels.c-22-\t\tNLA_POLICY_NESTED(ethnl_header_policy),\n--\nnet/ethtool/channels.c=57=static int channels_fill_reply(struct sk_buff *skb,\n--\nnet/ethtool/channels.c-64-\tif ((channels-\u003emax_rx \u0026\u0026\nnet/ethtool/channels.c:65:\t (nla_put_u32(skb, ETHTOOL_A_CHANNELS_RX_MAX,\nnet/ethtool/channels.c-66-\t\t\t channels-\u003emax_rx) ||\nnet/ethtool/channels.c:67:\t nla_put_u32(skb, ETHTOOL_A_CHANNELS_RX_COUNT,\nnet/ethtool/channels.c-68-\t\t\t channels-\u003erx_count))) ||\nnet/ethtool/channels.c-69-\t (channels-\u003emax_tx \u0026\u0026\nnet/ethtool/channels.c:70:\t (nla_put_u32(skb, ETHTOOL_A_CHANNELS_TX_MAX,\nnet/ethtool/channels.c-71-\t\t\t channels-\u003emax_tx) ||\nnet/ethtool/channels.c:72:\t nla_put_u32(skb, ETHTOOL_A_CHANNELS_TX_COUNT,\nnet/ethtool/channels.c-73-\t\t\t channels-\u003etx_count))) ||\nnet/ethtool/channels.c-74-\t (channels-\u003emax_other \u0026\u0026\nnet/ethtool/channels.c:75:\t (nla_put_u32(skb, ETHTOOL_A_CHANNELS_OTHER_MAX,\nnet/ethtool/channels.c-76-\t\t\t channels-\u003emax_other) ||\nnet/ethtool/channels.c:77:\t nla_put_u32(skb, ETHTOOL_A_CHANNELS_OTHER_COUNT,\nnet/ethtool/channels.c-78-\t\t\t channels-\u003eother_count))) ||\nnet/ethtool/channels.c-79-\t (channels-\u003emax_combined \u0026\u0026\nnet/ethtool/channels.c:80:\t (nla_put_u32(skb, ETHTOOL_A_CHANNELS_COMBINED_MAX,\nnet/ethtool/channels.c-81-\t\t\t channels-\u003emax_combined) ||\nnet/ethtool/channels.c:82:\t nla_put_u32(skb, ETHTOOL_A_CHANNELS_COMBINED_COUNT,\nnet/ethtool/channels.c-83-\t\t\t channels-\u003ecombined_count))))\n--\nnet/ethtool/channels.c=91=const struct nla_policy ethnl_channels_set_policy[] = {\nnet/ethtool/channels.c:92:\t[ETHTOOL_A_CHANNELS_HEADER]\t\t=\nnet/ethtool/channels.c-93-\t\tNLA_POLICY_NESTED(ethnl_header_policy),\nnet/ethtool/channels.c:94:\t[ETHTOOL_A_CHANNELS_RX_COUNT]\t\t= { .type = NLA_U32 },\nnet/ethtool/channels.c:95:\t[ETHTOOL_A_CHANNELS_TX_COUNT]\t\t= { .type = NLA_U32 },\nnet/ethtool/channels.c:96:\t[ETHTOOL_A_CHANNELS_OTHER_COUNT]\t= { .type = NLA_U32 },\nnet/ethtool/channels.c:97:\t[ETHTOOL_A_CHANNELS_COMBINED_COUNT]\t= { .type = NLA_U32 },\nnet/ethtool/channels.c-98-};\n--\nnet/ethtool/channels.c=110=ethnl_set_channels(struct ethnl_req_info *req_info, struct genl_info *info)\n--\n\n"
} |
| 13/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 47071 output: 32 thoughts: 19 Thoughts: **Examining `net/Kconfig` for `ETHTOOL_NETLINK`** Okay, let's dive into `net/Kconfig`. I need to figure out the configuration options around `ETHTOOL_NETLINK`. I'm guessing this means I need to understand how the netlink interface for ethtool is controlled, or perhaps which features depend on it. This is probably related to newer network management functionalities, potentially in the context of hardware offload or advanced device configuration. I anticipate finding conditionals or dependencies here that link `ETHTOOL_NETLINK` to other features, likely within the networking subsystem. My goal is to understand how this flag impacts the build and if any other configs should be evaluated in conjunction. |
| 14/2 | 2026/09/10 19:37 | tool | read-file |
0mArgs:{
"File": "net/Kconfig",
"FirstLine": 515,
"LineCount": 20
}Results: {
"Contents": " 515:\t\t failover netdev. This enables paravirtual drivers to use a\n 516:\t\t VF as an accelerated low latency datapath. It also allows live\n 517:\t\t migration of VMs with direct attached VFs by failing over to the\n 518:\t\t paravirtual datapath when the VF is unplugged.\n 519:\t\n 520:\tconfig ETHTOOL_NETLINK\n 521:\t\tbool \"Netlink interface for ethtool\"\n 522:\t\tselect DIMLIB\n 523:\t\tdefault y\n 524:\t\thelp\n 525:\t\t An alternative userspace interface for ethtool based on generic\n 526:\t\t netlink. It provides better extensibility and some new features,\n 527:\t\t e.g. notification messages.\n 528:\t\n 529:\tconfig NETDEV_ADDR_LIST_TEST\n 530:\t\ttristate \"Unit tests for device address list\"\n 531:\t\tdefault KUNIT_ALL_TESTS\n 532:\t\tdepends on KUNIT\n 533:\t\n 534:\tconfig NET_TEST\n"
} |
| 15/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 47578 output: 31 thoughts: 60 Thoughts: **Examining the Kernel Networking Landscape** Alright, let's dive in. First, I need to verify how these components are configured. My immediate focus is on `ETHTOOL_NETLINK` and the broader `NET` subsystem. I already know that `NET` represents the core networking infrastructure; that's fundamental. And I recall that `CONFIG_ETHTOOL_NETLINK` is the key to enabling that ethtool netlink interface. Now, the question is, does the fbnic driver have its own associated Kconfig option? Let's investigate that. |
| 16/2 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "FBNIC",
"PathPrefix": "drivers/net/ethernet/meta"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 7344 lines.\nUse more precise expression if possible.\n\ndrivers/net/ethernet/meta/Kconfig=18=if NET_VENDOR_META\ndrivers/net/ethernet/meta/Kconfig-19-\ndrivers/net/ethernet/meta/Kconfig:20:config FBNIC\ndrivers/net/ethernet/meta/Kconfig-21-\ttristate \"Meta Platforms Host Network Interface\"\n--\ndrivers/net/ethernet/meta/Makefile-5-\ndrivers/net/ethernet/meta/Makefile:6:obj-$(CONFIG_FBNIC) += fbnic/\n--\ndrivers/net/ethernet/meta/fbnic/Makefile-7-\ndrivers/net/ethernet/meta/fbnic/Makefile:8:obj-$(CONFIG_FBNIC) += fbnic.o\ndrivers/net/ethernet/meta/fbnic/Makefile-9-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-3-\ndrivers/net/ethernet/meta/fbnic/fbnic.h:4:#ifndef _FBNIC_H_\ndrivers/net/ethernet/meta/fbnic/fbnic.h:5:#define _FBNIC_H_\ndrivers/net/ethernet/meta/fbnic/fbnic.h-6-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h=20=struct fbnic_napi_vector;\ndrivers/net/ethernet/meta/fbnic/fbnic.h-21-\ndrivers/net/ethernet/meta/fbnic/fbnic.h:22:#define FBNIC_MAX_NAPI_VECTORS\t\t128u\ndrivers/net/ethernet/meta/fbnic/fbnic.h:23:#define FBNIC_MBX_CMPL_SLOTS\t\t4\ndrivers/net/ethernet/meta/fbnic/fbnic.h-24-\ndrivers/net/ethernet/meta/fbnic/fbnic.h=25=struct fbnic_dev {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-42-\t\tchar name[IFNAMSIZ + 9];\ndrivers/net/ethernet/meta/fbnic/fbnic.h:43:\t} napi_irq[FBNIC_MAX_NAPI_VECTORS];\ndrivers/net/ethernet/meta/fbnic/fbnic.h-44-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-46-\ndrivers/net/ethernet/meta/fbnic/fbnic.h:47:\tstruct fbnic_fw_mbx mbx[FBNIC_IPC_MBX_INDICES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h-48-\tstruct fbnic_fw_cap fw_cap;\ndrivers/net/ethernet/meta/fbnic/fbnic.h:49:\tstruct fbnic_fw_completion *cmpl_data[FBNIC_MBX_CMPL_SLOTS];\ndrivers/net/ethernet/meta/fbnic/fbnic.h-50-\t/* Lock protecting Tx Mailbox queue to prevent possible races */\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-62-\t/* Local copy of the devices TCAM */\ndrivers/net/ethernet/meta/fbnic/fbnic.h:63:\tstruct fbnic_act_tcam act_tcam[FBNIC_RPC_TCAM_ACT_NUM_ENTRIES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h:64:\tstruct fbnic_mac_addr mac_addr[FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h-65-\tu8 mac_addr_boundary;\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-68-\t/* IP TCAM */\ndrivers/net/ethernet/meta/fbnic/fbnic.h:69:\tstruct fbnic_ip_addr ip_src[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h:70:\tstruct fbnic_ip_addr ip_dst[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h:71:\tstruct fbnic_ip_addr ipo_src[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h:72:\tstruct fbnic_ip_addr ipo_dst[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES];\ndrivers/net/ethernet/meta/fbnic/fbnic.h-73-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h=112=enum {\ndrivers/net/ethernet/meta/fbnic/fbnic.h:113:\tFBNIC_FW_MSIX_ENTRY,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:114:\tFBNIC_PCS_MSIX_ENTRY,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:115:\tFBNIC_NON_NAPI_VECTORS\ndrivers/net/ethernet/meta/fbnic/fbnic.h-116-};\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h=133=static inline void fbnic_wrfl(struct fbnic_dev *fbd)\ndrivers/net/ethernet/meta/fbnic/fbnic.h-134-{\ndrivers/net/ethernet/meta/fbnic/fbnic.h:135:\tfbnic_rd32(fbd, FBNIC_MASTER_SPARE_0);\ndrivers/net/ethernet/meta/fbnic/fbnic.h-136-}\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h=155=void fbnic_fw_wr32(struct fbnic_dev *fbd, u32 reg, u32 val);\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-158-#define fw_wr32(_f, _r, _v)\tfbnic_fw_wr32(_f, _r, _v)\ndrivers/net/ethernet/meta/fbnic/fbnic.h:159:#define fw_wrfl(_f)\t\tfbnic_fw_rd32(_f, FBNIC_FW_ZERO_REG)\ndrivers/net/ethernet/meta/fbnic/fbnic.h-160-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h=200=void fbnic_free_irq(struct fbnic_dev *dev, int nr, void *data);\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-208- *\ndrivers/net/ethernet/meta/fbnic/fbnic.h:209: * @FBNIC_TEST_MSIX_SUCCESS: no errors\ndrivers/net/ethernet/meta/fbnic/fbnic.h:210: * @FBNIC_TEST_MSIX_NOMEM: allocation failure\ndrivers/net/ethernet/meta/fbnic/fbnic.h:211: * @FBNIC_TEST_MSIX_IRQ_REQ_FAIL: IRQ request failure\ndrivers/net/ethernet/meta/fbnic/fbnic.h:212: * @FBNIC_TEST_MSIX_MASK: masking failed to prevent IRQ\ndrivers/net/ethernet/meta/fbnic/fbnic.h:213: * @FBNIC_TEST_MSIX_UNMASK: unmasking failure w/ sw status set\ndrivers/net/ethernet/meta/fbnic/fbnic.h:214: * @FBNIC_TEST_MSIX_IRQ_CLEAR: interrupt when clearing mask\ndrivers/net/ethernet/meta/fbnic/fbnic.h:215: * @FBNIC_TEST_MSIX_NO_INTERRUPT: no interrupt when not masked\ndrivers/net/ethernet/meta/fbnic/fbnic.h:216: * @FBNIC_TEST_MSIX_NO_CLEAR_OR_MASK: status not cleared, or mask not set\ndrivers/net/ethernet/meta/fbnic/fbnic.h:217: * @FBNIC_TEST_MSIX_BITS_SET_AFTER_TEST: Bits are set after test\ndrivers/net/ethernet/meta/fbnic/fbnic.h-218- */\ndrivers/net/ethernet/meta/fbnic/fbnic.h=219=enum fbnic_msix_self_test_codes {\ndrivers/net/ethernet/meta/fbnic/fbnic.h:220:\tFBNIC_TEST_MSIX_SUCCESS = 0,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:221:\tFBNIC_TEST_MSIX_NOMEM = 5,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:222:\tFBNIC_TEST_MSIX_IRQ_REQ_FAIL = 10,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:223:\tFBNIC_TEST_MSIX_MASK = 20,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:224:\tFBNIC_TEST_MSIX_UNMASK = 30,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:225:\tFBNIC_TEST_MSIX_IRQ_CLEAR = 40,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:226:\tFBNIC_TEST_MSIX_NO_INTERRUPT = 50,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:227:\tFBNIC_TEST_MSIX_NO_CLEAR_OR_MASK = 60,\ndrivers/net/ethernet/meta/fbnic/fbnic.h:228:\tFBNIC_TEST_MSIX_BITS_SET_AFTER_TEST = 70,\ndrivers/net/ethernet/meta/fbnic/fbnic.h-229-};\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h=258=struct fbnic_info {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic.h-262-\ndrivers/net/ethernet/meta/fbnic/fbnic.h:263:#endif /* _FBNIC_H_ */\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-5-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:6:#define FBNIC_BOUNDS(section) { \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:7:\t.start = FBNIC_CSR_START_##section, \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:8:\t.end = FBNIC_CSR_END_##section + 1, \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-9-}\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c=16=static const struct fbnic_csr_bounds fbnic_csr_sects[] = {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:17:\tFBNIC_BOUNDS(INTR),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:18:\tFBNIC_BOUNDS(INTR_CQ),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:19:\tFBNIC_BOUNDS(QM_TX),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:20:\tFBNIC_BOUNDS(QM_RX),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:21:\tFBNIC_BOUNDS(TCE),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:22:\tFBNIC_BOUNDS(TCE_RAM),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:23:\tFBNIC_BOUNDS(TMI),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:24:\tFBNIC_BOUNDS(PTP),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:25:\tFBNIC_BOUNDS(RXB),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:26:\tFBNIC_BOUNDS(RPC),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:27:\tFBNIC_BOUNDS(FAB),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:28:\tFBNIC_BOUNDS(MASTER),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:29:\tFBNIC_BOUNDS(PCS),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:30:\tFBNIC_BOUNDS(RSFEC),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:31:\tFBNIC_BOUNDS(MAC_MAC),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:32:\tFBNIC_BOUNDS(SIG),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:33:\tFBNIC_BOUNDS(PCIE_SS_COMPHY),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:34:\tFBNIC_BOUNDS(PUL_USER),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:35:\tFBNIC_BOUNDS(QUEUE),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:36:\tFBNIC_BOUNDS(RPC_RAM),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-37-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-38-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:39:#define FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY\t\t\t14\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:40:#define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES\t\t\t64\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-41-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:42:#define FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY\t\t4\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:43:#define FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES\t\t32\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-44-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:45:#define FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY\t\t9\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:46:#define FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-47-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:48:#define FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY\t\t9\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:49:#define FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-50-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:51:#define FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY\t\t9\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:52:#define FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-53-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:54:#define FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY\t\t9\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:55:#define FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-56-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:57:#define FBNIC_RPC_RSS_TBL_DW_PER_ENTRY\t\t\t2\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:58:#define FBNIC_RPC_RSS_TBL_NUM_ENTRIES\t\t\t256\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-59-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c=60=static void fbnic_csr_get_regs_rpc_ram(struct fbnic_dev *fbd, u32 **data_p)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-61-{\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:62:\tu32 start = FBNIC_CSR_START_RPC_RAM;\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:63:\tu32 end = FBNIC_CSR_END_RPC_RAM;\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-64-\tu32 *data = *data_p;\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-69-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:70:\t/* FBNIC_RPC_TCAM_ACT */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:71:\tfor (i = 0; i \u003c FBNIC_RPC_TCAM_ACT_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:72:\t\tfor (j = 0; j \u003c FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:73:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_TCAM_ACT(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-74-\t}\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-75-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:76:\t/* FBNIC_RPC_TCAM_MACDA */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:77:\tfor (i = 0; i \u003c FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:78:\t\tfor (j = 0; j \u003c FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:79:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_TCAM_MACDA(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-80-\t}\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-81-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:82:\t/* FBNIC_RPC_TCAM_OUTER_IPSRC */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:83:\tfor (i = 0; i \u003c FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:84:\t\tfor (j = 0; j \u003c FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:85:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-86-\t}\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-87-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:88:\t/* FBNIC_RPC_TCAM_OUTER_IPDST */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:89:\tfor (i = 0; i \u003c FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:90:\t\tfor (j = 0; j \u003c FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:91:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-92-\t}\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-93-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:94:\t/* FBNIC_RPC_TCAM_IPSRC */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:95:\tfor (i = 0; i \u003c FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:96:\t\tfor (j = 0; j \u003c FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:97:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPSRC(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-98-\t}\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-99-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:100:\t/* FBNIC_RPC_TCAM_IPDST */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:101:\tfor (i = 0; i \u003c FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:102:\t\tfor (j = 0; j \u003c FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:103:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPDST(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-104-\t}\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-105-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:106:\t/* FBNIC_RPC_RSS_TBL */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:107:\tfor (i = 0; i \u003c FBNIC_RPC_RSS_TBL_NUM_ENTRIES; i++) {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:108:\t\tfor (j = 0; j \u003c FBNIC_RPC_RSS_TBL_DW_PER_ENTRY; j++)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:109:\t\t\t*(data++) = rd32(fbd, FBNIC_RPC_RSS_TBL(i, j));\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-110-\t}\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c=159=struct fbnic_csr_reg_test_data {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-166-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:167:#define FBNIC_QUEUE_REG_TEST(_name, _read, _write) { \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:168:\t.reg = FBNIC_QUEUE(0) + FBNIC_QUEUE_##_name, \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:169:\t.reg_offset = FBNIC_QUEUE_STRIDE, \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-170-\t.array_len = 64, \\\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c=175=static const struct fbnic_csr_reg_test_data pattern_test[] = {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:176:\tFBNIC_QUEUE_REG_TEST(TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:177:\t\t\t FBNIC_QUEUE_TWQ_CTL_RESET),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:178:\tFBNIC_QUEUE_REG_TEST(TWQ0_PTRS, 0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:179:\tFBNIC_QUEUE_REG_TEST(TWQ0_SIZE, FBNIC_QUEUE_TWQ_SIZE_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:180:\tFBNIC_QUEUE_REG_TEST(TWQ0_BAL, FBNIC_QUEUE_BAL_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:181:\tFBNIC_QUEUE_REG_TEST(TWQ0_BAH, ~0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:182:\tFBNIC_QUEUE_REG_TEST(TWQ1_CTL, FBNIC_QUEUE_TWQ_CTL_RESET,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:183:\t\t\t FBNIC_QUEUE_TWQ_CTL_RESET),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:184:\tFBNIC_QUEUE_REG_TEST(TWQ1_PTRS, 0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:185:\tFBNIC_QUEUE_REG_TEST(TWQ1_SIZE, FBNIC_QUEUE_TWQ_SIZE_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:186:\tFBNIC_QUEUE_REG_TEST(TWQ1_BAL, FBNIC_QUEUE_BAL_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:187:\tFBNIC_QUEUE_REG_TEST(TWQ1_BAH, ~0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:188:\tFBNIC_QUEUE_REG_TEST(TCQ_CTL, FBNIC_QUEUE_TCQ_CTL_RESET,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:189:\t\t\t FBNIC_QUEUE_TCQ_CTL_RESET),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:190:\tFBNIC_QUEUE_REG_TEST(TCQ_PTRS, 0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:191:\tFBNIC_QUEUE_REG_TEST(TCQ_SIZE, FBNIC_QUEUE_TCQ_SIZE_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:192:\tFBNIC_QUEUE_REG_TEST(TCQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:193:\tFBNIC_QUEUE_REG_TEST(TCQ_BAH, ~0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:194:\tFBNIC_QUEUE_REG_TEST(RCQ_CTL, FBNIC_QUEUE_RCQ_CTL_RESET,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:195:\t\t\t FBNIC_QUEUE_RCQ_CTL_RESET),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:196:\tFBNIC_QUEUE_REG_TEST(RCQ_PTRS, 0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:197:\tFBNIC_QUEUE_REG_TEST(RCQ_SIZE, FBNIC_QUEUE_RCQ_SIZE_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:198:\tFBNIC_QUEUE_REG_TEST(RCQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:199:\tFBNIC_QUEUE_REG_TEST(RCQ_BAH, ~0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:200:\tFBNIC_QUEUE_REG_TEST(BDQ_CTL, FBNIC_QUEUE_BDQ_CTL_RESET,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:201:\t\t\t FBNIC_QUEUE_BDQ_CTL_RESET),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:202:\tFBNIC_QUEUE_REG_TEST(BDQ_HPQ_PTRS, 0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:203:\tFBNIC_QUEUE_REG_TEST(BDQ_HPQ_SIZE, FBNIC_QUEUE_BDQ_SIZE_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:204:\tFBNIC_QUEUE_REG_TEST(BDQ_HPQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:205:\tFBNIC_QUEUE_REG_TEST(BDQ_HPQ_BAH, ~0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:206:\tFBNIC_QUEUE_REG_TEST(BDQ_PPQ_PTRS, 0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:207:\tFBNIC_QUEUE_REG_TEST(BDQ_PPQ_SIZE, FBNIC_QUEUE_BDQ_SIZE_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:208:\tFBNIC_QUEUE_REG_TEST(BDQ_PPQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:209:\tFBNIC_QUEUE_REG_TEST(BDQ_PPQ_BAH, ~0, ~0),\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-210-};\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c=213=fbnic_csr_reg_pattern_test(struct fbnic_dev *fbd, int index,\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-235-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:236:\t\t/* Note that FBNIC_INTR_STATUS(0) could be tested and fail\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-237-\t\t * and the result would not be reported since the register\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-243-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:244:\treturn FBNIC_REG_TEST_SUCCESS;\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-245-}\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-256- *\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:257: * Return: FBNIC_REG_TEST_SUCCESS on success, register number on failure\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-258- **/\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c=259=enum fbnic_reg_self_test_codes fbnic_csr_regs_test(struct fbnic_dev *fbd)\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-275-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c:276:\treturn FBNIC_REG_TEST_SUCCESS;\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.c-277-}\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-3-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:4:#ifndef _FBNIC_CSR_H_\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:5:#define _FBNIC_CSR_H_\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-6-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h=9=struct fbnic_dev;\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-17-#define FW_VER_CODE(_major, _minor, _patch, _build) (\t\t \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:18:\t\tFIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_MAJOR, _major) | \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:19:\t\tFIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_MINOR, _minor) | \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:20:\t\tFIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_PATCH, _patch) | \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:21:\t\tFIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_BUILD, _build))\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-22-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-39-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:40:#define PCI_DEVICE_ID_META_FBNIC_ASIC\t\t0x0013\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-41-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:42:#define FBNIC_CLOCK_FREQ\t(600 * (1000 * 1000))\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-43-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-45-/* Length, Type, Offset Masks and Shifts */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:46:#define FBNIC_TWD_L2_HLEN_MASK\t\t\tDESC_GENMASK(5, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-47-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:48:#define FBNIC_TWD_L3_TYPE_MASK\t\t\tDESC_GENMASK(7, 6)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-49-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:50:\tFBNIC_TWD_L3_TYPE_OTHER\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:51:\tFBNIC_TWD_L3_TYPE_IPV4\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:52:\tFBNIC_TWD_L3_TYPE_IPV6\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:53:\tFBNIC_TWD_L3_TYPE_V6V6\t= 3,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-54-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-55-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:56:#define FBNIC_TWD_L3_OHLEN_MASK\t\t\tDESC_GENMASK(15, 8)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:57:#define FBNIC_TWD_L3_IHLEN_MASK\t\t\tDESC_GENMASK(23, 16)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-58-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h=59=enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:60:\tFBNIC_TWD_L4_TYPE_OTHER\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:61:\tFBNIC_TWD_L4_TYPE_TCP\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:62:\tFBNIC_TWD_L4_TYPE_UDP\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-63-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-64-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:65:#define FBNIC_TWD_CSUM_OFFSET_MASK\t\tDESC_GENMASK(27, 24)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:66:#define FBNIC_TWD_L4_HLEN_MASK\t\t\tDESC_GENMASK(31, 28)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-67-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-68-/* Flags and Type */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:69:#define FBNIC_TWD_L4_TYPE_MASK\t\t\tDESC_GENMASK(33, 32)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:70:#define FBNIC_TWD_FLAG_REQ_TS\t\t\tDESC_BIT(34)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:71:#define FBNIC_TWD_FLAG_REQ_LSO\t\t\tDESC_BIT(35)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:72:#define FBNIC_TWD_FLAG_REQ_CSO\t\t\tDESC_BIT(36)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:73:#define FBNIC_TWD_FLAG_REQ_COMPLETION\t\tDESC_BIT(37)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:74:#define FBNIC_TWD_FLAG_DEST_MAC\t\t\tDESC_BIT(43)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:75:#define FBNIC_TWD_FLAG_DEST_BMC\t\t\tDESC_BIT(44)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:76:#define FBNIC_TWD_FLAG_DEST_FW\t\t\tDESC_BIT(45)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:77:#define FBNIC_TWD_TYPE_MASK\t\t\tDESC_GENMASK(47, 46)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-78-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:79:\tFBNIC_TWD_TYPE_META\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:80:\tFBNIC_TWD_TYPE_OPT_META\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:81:\tFBNIC_TWD_TYPE_AL\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:82:\tFBNIC_TWD_TYPE_LAST_AL\t= 3,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-83-};\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-85-/* MSS and Completion Req */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:86:#define FBNIC_TWD_MSS_MASK\t\t\tDESC_GENMASK(61, 48)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-87-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:88:#define FBNIC_TWD_TS_MASK\t\t\tDESC_GENMASK(39, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:89:#define FBNIC_TWD_ADDR_MASK\t\t\tDESC_GENMASK(45, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:90:#define FBNIC_TWD_LEN_MASK\t\t\tDESC_GENMASK(63, 48)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-91-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-92-/* Tx Completion Descriptor Format */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:93:#define FBNIC_TCD_TYPE0_HEAD0_MASK\t\tDESC_GENMASK(15, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:94:#define FBNIC_TCD_TYPE0_HEAD1_MASK\t\tDESC_GENMASK(31, 16)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-95-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:96:#define FBNIC_TCD_TYPE1_TS_MASK\t\t\tDESC_GENMASK(39, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-97-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:98:#define FBNIC_TCD_STATUS_MASK\t\t\tDESC_GENMASK(59, 48)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:99:#define FBNIC_TCD_STATUS_TS_INVALID\t\tDESC_BIT(48)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:100:#define FBNIC_TCD_STATUS_ILLEGAL_TS_REQ\t\tDESC_BIT(49)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:101:#define FBNIC_TCD_TWQ1\t\t\t\tDESC_BIT(60)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:102:#define FBNIC_TCD_TYPE_MASK\t\t\tDESC_GENMASK(62, 61)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-103-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:104:\tFBNIC_TCD_TYPE_0\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:105:\tFBNIC_TCD_TYPE_1\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-106-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-107-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:108:#define FBNIC_TCD_DONE\t\t\t\tDESC_BIT(63)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-109-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-120- */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:121:#define FBNIC_BD_DESC_ADDR_MASK\t\t\tDESC_GENMASK(45, 12)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:122:#define FBNIC_BD_DESC_ID_MASK\t\t\tDESC_GENMASK(63, 48)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:123:#define FBNIC_BD_PAGE_SIZE \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:124:\t(FBNIC_BD_DESC_ADDR_MASK \u0026 ~(FBNIC_BD_DESC_ADDR_MASK - 1))\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-125-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-126-/* Rx Completion Queue Descriptors */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:127:#define FBNIC_RCD_TYPE_MASK\t\t\tDESC_GENMASK(62, 61)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-128-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:129:\tFBNIC_RCD_TYPE_HDR_AL\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:130:\tFBNIC_RCD_TYPE_PAY_AL\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:131:\tFBNIC_RCD_TYPE_OPT_META\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:132:\tFBNIC_RCD_TYPE_META\t= 3,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-133-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-134-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:135:#define FBNIC_RCD_DONE\t\t\t\tDESC_BIT(63)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-136-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-137-/* Address/Length Completion Descriptors */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:138:#define FBNIC_RCD_AL_BUFF_ID_MASK\t\tDESC_GENMASK(15, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:139:#define FBNIC_RCD_AL_BUFF_LEN_MASK\t\tDESC_GENMASK(28, 16)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:140:#define FBNIC_RCD_AL_BUFF_OFF_MASK\t\tDESC_GENMASK(43, 32)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:141:#define FBNIC_RCD_AL_PAGE_FIN\t\t\tDESC_BIT(60)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-142-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-143-/* Header AL specific values */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:144:#define FBNIC_RCD_HDR_AL_OVERFLOW\t\tDESC_BIT(53)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:145:#define FBNIC_RCD_HDR_AL_DMA_HINT_MASK\t\tDESC_GENMASK(59, 54)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-146-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:147:\tFBNIC_RCD_HDR_AL_DMA_HINT_NONE = 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:148:\tFBNIC_RCD_HDR_AL_DMA_HINT_L2\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:149:\tFBNIC_RCD_HDR_AL_DMA_HINT_L3\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:150:\tFBNIC_RCD_HDR_AL_DMA_HINT_L4\t= 4,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-151-};\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-153-/* Optional Metadata Completion Descriptors */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:154:#define FBNIC_RCD_OPT_META_TS_MASK\t\tDESC_GENMASK(39, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:155:#define FBNIC_RCD_OPT_META_ACTION_MASK\t\tDESC_GENMASK(45, 40)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:156:#define FBNIC_RCD_OPT_META_ACTION\t\tDESC_BIT(57)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:157:#define FBNIC_RCD_OPT_META_TS\t\t\tDESC_BIT(58)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:158:#define FBNIC_RCD_OPT_META_TYPE_MASK\t\tDESC_GENMASK(60, 59)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-159-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-160-/* Metadata Completion Descriptors */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:161:#define FBNIC_RCD_META_RSS_HASH_MASK\t\tDESC_GENMASK(31, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:162:#define FBNIC_RCD_META_L2_CSUM_MASK\t\tDESC_GENMASK(47, 32)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:163:#define FBNIC_RCD_META_L3_TYPE_MASK\t\tDESC_GENMASK(49, 48)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-164-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:165:\tFBNIC_RCD_META_L3_TYPE_OTHER\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:166:\tFBNIC_RCD_META_L3_TYPE_IPV4\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:167:\tFBNIC_RCD_META_L3_TYPE_IPV6\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:168:\tFBNIC_RCD_META_L3_TYPE_V6V6\t= 3,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-169-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-170-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:171:#define FBNIC_RCD_META_L4_TYPE_MASK\t\tDESC_GENMASK(51, 50)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-172-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:173:\tFBNIC_RCD_META_L4_TYPE_OTHER\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:174:\tFBNIC_RCD_META_L4_TYPE_TCP\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:175:\tFBNIC_RCD_META_L4_TYPE_UDP\t= 2,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-176-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-177-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:178:#define FBNIC_RCD_META_L4_CSUM_UNNECESSARY\tDESC_BIT(52)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:179:#define FBNIC_RCD_META_ERR_MAC_EOP\t\tDESC_BIT(53)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:180:#define FBNIC_RCD_META_ERR_TRUNCATED_FRAME\tDESC_BIT(54)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:181:#define FBNIC_RCD_META_ERR_PARSER\t\tDESC_BIT(55)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:182:#define FBNIC_RCD_META_UNCORRECTABLE_ERR_MASK\t\\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:183:\t(FBNIC_RCD_META_ERR_MAC_EOP | FBNIC_RCD_META_ERR_TRUNCATED_FRAME)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:184:#define FBNIC_RCD_META_ECN\t\t\tDESC_BIT(60)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-185-\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-194-/* Interrupt Registers */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:195:#define FBNIC_CSR_START_INTR\t\t0x00000\t/* CSR section delimiter */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:196:#define FBNIC_INTR_STATUS(n)\t\t(0x00000 + (n))\t/* 0x00000 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:197:#define FBNIC_INTR_STATUS_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:198:#define FBNIC_INTR_MASK(n)\t\t(0x00008 + (n)) /* 0x00020 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:199:#define FBNIC_INTR_MASK_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:200:#define FBNIC_INTR_SET(n)\t\t(0x00010 + (n))\t/* 0x00040 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:201:#define FBNIC_INTR_SET_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:202:#define FBNIC_INTR_CLEAR(n)\t\t(0x00018 + (n))\t/* 0x00060 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:203:#define FBNIC_INTR_CLEAR_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:204:#define FBNIC_INTR_SW_STATUS(n)\t\t(0x00020 + (n)) /* 0x00080 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:205:#define FBNIC_INTR_SW_STATUS_CNT\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:206:#define FBNIC_INTR_SW_AC_MODE(n)\t(0x00028 + (n)) /* 0x000a0 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:207:#define FBNIC_INTR_SW_AC_MODE_CNT\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:208:#define FBNIC_INTR_MASK_SET(n)\t\t(0x00030 + (n)) /* 0x000c0 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:209:#define FBNIC_INTR_MASK_SET_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:210:#define FBNIC_INTR_MASK_CLEAR(n)\t(0x00038 + (n)) /* 0x000e0 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:211:#define FBNIC_INTR_MASK_CLEAR_CNT\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:212:#define FBNIC_MAX_MSIX_VECS\t\t256U\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:213:#define FBNIC_INTR_MSIX_CTRL(n)\t\t(0x00040 + (n)) /* 0x00100 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:214:#define FBNIC_INTR_MSIX_CTRL_VECTOR_MASK\tCSR_GENMASK(7, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:215:#define FBNIC_INTR_MSIX_CTRL_ENABLE\t\tCSR_BIT(31)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-216-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:217:\tFBNIC_INTR_MSIX_CTRL_RXB_IDX\t= 7,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:218:\tFBNIC_INTR_MSIX_CTRL_PCS_IDX\t= 34,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-219-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-220-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:221:#define FBNIC_CSR_END_INTR\t\t0x0005f\t/* CSR section delimiter */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-222-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-223-/* Interrupt MSIX Registers */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:224:#define FBNIC_CSR_START_INTR_CQ\t\t0x00400\t/* CSR section delimiter */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:225:#define FBNIC_INTR_CQ_REARM(n) \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-226-\t\t\t\t(0x00400 + 4 * (n))\t/* 0x01000 + 16*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:227:#define FBNIC_INTR_CQ_REARM_CNT\t\t\t256\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:228:#define FBNIC_INTR_CQ_REARM_RCQ_TIMEOUT\t\tCSR_GENMASK(13, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:229:#define FBNIC_INTR_CQ_REARM_RCQ_TIMEOUT_UPD_EN\tCSR_BIT(14)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:230:#define FBNIC_INTR_CQ_REARM_TCQ_TIMEOUT\t\tCSR_GENMASK(28, 15)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:231:#define FBNIC_INTR_CQ_REARM_TCQ_TIMEOUT_UPD_EN\tCSR_BIT(29)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:232:#define FBNIC_INTR_CQ_REARM_INTR_RELOAD\t\tCSR_BIT(30)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:233:#define FBNIC_INTR_CQ_REARM_INTR_UNMASK\t\tCSR_BIT(31)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-234-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:235:#define FBNIC_INTR_RCQ_TIMEOUT(n) \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-236-\t\t\t\t(0x00401 + 4 * (n))\t/* 0x01004 + 16*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:237:#define FBNIC_INTR_RCQ_TIMEOUT_CNT\t\t256\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:238:#define FBNIC_INTR_TCQ_TIMEOUT(n) \\\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-239-\t\t\t\t(0x00402 + 4 * (n))\t/* 0x01008 + 16*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:240:#define FBNIC_INTR_TCQ_TIMEOUT_CNT\t\t256\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:241:#define FBNIC_CSR_END_INTR_CQ\t\t0x007fe\t/* CSR section delimiter */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-242-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-243-/* Global QM Tx registers */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:244:#define FBNIC_CSR_START_QM_TX\t\t0x00800\t/* CSR section delimiter */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:245:#define FBNIC_QM_TWQ_IDLE(n)\t\t(0x00800 + (n)) /* 0x02000 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:246:#define FBNIC_QM_TWQ_IDLE_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:247:#define FBNIC_QM_TWQ_DEFAULT_META_L\t0x00818\t\t/* 0x02060 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:248:#define FBNIC_QM_TWQ_DEFAULT_META_H\t0x00819\t\t/* 0x02064 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-249-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:250:#define FBNIC_QM_TQS_CTL0\t\t0x0081b\t\t/* 0x0206c */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:251:#define FBNIC_QM_TQS_CTL0_LSO_TS_MASK\tCSR_BIT(0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-252-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:253:\tFBNIC_QM_TQS_CTL0_LSO_TS_FIRST\t= 0,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:254:\tFBNIC_QM_TQS_CTL0_LSO_TS_LAST\t= 1,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-255-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-256-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:257:#define FBNIC_QM_TQS_CTL0_PREFETCH_THRESH\tCSR_GENMASK(7, 1)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-258-enum {\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:259:\tFBNIC_QM_TQS_CTL0_PREFETCH_THRESH_MIN\t= 16,\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-260-};\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h-261-\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:262:#define FBNIC_QM_TQS_CTL1\t\t0x0081c\t\t/* 0x02070 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:263:#define FBNIC_QM_TQS_CTL1_MC_MAX_CREDITS\tCSR_GENMASK(7, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:264:#define FBNIC_QM_TQS_CTL1_BULK_MAX_CREDITS\tCSR_GENMASK(15, 8)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:265:#define FBNIC_QM_TQS_MTU_CTL0\t\t0x0081d\t\t/* 0x02074 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:266:#define FBNIC_QM_TQS_MTU_CTL1\t\t0x0081e\t\t/* 0x02078 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:267:#define FBNIC_QM_TQS_MTU_CTL1_BULK\t\tCSR_GENMASK(13, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:268:#define FBNIC_QM_TCQ_IDLE(n)\t\t(0x00821 + (n)) /* 0x02084 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:269:#define FBNIC_QM_TCQ_IDLE_CNT\t\t\t4\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:270:#define FBNIC_QM_TCQ_CTL0\t\t0x0082d\t\t/* 0x020b4 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:271:#define FBNIC_QM_TCQ_CTL0_COAL_WAIT\t\tCSR_GENMASK(15, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:272:#define FBNIC_QM_TCQ_CTL0_TICK_CYCLES\t\tCSR_GENMASK(26, 16)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:273:#define FBNIC_QM_TQS_IDLE(n)\t\t(0x00830 + (n)) /* 0x020c0 + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:274:#define FBNIC_QM_TQS_IDLE_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:275:#define FBNIC_QM_TQS_EDT_TS_RANGE\t0x00849\t\t/* 0x2124 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:276:#define FBNIC_QM_TDE_IDLE(n)\t\t(0x00853 + (n)) /* 0x0214c + 4*n */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:277:#define FBNIC_QM_TDE_IDLE_CNT\t\t\t8\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:278:#define FBNIC_QM_TNI_TDF_CTL\t\t0x0086c\t\t/* 0x021b0 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:279:#define FBNIC_QM_TNI_TDF_CTL_MRRS\t\tCSR_GENMASK(1, 0)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:280:#define FBNIC_QM_TNI_TDF_CTL_CLS\t\tCSR_GENMASK(3, 2)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:281:#define FBNIC_QM_TNI_TDF_CTL_MAX_OT\t\tCSR_GENMASK(11, 4)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:282:#define FBNIC_QM_TNI_TDF_CTL_MAX_OB\t\tCSR_GENMASK(23, 12)\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:283:#define FBNIC_QM_TNI_TDE_CTL\t\t0x0086d\t\t/* 0x021b4 */\ndrivers/net/ethernet/meta/fbnic/fbnic_csr.h:284:#define FBNIC_QM_TNI_TDE_CTL_MRRS\t\tCSR_GENMASK(1, 0)\n\n"
} |
| 17/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 66484 output: 37 thoughts: 17 Thoughts: Here's a summary of my thought process, as requested: **Kconfig Dive** Okay, time to get started. My first instinct is to zero in on the `drivers/net/ethernet/meta/Kconfig` file. I'm guessing this `meta` directory likely contains the top-level configuration options related to Ethernet drivers. Considering my understanding of the system's architecture, this is the logical place to begin my investigation into how Ethernet drivers are configured within this build system. This `Kconfig` file should give me a good overview of the available choices, dependencies, and any overarching configuration parameters that govern the Ethernet subsystems. From there, I can drill down as needed. |
| 18/2 | 2026/09/10 19:37 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/meta/Kconfig",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t#\n 3:\t# Meta Platforms network device configuration\n 4:\t#\n 5:\t\n 6:\tconfig NET_VENDOR_META\n 7:\t\tbool \"Meta Platforms devices\"\n 8:\t\tdefault y\n 9:\t\thelp\n 10:\t\t If you have a network (Ethernet) card designed by Meta, say Y.\n 11:\t\t That's Meta as in the parent company of Facebook.\n 12:\t\n 13:\t\t Note that the answer to this question doesn't directly affect the\n 14:\t\t kernel: saying N will just cause the configurator to skip all\n 15:\t\t the questions about Meta cards. If you say Y, you will be asked for\n 16:\t\t your specific card in the following questions.\n 17:\t\n 18:\tif NET_VENDOR_META\n 19:\t\n 20:\tconfig FBNIC\n 21:\t\ttristate \"Meta Platforms Host Network Interface\"\n 22:\t\tdepends on 64BIT || COMPILE_TEST\n 23:\t\tdepends on !S390\n 24:\t\tdepends on MAX_SKB_FRAGS \u003c 22\n 25:\t\tdepends on PCI_MSI\n 26:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n 27:\t\tselect NET_DEVLINK\n 28:\t\tselect PAGE_POOL\n 29:\t\tselect PCS_XPCS\n 30:\t\tselect PHYLINK\n 31:\t\tselect PLDMFW\n 32:\t\thelp\n 33:\t\t This driver supports Meta Platforms Host Network Interface.\n 34:\t\n 35:\t\t To compile this driver as a module, choose M here. The module\n 36:\t\t will be called fbnic. MSI-X interrupt support is required.\n 37:\t\n 38:\tendif # NET_VENDOR_META\n"
} |
| 19/2 | 2026/09/10 19:37 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 67180 output: 270 thoughts: 1122 Thoughts: **Analyzing Reachable Code for Fuzzing** Okay, let's break this down for fuzzing. My initial focus is on identifying the relevant configuration options. Clearly, we need `NET` for standard networking functionality. Then, `ETHTOOL_NETLINK` is essential because the netlink changes in `net/ethtool` are a key area. Now, I want to confirm if there are any *other* config dependencies. I'm seeing that code in `net/core/netdev_config.c`, `net/ethtool/ioctl.c`, and `net/ethtool/common.c` is always compiled if `NET` is set. However, `net/ethtool/rings.c` and `net/ethtool/netlink.c` are dependent on `ETHTOOL_NETLINK`. Next, I need to pinpoint the specific symbols that are the entry points. Here's what I've identified from the code: - `netdev_alloc_config`, `netdev_free_config`, `netdev_reconfig_start`, `netdev_queue_config_revalidate` in `net/core/netdev_config.c` - `ethtool_ringparam_set_cfg` in `net/ethtool/common.c` - `ethtool_set_ringparam` in `net/ethtool/ioctl.c` - `ethnl_set_rings` in `net/ethtool/rings.c` Okay, let's analyze the importance of these symbols. `netdev_alloc_config` is called during device allocation using `alloc_netdev_mqs`. While netdev allocation is ubiquitous, I believe it's more of a lifecycle function. Other functions, `netdev_reconfig_start`, `netdev_queue_config_revalidate`, `ethtool_ringparam_set_cfg`, `ethtool_set_ringparam`, `ethnl_set_rings`, are very specific entry points into feature logic. We should absolutely include those. `netdev_alloc_config` and `netdev_free_config`, are also important. I'm thinking, are there any other symbols in `net/core/` and `net/ethtool/` that need to be considered? Let's check `net/core/dev.c`. I see `alloc_netdev_mqs` and `free_netdev` but they are generic. Let's focus on the helper functions `netdev_alloc_config` and `netdev_free_config` in `net/core/netdev_config.c`. `netdev_qcfg_apply_dev` in `net/core/netdev_config.c` is static. That means we should exclude this function. But `netdev_queue_config_revalidate` is exported and non-static, so we keep that. So, here's my reasoning, distilled: This patch touches networking core code and the ethtool ioctl *and* netlink handlers, along with driver code. This represents changes to fundamental aspects of how we manage network device queues and ring configuration. This is accomplished with new transaction tracking mechanisms (`netdev_reconfig_start`, `netdev_queue_config_revalidate`, `netdev_alloc_config`, `netdev_free_config`). These core paths are exposed to userspace through both ioctls and netlink, as well as the standard allocation/deallocation process. Therefore, these code modifications are definitely reachable and *need* fuzzing. To be clear, the required configs are: - `NET` - `ETHTOOL_NETLINK` Now, that's done, and all is good. Let's send those results. |
| 20/2 | 2026/09/10 19:37 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"NET",
"ETHTOOL_NETLINK"
],
"FocusSymbols": [
"netdev_reconfig_start",
"netdev_queue_config_revalidate",
"netdev_alloc_config",
"netdev_free_config",
"ethtool_ringparam_set_cfg",
"ethtool_set_ringparam",
"ethnl_set_rings"
],
"Reasoning": "The patch series modifies core networking configuration logic (net/core/dev.c, net/core/netdev_config.c) and ethtool ring parameter interfaces (net/ethtool/ioctl.c, net/ethtool/rings.c, net/ethtool/common.c) in addition to the fbnic driver. It refactors ring and queue configuration lifecycle management, adds transaction-based configuration validation helpers (netdev_reconfig_start, netdev_queue_config_revalidate), and includes state assertions (WARN_ON). These code paths are directly reachable from userspace via SIOCETHTOOL ioctl commands and Ethtool generic Netlink messages on any netdevice, making them worth fuzzing.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"NET",
"ETHTOOL_NETLINK"
],
"FocusSymbols": [
"netdev_reconfig_start",
"netdev_queue_config_revalidate",
"netdev_alloc_config",
"netdev_free_config",
"ethtool_ringparam_set_cfg",
"ethtool_set_ringparam",
"ethnl_set_rings"
],
"Reasoning": "The patch series modifies core networking configuration logic (net/core/dev.c, net/core/netdev_config.c) and ethtool ring parameter interfaces (net/ethtool/ioctl.c, net/ethtool/rings.c, net/ethtool/common.c) in addition to the fbnic driver. It refactors ring and queue configuration lifecycle management, adds transaction-based configuration validation helpers (netdev_reconfig_start, netdev_queue_config_revalidate), and includes state assertions (WARN_ON). These code paths are directly reachable from userspace via SIOCETHTOOL ioctl commands and Ethtool generic Netlink messages on any netdevice, making them worth fuzzing.",
"WorthFuzzing": true
} |
| 21/1 | 2026/09/10 19:37 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 22/2 | 2026/09/10 19:37 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch series adds netdev queue configuration tracking for ring sizes (storing accepted ring sizes in dev-\u003ecfg/dev-\u003ecfg_pending and validating queue configurations upon ring changes) and implements multi-page RX buffer descriptor support in the Meta fbnic driver.\n\n- Memory Initialization: All newly allocated kernel objects (dev-\u003ecfg via kzalloc_obj in netdev_alloc_config and cloned via kmemdup in netdev_reconfig_start) and stack structures (qcfg in __netdev_queue_config) are explicitly zero-initialized using kzalloc/kmemdup/memset prior to usage.\n- User-Kernel Boundary: No uninitialized kernel struct fields or padding bytes are exposed to user space. Ethtool notifications and ioctls use existing initialized data paths.\n- Driver Logic: Changes in fbnic modify descriptor indexing, page offset calculations, and ring sizing logic based on bd_page_shift. Any boundary or calculation errors here would involve out-of-bounds ring accesses or DMA descriptor management, which are detectable by KASAN or hardware/driver assertions, rather than reads of uninitialized memory.\n\nBecause no uninitialized memory risks or info-leaks are introduced or exposed, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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 99bc766fcd57eaf682f9ea8903f89d67ab31862b
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Sep 10 19:37:00 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
index 64b958df77744..2b9f8644b132d 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
@@ -109,34 +109,19 @@ enum {
/* Rx Buffer Descriptor Format
*
- * The layout of this can vary depending on the page size of the system.
+ * Buffer descriptors describe 4 KiB device pages. A posted page larger than
+ * 4 KiB is represented by consecutive device-page descriptors.
*
- * If the page size is 4K then the layout will simply consist of ID for
- * the 16 most significant bits, and the lower 46 are essentially the page
- * address with the lowest 12 bits being reserved 0 due to the fact that
- * a page will be aligned.
- *
- * If the page size is larger than 4K then the lower n bits of the ID and
- * page address will be reserved for the fragment ID. This fragment will
- * be 4K in size and will be used to index both the DMA address and the ID
- * by the same amount.
+ * The address field stores the 4 KiB-aligned DMA address. The ID field stores
+ * the software page ID, with the low n bits used as the device-page ID when a
+ * posted page spans multiple device pages. The driver increments both the
+ * address and ID by one device page for each descriptor belonging to a posted
+ * page.
*/
#define FBNIC_BD_DESC_ADDR_MASK DESC_GENMASK(45, 12)
#define FBNIC_BD_DESC_ID_MASK DESC_GENMASK(63, 48)
-#define FBNIC_BD_FRAG_SIZE \
+#define FBNIC_BD_PAGE_SIZE \
(FBNIC_BD_DESC_ADDR_MASK & ~(FBNIC_BD_DESC_ADDR_MASK - 1))
-#define FBNIC_BD_FRAG_COUNT \
- (PAGE_SIZE / FBNIC_BD_FRAG_SIZE)
-#define FBNIC_BD_FRAG_ADDR_MASK \
- (FBNIC_BD_DESC_ADDR_MASK & \
- ~(FBNIC_BD_DESC_ADDR_MASK * FBNIC_BD_FRAG_COUNT))
-#define FBNIC_BD_FRAG_ID_MASK \
- (FBNIC_BD_DESC_ID_MASK & \
- ~(FBNIC_BD_DESC_ID_MASK * FBNIC_BD_FRAG_COUNT))
-#define FBNIC_BD_PAGE_ADDR_MASK \
- (FBNIC_BD_DESC_ADDR_MASK & ~FBNIC_BD_FRAG_ADDR_MASK)
-#define FBNIC_BD_PAGE_ID_MASK \
- (FBNIC_BD_DESC_ID_MASK & ~FBNIC_BD_FRAG_ID_MASK)
/* Rx Completion Queue Descriptors */
#define FBNIC_RCD_TYPE_MASK DESC_GENMASK(62, 61)
@@ -151,9 +136,6 @@ enum {
/* Address/Length Completion Descriptors */
#define FBNIC_RCD_AL_BUFF_ID_MASK DESC_GENMASK(15, 0)
-#define FBNIC_RCD_AL_BUFF_FRAG_MASK (FBNIC_BD_FRAG_COUNT - 1)
-#define FBNIC_RCD_AL_BUFF_PAGE_MASK \
- (FBNIC_RCD_AL_BUFF_ID_MASK & ~FBNIC_RCD_AL_BUFF_FRAG_MASK)
#define FBNIC_RCD_AL_BUFF_LEN_MASK DESC_GENMASK(28, 16)
#define FBNIC_RCD_AL_BUFF_OFF_MASK DESC_GENMASK(43, 32)
#define FBNIC_RCD_AL_PAGE_FIN DESC_BIT(60)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
index 3c4563c8f403f..7f23a0f97e637 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
@@ -181,8 +181,8 @@ static int fbnic_dbg_tcq_desc_seq_show(struct seq_file *s, void *v)
static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)
{
struct fbnic_ring *ring = s->private;
+ unsigned int i, desc_count;
char hdr[80];
- int i;
/* Generate header on first entry */
fbnic_dbg_ring_show(s);
@@ -197,7 +197,8 @@ static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)
return 0;
}
- for (i = 0; i < (ring->size_mask + 1) * FBNIC_BD_FRAG_COUNT; i++) {
+ desc_count = (ring->size_mask + 1) * fbnic_bd_page_count(ring);
+ for (i = 0; i < desc_count; i++) {
u64 bd = le64_to_cpu(ring->desc[i]);
seq_printf(s, "%04x %#04llx %#014llx\n", i,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index 0e47088ec44ba..2def4c26207d1 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -334,10 +334,10 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
struct fbnic_net *clone;
int err;
- ring->rx_pending = roundup_pow_of_two(ring->rx_pending);
- ring->rx_mini_pending = roundup_pow_of_two(ring->rx_mini_pending);
- ring->rx_jumbo_pending = roundup_pow_of_two(ring->rx_jumbo_pending);
- ring->tx_pending = roundup_pow_of_two(ring->tx_pending);
+ ring->rx_pending = fbnic_ring_size_pow2(ring->rx_pending);
+ ring->rx_mini_pending = fbnic_ring_size_pow2(ring->rx_mini_pending);
+ ring->rx_jumbo_pending = fbnic_ring_size_pow2(ring->rx_jumbo_pending);
+ ring->tx_pending = fbnic_ring_size_pow2(ring->tx_pending);
/* These are absolute minimums allowing the device and driver to operate
* but not necessarily guarantee reasonable performance. Settings below
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index 10bf99be3f244..8bc5e6e5c59e8 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -773,6 +773,11 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
fbn->ppq_size = FBNIC_PPQ_SIZE_DEFAULT;
fbn->rcq_size = FBNIC_RCQ_SIZE_DEFAULT;
+ netdev->cfg->rings.rx_pending = fbn->rcq_size;
+ netdev->cfg->rings.rx_mini_pending = fbn->hpq_size;
+ netdev->cfg->rings.rx_jumbo_pending = fbn->ppq_size;
+ netdev->cfg->rings.tx_pending = fbn->txq_size;
+
fbn->tx_usecs = FBNIC_TX_USECS_DEFAULT;
fbn->rx_usecs = FBNIC_RX_USECS_DEFAULT;
fbn->rx_max_frames = FBNIC_RX_FRAMES_DEFAULT;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
index 401f8b8ae1cae..5e22905a63739 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
@@ -871,19 +871,31 @@ static void fbnic_clean_bdq(struct fbnic_ring *ring, unsigned int hw_head,
ring->head = head;
}
+static u16 fbnic_rcd_bd_idx(const struct fbnic_ring *bdq, u64 rcd)
+{
+ return FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd) >> bdq->bd_page_shift;
+}
+
+static unsigned int fbnic_rcd_bd_page_offset(const struct fbnic_ring *bdq,
+ u64 rcd)
+{
+ u16 id = FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd);
+ u16 page_id = id & (fbnic_bd_page_count(bdq) - 1);
+
+ return page_id * FBNIC_BD_PAGE_SIZE;
+}
+
static void fbnic_bd_prep(struct fbnic_ring *bdq, u16 id, netmem_ref netmem)
{
- __le64 *bdq_desc = &bdq->desc[id * FBNIC_BD_FRAG_COUNT];
+ __le64 *bdq_desc = &bdq->desc[id * fbnic_bd_page_count(bdq)];
dma_addr_t dma = page_pool_get_dma_addr_netmem(netmem);
- u64 bd, i = FBNIC_BD_FRAG_COUNT;
+ u64 bd, i = fbnic_bd_page_count(bdq);
- bd = (FBNIC_BD_PAGE_ADDR_MASK & dma) |
- FIELD_PREP(FBNIC_BD_PAGE_ID_MASK, id);
+ bd = (FBNIC_BD_DESC_ADDR_MASK & dma) |
+ FIELD_PREP(FBNIC_BD_DESC_ID_MASK, (u64)id << bdq->bd_page_shift);
- /* In the case that a page size is larger than 4K we will map a
- * single page to multiple fragments. The fragments will be
- * FBNIC_BD_FRAG_COUNT in size and the lower n bits will be use
- * to indicate the individual fragment IDs.
+ /* Posted pages larger than 4 KiB use consecutive device-page IDs in
+ * the low bits of the software page ID.
*/
do {
*bdq_desc = cpu_to_le64(bd);
@@ -928,7 +940,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq)
/* Force DMA writes to flush before writing to tail */
dma_wmb();
- writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell);
+ writel(i * fbnic_bd_page_count(bdq), bdq->doorbell);
}
}
@@ -959,26 +971,27 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd,
struct fbnic_pkt_buff *pkt,
struct fbnic_q_triad *qt)
{
- unsigned int hdr_pg_idx = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
unsigned int hdr_pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd);
- struct page *page = fbnic_page_pool_get_head(qt, hdr_pg_idx);
unsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd);
+ unsigned int hdr_pg_idx = fbnic_rcd_bd_idx(&qt->sub0, rcd);
unsigned int frame_sz, hdr_pg_start, hdr_pg_end, headroom;
unsigned char *hdr_start;
+ struct page *page;
/* data_hard_start should always be NULL when this is called */
WARN_ON_ONCE(pkt->buff.data_hard_start);
+ page = fbnic_page_pool_get_head(qt, hdr_pg_idx);
+
/* Short-cut the end calculation if we know page is fully consumed */
hdr_pg_end = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ?
- FBNIC_BD_FRAG_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len);
+ FBNIC_BD_PAGE_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len);
hdr_pg_start = fbnic_hdr_pg_start(hdr_pg_off);
headroom = hdr_pg_off - hdr_pg_start + FBNIC_RX_PAD;
frame_sz = hdr_pg_end - hdr_pg_start;
xdp_init_buff(&pkt->buff, frame_sz, &qt->xdp_rxq);
- hdr_pg_start += (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) *
- FBNIC_BD_FRAG_SIZE;
+ hdr_pg_start += fbnic_rcd_bd_page_offset(&qt->sub0, rcd);
/* Sync DMA buffer */
dma_sync_single_range_for_cpu(nv->dev, page_pool_get_dma_addr(page),
@@ -999,23 +1012,28 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vector *nv, u64 rcd,
struct fbnic_pkt_buff *pkt,
struct fbnic_q_triad *qt)
{
- unsigned int pg_idx = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
unsigned int pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd);
unsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd);
- netmem_ref netmem = fbnic_page_pool_get_data(qt, pg_idx);
+ unsigned int pg_idx = fbnic_rcd_bd_idx(&qt->sub1, rcd);
unsigned int truesize;
+ netmem_ref netmem;
bool added;
+ netmem = fbnic_page_pool_get_data(qt, pg_idx);
+
truesize = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ?
- FBNIC_BD_FRAG_SIZE - pg_off : ALIGN(len, 128);
+ FBNIC_BD_PAGE_SIZE - pg_off :
+ ALIGN(len, FBNIC_RX_PAYLD_ALIGN);
- pg_off += (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) *
- FBNIC_BD_FRAG_SIZE;
+ pg_off += fbnic_rcd_bd_page_offset(&qt->sub1, rcd);
/* Sync DMA buffer */
page_pool_dma_sync_netmem_for_cpu(qt->sub1.page_pool, netmem,
pg_off, truesize);
+ /* Consecutive device-page completions from one PPQ page are adjacent
+ * ranges in the same netmem.
+ */
added = xdp_buff_add_frag(&pkt->buff, netmem, pg_off, len, truesize);
if (unlikely(!added)) {
pkt->add_frag_failed = true;
@@ -1257,12 +1275,12 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv,
switch (FIELD_GET(FBNIC_RCD_TYPE_MASK, rcd)) {
case FBNIC_RCD_TYPE_HDR_AL:
- head0 = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
+ head0 = fbnic_rcd_bd_idx(&qt->sub0, rcd);
fbnic_pkt_prepare(nv, rcd, pkt, qt);
break;
case FBNIC_RCD_TYPE_PAY_AL:
- head1 = FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd);
+ head1 = fbnic_rcd_bd_idx(&qt->sub1, rcd);
fbnic_add_rx_frag(nv, rcd, pkt, qt);
break;
@@ -1550,7 +1568,7 @@ void fbnic_free_napi_vectors(struct fbnic_net *fbn)
static int
fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
- unsigned int rxq_idx)
+ unsigned int rxq_idx, u32 rx_page_size)
{
struct page_pool_params pp_params = {
.order = 0,
@@ -1585,6 +1603,8 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
qt->sub0.page_pool = pp;
if (netif_rxq_has_unreadable_mp(fbn->netdev, rxq_idx)) {
+ pp_params.order = get_order(rx_page_size);
+ pp_params.max_len = rx_page_size;
pp_params.flags |= PP_FLAG_ALLOW_UNREADABLE_NETMEM;
pp_params.dma_dir = DMA_FROM_DEVICE;
@@ -1603,6 +1623,16 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
return PTR_ERR(pp);
}
+static u8 fbnic_bdq_page_shift(u32 page_size)
+{
+ return ilog2(page_size / FBNIC_BD_PAGE_SIZE);
+}
+
+static void fbnic_bdq_set_page_size(struct fbnic_ring *bdq, u32 page_size)
+{
+ bdq->bd_page_shift = fbnic_bdq_page_shift(page_size);
+}
+
static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell,
int q_idx, u8 flags)
{
@@ -1610,6 +1640,7 @@ static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell,
ring->doorbell = doorbell;
ring->q_idx = q_idx;
ring->flags = flags;
+ fbnic_bdq_set_page_size(ring, PAGE_SIZE);
ring->deferred_head = -1;
}
@@ -1894,12 +1925,12 @@ static int fbnic_alloc_rx_ring_desc(struct fbnic_net *fbn,
switch (rxr->doorbell - fbnic_ring_csr_base(rxr)) {
case FBNIC_QUEUE_BDQ_HPQ_TAIL:
- rxq_size = fbn->hpq_size / FBNIC_BD_FRAG_COUNT;
- desc_size *= FBNIC_BD_FRAG_COUNT;
+ rxq_size = fbn->hpq_size / fbnic_bd_page_count(rxr);
+ desc_size *= fbnic_bd_page_count(rxr);
break;
case FBNIC_QUEUE_BDQ_PPQ_TAIL:
- rxq_size = fbn->ppq_size / FBNIC_BD_FRAG_COUNT;
- desc_size *= FBNIC_BD_FRAG_COUNT;
+ rxq_size = fbn->ppq_size / fbnic_bd_page_count(rxr);
+ desc_size *= fbnic_bd_page_count(rxr);
break;
case FBNIC_QUEUE_RCQ_HEAD:
rxq_size = fbn->rcq_size;
@@ -2003,15 +2034,18 @@ static int fbnic_alloc_tx_qt_resources(struct fbnic_net *fbn,
static int fbnic_alloc_rx_qt_resources(struct fbnic_net *fbn,
struct fbnic_napi_vector *nv,
- struct fbnic_q_triad *qt)
+ struct fbnic_q_triad *qt,
+ u32 rx_page_size)
{
struct device *dev = fbn->netdev->dev.parent;
int err;
- err = fbnic_alloc_qt_page_pools(fbn, qt, qt->cmpl.q_idx);
+ err = fbnic_alloc_qt_page_pools(fbn, qt, qt->cmpl.q_idx, rx_page_size);
if (err)
return err;
+ fbnic_bdq_set_page_size(&qt->sub1, rx_page_size);
+
err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->sub0.q_idx,
nv->napi.napi_id);
if (err)
@@ -2072,7 +2106,11 @@ static int fbnic_alloc_nv_resources(struct fbnic_net *fbn,
/* Allocate Rx Resources */
for (j = 0; j < nv->rxt_count; j++, i++) {
- err = fbnic_alloc_rx_qt_resources(fbn, nv, &nv->qt[i]);
+ struct netdev_queue_config qcfg;
+
+ netdev_queue_config(fbn->netdev, nv->qt[i].cmpl.q_idx, &qcfg);
+ err = fbnic_alloc_rx_qt_resources(fbn, nv, &nv->qt[i],
+ qcfg.rx_page_size);
if (err)
goto free_qt_resources;
}
@@ -2565,7 +2603,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
hpq->tail = 0;
hpq->head = 0;
- log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+ log_size = fls(hpq->size_mask) + hpq->bd_page_shift;
/* Store descriptor ring address and size */
fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma));
@@ -2577,7 +2615,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
if (!ppq->size_mask)
goto write_ctl;
- log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+ log_size = fls(ppq->size_mask) + ppq->bd_page_shift;
/* Add enabling of PPQ to BDQ control */
bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;
@@ -2839,7 +2877,8 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,
struct fbnic_napi_vector *nv;
if (!netif_running(dev))
- return fbnic_alloc_qt_page_pools(fbn, qt, idx);
+ return fbnic_alloc_qt_page_pools(fbn, qt, idx,
+ qcfg->rx_page_size);
real = container_of(fbn->rx[idx], struct fbnic_q_triad, cmpl);
nv = fbn->napi[idx % fbn->num_napi];
@@ -2851,7 +2890,62 @@ static int fbnic_queue_mem_alloc(struct net_device *dev,
fbnic_ring_init(&qt->cmpl, real->cmpl.doorbell, real->cmpl.q_idx,
real->cmpl.flags);
- return fbnic_alloc_rx_qt_resources(fbn, nv, qt);
+ return fbnic_alloc_rx_qt_resources(fbn, nv, qt, qcfg->rx_page_size);
+}
+
+static void fbnic_default_qcfg(struct net_device *dev,
+ struct netdev_queue_config *qcfg)
+{
+ qcfg->rx_page_size = PAGE_SIZE;
+}
+
+static int fbnic_validate_qcfg(struct net_device *dev,
+ struct netdev_queue_config *qcfg,
+ struct netlink_ext_ack *extack)
+{
+ u32 ppq_size = fbnic_ring_size_pow2(qcfg->rx_jumbo_ring_size);
+ u32 bd_page_count, ppq_entries, frag_count;
+ u32 rx_page_size = qcfg->rx_page_size;
+
+ if (!is_power_of_2(rx_page_size)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx_page_size must be a power of 2");
+ return -EINVAL;
+ }
+
+ if (rx_page_size < FBNIC_BD_PAGE_SIZE) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx_page_size must be at least 4K");
+ return -EINVAL;
+ }
+
+ /* Payload fragments occupy multiples of FBNIC_RX_PAYLD_ALIGN bytes.
+ * Keep at least one reference in the bias until fbnic_clean_bdq()
+ * observes a completion from a subsequent allocation.
+ */
+ frag_count = rx_page_size / FBNIC_RX_PAYLD_ALIGN;
+ if (frag_count >= FBNIC_PAGECNT_BIAS_MAX) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx_page_size can produce too many fragments");
+ return -EINVAL;
+ }
+
+ bd_page_count = rx_page_size / FBNIC_BD_PAGE_SIZE;
+ ppq_entries = ppq_size / bd_page_count;
+ /* The PPQ is sized in 4 KiB device pages. One software entry tracks
+ * each page-pool allocation. In addition to the unused entry for
+ * empty/full accounting, cleanup retains the current allocation
+ * until a completion identifies a subsequent allocation. A two-entry
+ * ring can only post one allocation and cannot make progress.
+ * Require at least four entries, since ring sizes are powers of two.
+ */
+ if (ppq_entries < 4) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx-jumbo ring size too small for rx_page_size");
+ return -EINVAL;
+ }
+
+ return 0;
}
static void fbnic_queue_mem_free(struct net_device *dev, void *qmem)
@@ -2953,4 +3047,7 @@ const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops = {
.ndo_queue_mem_free = fbnic_queue_mem_free,
.ndo_queue_start = fbnic_queue_start,
.ndo_queue_stop = fbnic_queue_stop,
+ .ndo_default_qcfg = fbnic_default_qcfg,
+ .ndo_validate_qcfg = fbnic_validate_qcfg,
+ .supported_params = QCFG_RX_PAGE_SIZE,
};
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
index e03c9d2c38dca..12b3a684f4611 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
@@ -49,12 +49,18 @@ struct fbnic_net;
#define FBNIC_RX_USECS_DEFAULT 30
#define FBNIC_RX_FRAMES_DEFAULT 0
+static inline u32 fbnic_ring_size_pow2(u32 size)
+{
+ return size ? roundup_pow_of_two(size) : 0;
+}
+
#define FBNIC_RX_TROOM \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
#define FBNIC_RX_HROOM_PAD 128
#define FBNIC_RX_HROOM \
(ALIGN(FBNIC_RX_TROOM + FBNIC_RX_HROOM_PAD, 128) - FBNIC_RX_TROOM)
#define FBNIC_RX_PAD 0
+#define FBNIC_RX_PAYLD_ALIGN 128
#define FBNIC_RX_PAYLD_OFFSET 0
#define FBNIC_RX_PAYLD_PG_CL 0
@@ -121,6 +127,7 @@ struct fbnic_ring {
u16 size_mask; /* Size of ring in descriptors - 1 */
u8 q_idx; /* Logical netdev ring index */
u8 flags; /* Ring flags (FBNIC_RING_F_*) */
+ u8 bd_page_shift; /* BDQ: ilog2(page_size / 4096) */
u32 head, tail; /* Head/Tail of ring */
@@ -162,6 +169,11 @@ struct fbnic_napi_vector {
extern const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops;
+static inline u16 fbnic_bd_page_count(const struct fbnic_ring *bdq)
+{
+ return 1U << bdq->bd_page_shift;
+}
+
netdev_tx_t fbnic_xmit_frame(struct sk_buff *skb, struct net_device *dev);
netdev_features_t
fbnic_features_check(struct sk_buff *skb, struct net_device *dev,
diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
index 70c9fe9e83cc4..31121900aac88 100644
--- a/include/net/netdev_queues.h
+++ b/include/net/netdev_queues.h
@@ -4,18 +4,59 @@
#include <linux/netdevice.h>
+/**
+ * struct netdev_ring_config - accepted RX/TX ring depth configuration
+ * @rx_pending: Size of the regular RX ring.
+ * @rx_mini_pending: Size of the RX mini ring.
+ * @rx_jumbo_pending: Size of the RX jumbo ring.
+ * @tx_pending: Size of the TX ring.
+ *
+ * This stores only persistent configuration values. Capability fields,
+ * such as max ring sizes, are reported by drivers but are not part of the
+ * accepted configuration.
+ *
+ * Note: these values are only used for queue-configuration validation
+ * today. Some drivers update their ring sizes without reflecting the change
+ * in @cfg. Before using the stored values for anything else, those cases
+ * need to be audited, and the core likely needs a driver notification API
+ * similar to ethtool_rxfh_context_lost().
+ */
+struct netdev_ring_config {
+ u32 rx_pending;
+ u32 rx_mini_pending;
+ u32 rx_jumbo_pending;
+ u32 tx_pending;
+};
+
/**
* struct netdev_config - queue-related configuration for a netdev
* @hds_thresh: HDS Threshold value.
* @hds_config: HDS value from userspace.
+ * @rings: Accepted RX/TX ring depths.
+ *
+ * Direct values, such as @hds_thresh and @rings, hold the current
+ * accepted configuration. Drivers which use them for queue rendering
+ * must initialize them with their defaults.
*/
struct netdev_config {
u32 hds_thresh;
u8 hds_config;
+
+ struct netdev_ring_config rings;
};
+/**
+ * struct netdev_queue_config - rendered configuration for an RX queue
+ * @rx_page_size: Size of one RX page-pool allocation.
+ * @rx_ring_size: Effective size of the regular RX ring.
+ * @rx_mini_ring_size: Effective size of the RX mini ring.
+ * @rx_jumbo_ring_size: Effective size of the RX jumbo ring.
+ */
struct netdev_queue_config {
u32 rx_page_size;
+ u32 rx_ring_size;
+ u32 rx_mini_ring_size;
+ u32 rx_jumbo_ring_size;
};
/* See the netdev.yaml spec for definition of each statistic */
@@ -145,10 +186,9 @@ enum {
*
* @ndo_validate_qcfg: (Optional) Check if queue config is supported.
* Called when configuration affecting a queue may be
- * changing, either due to NIC-wide config, or config
- * scoped to the queue at a specified index.
- * When NIC-wide config is changed the callback will
- * be invoked for all queues.
+ * changing. When NIC-wide config is changed the
+ * callback will be invoked for the defaults and all
+ * queue overrides.
*
* @ndo_queue_create: Create a new RX queue on a virtual device that will
* be paired with a physical device's queue via leasing.
diff --git a/net/core/dev.c b/net/core/dev.c
index 290e0f099e6bf..4a7c5a5e48e52 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12195,10 +12195,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
if (!dev->ethtool)
goto free_all;
- dev->cfg = kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT);
- if (!dev->cfg)
+ if (netdev_alloc_config(dev))
goto free_all;
- dev->cfg_pending = dev->cfg;
dev->num_napi_configs = maxqs;
napi_config_sz = array_size(maxqs, sizeof(*dev->napi_config));
@@ -12270,8 +12268,7 @@ void free_netdev(struct net_device *dev)
return;
}
- WARN_ON(dev->cfg != dev->cfg_pending);
- kfree(dev->cfg);
+ netdev_free_config(dev);
kfree(dev->ethtool);
netif_free_tx_queues(dev);
netif_free_rx_queues(dev);
diff --git a/net/core/dev.h b/net/core/dev.h
index b757faead4d1a..567e7b82ef24b 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -102,9 +102,16 @@ extern struct rw_semaphore dev_addr_sem;
extern struct list_head net_todo_list;
void netdev_run_todo(void);
+int netdev_alloc_config(struct net_device *dev);
+void __netdev_free_config(struct netdev_config *cfg);
+void netdev_free_config(struct net_device *dev);
+int netdev_reconfig_start(struct net_device *dev);
+
int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack);
+int netdev_queue_config_revalidate(struct net_device *dev,
+ struct netlink_ext_ack *extack);
bool netif_rxq_has_mp(struct net_device *dev, unsigned int rxq_idx);
bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx);
diff --git a/net/core/netdev_config.c b/net/core/netdev_config.c
index f14af365d5cd7..1975de42a60d9 100644
--- a/net/core/netdev_config.c
+++ b/net/core/netdev_config.c
@@ -6,6 +6,43 @@
#include "dev.h"
+int netdev_alloc_config(struct net_device *dev)
+{
+ struct netdev_config *cfg;
+
+ cfg = kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT);
+ if (!cfg)
+ return -ENOMEM;
+
+ dev->cfg = cfg;
+ dev->cfg_pending = cfg;
+ return 0;
+}
+
+void __netdev_free_config(struct netdev_config *cfg)
+{
+ kfree(cfg);
+}
+
+void netdev_free_config(struct net_device *dev)
+{
+ WARN_ON(dev->cfg != dev->cfg_pending);
+ __netdev_free_config(dev->cfg);
+}
+
+int netdev_reconfig_start(struct net_device *dev)
+{
+ struct netdev_config *cfg;
+
+ WARN_ON(dev->cfg != dev->cfg_pending);
+ cfg = kmemdup(dev->cfg, sizeof(*dev->cfg), GFP_KERNEL_ACCOUNT);
+ if (!cfg)
+ return -ENOMEM;
+
+ dev->cfg_pending = cfg;
+ return 0;
+}
+
static int netdev_nop_validate_qcfg(struct net_device *dev,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack)
@@ -13,6 +50,15 @@ static int netdev_nop_validate_qcfg(struct net_device *dev,
return 0;
}
+static void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg,
+ const struct netdev_config *cfg)
+{
+ /* Device config overrides callback-provided fallbacks. */
+ qcfg->rx_ring_size = cfg->rings.rx_pending;
+ qcfg->rx_mini_ring_size = cfg->rings.rx_mini_pending;
+ qcfg->rx_jumbo_ring_size = cfg->rings.rx_jumbo_pending;
+}
+
static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack,
@@ -33,6 +79,7 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
/* Get defaults from the driver, in case user config not set */
if (dev->queue_mgmt_ops->ndo_default_qcfg)
dev->queue_mgmt_ops->ndo_default_qcfg(dev, qcfg);
+ netdev_qcfg_apply_dev(qcfg, dev->cfg_pending);
err = validate_cb(dev, qcfg, extack);
if (err)
return err;
@@ -54,9 +101,11 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
* @rxq_idx: index of the queue of interest
* @qcfg: queue configuration struct (output)
*
- * Render the configuration for a given queue. This helper should be used
- * by drivers which support queue configuration to retrieve config for
- * a particular queue.
+ * Render the configuration for a given queue. During a configuration
+ * transaction this includes the proposed device-wide values in
+ * @dev->cfg_pending; otherwise @dev->cfg_pending points to the accepted
+ * configuration. This helper should be used by drivers which support queue
+ * configuration to retrieve config for a particular queue.
*
* @qcfg is an output parameter and is always fully initialized by this
* function. Some values may not be set by the user, drivers may either
@@ -76,3 +125,23 @@ int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,
{
return __netdev_queue_config(dev, rxq_idx, qcfg, extack, true);
}
+
+int netdev_queue_config_revalidate(struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops;
+ struct netdev_queue_config qcfg;
+ unsigned int i;
+ int err;
+
+ if (!qops || !qops->ndo_validate_qcfg)
+ return 0;
+
+ for (i = 0; i < dev->real_num_rx_queues; i++) {
+ err = netdev_queue_config_validate(dev, i, &qcfg, extack);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 23db40618fed1..05ed22fd1f906 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -956,6 +956,15 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,
kparam->hds_thresh = dev->cfg->hds_thresh;
}
+void ethtool_ringparam_set_cfg(struct netdev_config *cfg,
+ const struct ethtool_ringparam *param)
+{
+ cfg->rings.rx_pending = param->rx_pending;
+ cfg->rings.rx_mini_pending = param->rx_mini_pending;
+ cfg->rings.rx_jumbo_pending = param->rx_jumbo_pending;
+ cfg->rings.tx_pending = param->tx_pending;
+}
+
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
{
memset(info, 0, sizeof(*info));
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 4e5356e26f400..a27944d4cbf83 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -53,6 +53,8 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,
struct ethtool_ringparam *param,
struct kernel_ethtool_ringparam *kparam,
struct netlink_ext_ack *extack);
+void ethtool_ringparam_set_cfg(struct netdev_config *cfg,
+ const struct ethtool_ringparam *param);
int ethtool_get_rx_ring_count(struct net_device *dev);
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 4b0bc503f9307..1320289025b25 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -35,6 +35,7 @@
#include <net/netdev_queues.h>
#include "common.h"
+#include "../core/dev.h"
/* State held across locks and calls for commands which have devlink fallback */
struct ethtool_devlink_compat {
@@ -2239,10 +2240,29 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
ringparam.tx_pending > max.tx_max_pending)
return -EINVAL;
+ ret = netdev_reconfig_start(dev);
+ if (ret)
+ return ret;
+
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+
+ ret = netdev_queue_config_revalidate(dev, NULL);
+ if (ret)
+ goto out_free_cfg;
+
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
&kernel_ringparam, NULL);
- if (!ret)
- ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF);
+ if (ret)
+ goto out_free_cfg;
+
+ /* The driver may adjust the accepted ring depths. */
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+ swap(dev->cfg, dev->cfg_pending);
+ ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF);
+
+out_free_cfg:
+ __netdev_free_config(dev->cfg_pending);
+ dev->cfg_pending = dev->cfg;
return ret;
}
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1af395b54330e..383e911f50f78 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -11,6 +11,8 @@
#include "module_fw.h"
#include "netlink.h"
+#include "../core/dev.h"
+
static struct genl_family ethtool_genl_family;
static bool ethnl_ok __read_mostly;
@@ -934,12 +936,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
if (need_rtnl)
rtnl_lock();
netdev_lock_ops(dev);
- dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
- GFP_KERNEL_ACCOUNT);
- if (!dev->cfg_pending) {
- ret = -ENOMEM;
- goto out_tie_cfg;
- }
+ ret = netdev_reconfig_start(dev);
+ if (ret)
+ goto out_unlock;
ret = ethnl_ops_begin(dev);
if (ret < 0)
@@ -958,9 +957,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
out_ops:
ethnl_ops_complete(dev);
out_free_cfg:
- kfree(dev->cfg_pending);
-out_tie_cfg:
+ __netdev_free_config(dev->cfg_pending);
dev->cfg_pending = dev->cfg;
+out_unlock:
netdev_unlock_ops(dev);
if (need_rtnl)
rtnl_unlock();
diff --git a/net/ethtool/rings.c b/net/ethtool/rings.c
index 9054c89c5d7bb..c04312fc0d061 100644
--- a/net/ethtool/rings.c
+++ b/net/ethtool/rings.c
@@ -4,6 +4,7 @@
#include "common.h"
#include "netlink.h"
+#include "../core/dev.h"
struct rings_req_info {
struct ethnl_req_info base;
@@ -299,10 +300,20 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
dev->cfg_pending->hds_config = kernel_ringparam.tcp_data_split;
dev->cfg_pending->hds_thresh = kernel_ringparam.hds_thresh;
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+
+ ret = netdev_queue_config_revalidate(dev, info->extack);
+ if (ret)
+ return ret;
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
&kernel_ringparam, info->extack);
- return ret < 0 ? ret : 1;
+ if (ret < 0)
+ return ret;
+
+ /* The driver may adjust the accepted ring depths. */
+ ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam);
+ return 1;
}
const struct ethnl_request_ops ethnl_rings_request_ops = {
diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
index f6a8fc5fac241..c0d9065b21030 100644
--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
@@ -84,6 +84,9 @@ static int cfg_oneshot_recvs;
static int cfg_send_size = SEND_SIZE;
static struct sockaddr_in6 cfg_addr;
static unsigned int cfg_rx_buf_len;
+static unsigned int cfg_min_data_end;
+static bool cfg_check_data_end;
+static bool seen_data_end;
static bool cfg_dry_run;
static char *payload;
@@ -298,6 +301,15 @@ static void process_recvzc(struct io_uring *ring, struct io_uring_cqe *cqe)
mask = (1ULL << IORING_ZCRX_AREA_SHIFT) - 1;
data = (char *)area_ptr + (rcqe->off & mask);
+ if (cfg_check_data_end) {
+ unsigned int rx_buf_len = cfg_rx_buf_len ?: page_size;
+ unsigned int data_end_off;
+
+ data_end_off = (rcqe->off & mask) % rx_buf_len + n;
+ if (data_end_off > cfg_min_data_end)
+ seen_data_end = true;
+ }
+
for (i = 0; i < n; i++) {
if (*(data + i) != payload[(received + i)])
error(1, 0, "payload mismatch at %d", i);
@@ -373,7 +385,10 @@ static void run_server(void)
server_loop(&ring);
if (!stop)
- error(1, 0, "test failed\n");
+ error(1, 0, "test failed after receiving %zu bytes", received);
+ if (cfg_check_data_end && !seen_data_end)
+ error(1, 0, "no payload CQE ending past offset %u",
+ cfg_min_data_end);
}
static void run_client(void)
@@ -406,8 +421,11 @@ static void run_client(void)
static void usage(const char *filepath)
{
- error(1, 0, "Usage: %s (-4|-6) (-s|-c) -h<server_ip> -p<port> "
- "-l<payload_size> -i<ifname> -q<rxq_id>", filepath);
+ error(1, 0,
+ "Usage: %s (-4|-6) (-s|-c) -h<server_ip> -p<port>\n"
+ "\t-l<payload_size> -i<ifname> -q<rxq_id>\n"
+ "\t[-x<rx_buf_pages>] [-E<min_data_end>] [-d]\n",
+ filepath);
}
static void parse_opts(int argc, char **argv)
@@ -425,7 +443,7 @@ static void parse_opts(int argc, char **argv)
usage(argv[0]);
cfg_payload_len = max_payload_len;
- while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:x:d")) != -1) {
+ while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:x:E:d")) != -1) {
switch (c) {
case 's':
if (cfg_client)
@@ -463,6 +481,10 @@ static void parse_opts(int argc, char **argv)
case 'x':
cfg_rx_buf_len = page_size * strtoul(optarg, NULL, 0);
break;
+ case 'E':
+ cfg_check_data_end = true;
+ cfg_min_data_end = strtoul(optarg, NULL, 0);
+ break;
case 'd':
cfg_dry_run = true;
break;
@@ -484,6 +506,9 @@ static void parse_opts(int argc, char **argv)
if (cfg_payload_len > max_payload_len)
error(1, 0, "-l: payload exceeds max (%d)", max_payload_len);
+ if (cfg_check_data_end &&
+ cfg_min_data_end >= (cfg_rx_buf_len ?: page_size))
+ error(1, 0, "-E: offset outside rx_buf_len");
}
int main(int argc, char **argv)
diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
index b7a225fe4beae..a9f62c6b950bb 100755
--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
@@ -175,9 +175,13 @@ def test_zcrx_large_chunks(cfg) -> None:
single(cfg)
page_size = resource.getpagesize()
+ mtu = cfg.dev["mtu"]
nr_pages = 2
+ while nr_pages * page_size <= 2 * mtu:
+ nr_pages *= 2
rx_buf_len = nr_pages * page_size
- rx_cmd = f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.target} -x {nr_pages}"
+ rx_cmd = (f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} "
+ f"-q {cfg.target} -x {nr_pages} -E {mtu}")
tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 12840"
probe = cmd(rx_cmd + " -d", fail=False)
|
| 23/3 | 2026/09/10 19:37 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 17068 output: 30 thoughts: 824 Thoughts: **Analyzing the Patch for Potential KMSAN Needs** Okay, let's dive into this patch. My initial focus is to understand the scope of the changes and determine if anything here warrants a KMSAN (Kernel Memory Sanitizer) check. Given my experience, I can quickly assess the potential for uninitialized memory reads or information leaks. First, I need to get a clear picture of the affected files. Alright, so the patch touches a significant chunk of the networking stack: the fbnic driver (Meta's, I recall that well), ethtool, and some core network device configuration files (`netdev_queues.h`, `dev.c`, `netdev_config.c`, etc.). There are also some selftests, which is good to see for validation. Now, let's break down the changes. The first major area involves ethtool ring configuration and netdev queue configuration validation. It seems the patch introduces a new structure, `struct netdev_config`, to track accepted ring depths and is adding functions to allocate, free, and manage these configurations. It seems to have a `cfg_pending` to track changes. I'm taking note of the `kzalloc_obj`, `kmemdup`, and how these pending copies are handled during ring parameter setting (like `ethtool_set_ringparam` and `ethnl_set_rings`) and queue validation. It looks like we're being careful with the configuration, validating and copying before making it active. The use of `ndo_default_qcfg` is of interest here, and I'll keep an eye on how the driver handles initialization. The second area is specific to the `fbnic` driver. It adds support for multi-page buffer descriptors and larger page pools, which makes sense for performance improvements. This involves updating functions like `fbnic_bd_prep`, `fbnic_fill_bdq`, etc., and implementing functions like `fbnic_default_qcfg` and `fbnic_validate_qcfg`. The sizing descriptors are now based on `fbnic_bd_page_count`. Given the structure allocations and potential for modifications to buffer descriptors, I immediately want to scrutinize the initialization of memory and if there are any uninitialized memory reads or info leaks introduced. Specifically, I need to check how `struct netdev_queue_config` is defined, passed around, and initialized, especially in the context of the new `netdev_config.c`. A `grep` for `__netdev_queue_config` should quickly show me where this crucial structure is used. I'll read through `netdev_config.c` as well. This will be the key to ensuring that the new queue configuration handling is safe. |
| 24/3 | 2026/09/10 19:37 | tool | grepper |
0mArgs:{
"Expression": "__netdev_queue_config",
"PathPrefix": "net/core"
}Results: {
"Output": "net/core/netdev_config.c=53=static void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg,\n--\nnet/core/netdev_config.c-61-\nnet/core/netdev_config.c:62:static int __netdev_queue_config(struct net_device *dev, int rxq_idx,\nnet/core/netdev_config.c-63-\t\t\t\t struct netdev_queue_config *qcfg,\n--\nnet/core/netdev_config.c=115=void netdev_queue_config(struct net_device *dev, int rxq_idx,\n--\nnet/core/netdev_config.c-117-{\nnet/core/netdev_config.c:118:\t__netdev_queue_config(dev, rxq_idx, qcfg, NULL, false);\nnet/core/netdev_config.c-119-}\n--\nnet/core/netdev_config.c=122=int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,\n--\nnet/core/netdev_config.c-125-{\nnet/core/netdev_config.c:126:\treturn __netdev_queue_config(dev, rxq_idx, qcfg, extack, true);\nnet/core/netdev_config.c-127-}\n"
} |
| 25/3 | 2026/09/10 19:38 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 18859 output: 37 thoughts: 26 Thoughts: Here's my summary, as though I'm thinking through this section of the code: **Diving into `netdev_config.c` - Lines 50-130** Alright, let's get into the nitty-gritty. I'm focusing on `net/core/netdev_config.c`, specifically around lines 50 to 130. This is probably where they're handling some core network device configuration logic. I expect to see the basic building blocks here – device initialization routines, maybe some default parameter settings, and potentially some calls related to hardware-specific capabilities discovery or setup. I'm especially keen to see how they're handling things like MTU settings, link speed negotiation, and potentially the initial setting of mac address or other important configurations. Knowing the kernel code base, I expect to be greeted by a lot of macro usages and potentially some function pointer usage. This could be a critical area, affecting how reliably devices come up and interact with the network stack. I'm going to look out for common pitfalls, such as potential race conditions or how the code handles different network interface types (e.g., ethernet, wifi, etc.). Time to get to it! |
| 26/3 | 2026/09/10 19:38 | tool | read-file |
0mArgs:{
"File": "net/core/netdev_config.c",
"FirstLine": 50,
"LineCount": 80
}Results: {
"Contents": " 50:\t\treturn 0;\n 51:\t}\n 52:\t\n 53:\tstatic void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg,\n 54:\t\t\t\t\t const struct netdev_config *cfg)\n 55:\t{\n 56:\t\t/* Device config overrides callback-provided fallbacks. */\n 57:\t\tqcfg-\u003erx_ring_size = cfg-\u003erings.rx_pending;\n 58:\t\tqcfg-\u003erx_mini_ring_size = cfg-\u003erings.rx_mini_pending;\n 59:\t\tqcfg-\u003erx_jumbo_ring_size = cfg-\u003erings.rx_jumbo_pending;\n 60:\t}\n 61:\t\n 62:\tstatic int __netdev_queue_config(struct net_device *dev, int rxq_idx,\n 63:\t\t\t\t\t struct netdev_queue_config *qcfg,\n 64:\t\t\t\t\t struct netlink_ext_ack *extack,\n 65:\t\t\t\t\t bool validate)\n 66:\t{\n 67:\t\tint (*validate_cb)(struct net_device *dev,\n 68:\t\t\t\t struct netdev_queue_config *qcfg,\n 69:\t\t\t\t struct netlink_ext_ack *extack);\n 70:\t\tstruct pp_memory_provider_params *mpp;\n 71:\t\tint err;\n 72:\t\n 73:\t\tvalidate_cb = netdev_nop_validate_qcfg;\n 74:\t\tif (validate \u0026\u0026 dev-\u003equeue_mgmt_ops-\u003endo_validate_qcfg)\n 75:\t\t\tvalidate_cb = dev-\u003equeue_mgmt_ops-\u003endo_validate_qcfg;\n 76:\t\n 77:\t\tmemset(qcfg, 0, sizeof(*qcfg));\n 78:\t\n 79:\t\t/* Get defaults from the driver, in case user config not set */\n 80:\t\tif (dev-\u003equeue_mgmt_ops-\u003endo_default_qcfg)\n 81:\t\t\tdev-\u003equeue_mgmt_ops-\u003endo_default_qcfg(dev, qcfg);\n 82:\t\tnetdev_qcfg_apply_dev(qcfg, dev-\u003ecfg_pending);\n 83:\t\terr = validate_cb(dev, qcfg, extack);\n 84:\t\tif (err)\n 85:\t\t\treturn err;\n 86:\t\n 87:\t\t/* Apply MP overrides */\n 88:\t\tmpp = \u0026__netif_get_rx_queue(dev, rxq_idx)-\u003emp_params;\n 89:\t\tif (mpp-\u003erx_page_size)\n 90:\t\t\tqcfg-\u003erx_page_size = mpp-\u003erx_page_size;\n 91:\t\terr = validate_cb(dev, qcfg, extack);\n 92:\t\tif (err)\n 93:\t\t\treturn err;\n 94:\t\n 95:\t\treturn 0;\n 96:\t}\n 97:\t\n 98:\t/**\n 99:\t * netdev_queue_config() - get configuration for a given queue\n 100:\t * @dev: net_device instance\n 101:\t * @rxq_idx: index of the queue of interest\n 102:\t * @qcfg: queue configuration struct (output)\n 103:\t *\n 104:\t * Render the configuration for a given queue. During a configuration\n 105:\t * transaction this includes the proposed device-wide values in\n 106:\t * @dev-\u003ecfg_pending; otherwise @dev-\u003ecfg_pending points to the accepted\n 107:\t * configuration. This helper should be used by drivers which support queue\n 108:\t * configuration to retrieve config for a particular queue.\n 109:\t *\n 110:\t * @qcfg is an output parameter and is always fully initialized by this\n 111:\t * function. Some values may not be set by the user, drivers may either\n 112:\t * deal with the \"unset\" values in @qcfg, or provide the callback\n 113:\t * to populate defaults in queue_management_ops.\n 114:\t */\n 115:\tvoid netdev_queue_config(struct net_device *dev, int rxq_idx,\n 116:\t\t\t\t struct netdev_queue_config *qcfg)\n 117:\t{\n 118:\t\t__netdev_queue_config(dev, rxq_idx, qcfg, NULL, false);\n 119:\t}\n 120:\tEXPORT_SYMBOL(netdev_queue_config);\n 121:\t\n 122:\tint netdev_queue_config_validate(struct net_device *dev, int rxq_idx,\n 123:\t\t\t\t\t struct netdev_queue_config *qcfg,\n 124:\t\t\t\t\t struct netlink_ext_ack *extack)\n 125:\t{\n 126:\t\treturn __netdev_queue_config(dev, rxq_idx, qcfg, extack, true);\n 127:\t}\n 128:\t\n 129:\tint netdev_queue_config_revalidate(struct net_device *dev,\n"
} |
| 27/3 | 2026/09/10 19:38 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 20488 output: 285 thoughts: 1159 Thoughts: **KMSAN Applicability Analysis for Network Device Configuration** Okay, let's break this down. My primary concern here is memory safety, specifically whether this code introduces any uninitialized memory access vectors. I've meticulously reviewed the code concerning network device configuration, focusing on potential KMSAN (Kernel Memory Sanitizer) and KASAN (Kernel Address Sanitizer) issues. First, I examined the initialization of the configuration structures. In `__netdev_queue_config`, the `qcfg` structure is *always* zeroed with `memset` *before* any other operations. Also, `dev->cfg` which seems to be the main configuration object, is allocated using `kzalloc_obj`, which *zero-initializes* all its memory. This is critical. We can see that the ring sizes are also populated via allocation, not via potentially random memory areas. Next, I looked at how userspace interacts with this configuration. Ethtool uses the standard `ethtool_ringparam` structure, which is populated from user space using `copy_from_user`—a process I consider safe. The configuration in the kernel is created with `kmemdup`, and all of the ring configuration happens on the `cfg_pending` area, and validated before being written to the device. I then moved onto the `fbnic` driver's ring buffer descriptor calculations and DMA operations. I checked the pointer math and descriptor indexing. While these are complex, the code consistently uses calculated values based on defined `bd_page_shift` and `bd_page_count` or masks. Crucially, the code is checking for alignment and bitfields, and the code appears to be using the appropriate masks to ensure it doesn't cause out-of-bounds access. The `fbnic_bd_prep` function carefully constructs the DMA descriptor, initializing all relevant bits. I focused on a potential issue: uninitialized memory, which could lead to information leaks or exploitable conditions. I systematically checked four crucial criteria: 1. **Kernel structures to userspace:** No structures are sent to user space without zeroing. 2. **Conditional logic with uninitialized variables:** Nope, no issues found. 3. **Complex structure allocation and uninitialized fields:** `kzalloc` and `memset` handle allocation and initialization. 4. **Bounds checks and uninitialized buffer access:** The calculations are checked and all pointers/offsets look correct. Based on my analysis, this code *does not* introduce any new vectors for uninitialized memory access. Potential bugs related to descriptor calculations or logic errors (like out-of-bounds accesses) are more likely to be detected by KASAN or standard testing/assertions. Therefore, my conclusion is that `NeedsKMSAN` should be `false`. KMSAN is not applicable here because the code doesn't create any new avenues for leaking kernel memory content to userspace, or introducing arbitrary read/write access. |
| 28/3 | 2026/09/10 19:38 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series adds netdev queue configuration tracking for ring sizes (storing accepted ring sizes in dev-\u003ecfg/dev-\u003ecfg_pending and validating queue configurations upon ring changes) and implements multi-page RX buffer descriptor support in the Meta fbnic driver.\n\n- Memory Initialization: All newly allocated kernel objects (dev-\u003ecfg via kzalloc_obj in netdev_alloc_config and cloned via kmemdup in netdev_reconfig_start) and stack structures (qcfg in __netdev_queue_config) are explicitly zero-initialized using kzalloc/kmemdup/memset prior to usage.\n- User-Kernel Boundary: No uninitialized kernel struct fields or padding bytes are exposed to user space. Ethtool notifications and ioctls use existing initialized data paths.\n- Driver Logic: Changes in fbnic modify descriptor indexing, page offset calculations, and ring sizing logic based on bd_page_shift. Any boundary or calculation errors here would involve out-of-bounds ring accesses or DMA descriptor management, which are detectable by KASAN or hardware/driver assertions, rather than reads of uninitialized memory.\n\nBecause no uninitialized memory risks or info-leaks are introduced or exposed, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series adds netdev queue configuration tracking for ring sizes (storing accepted ring sizes in dev-\u003ecfg/dev-\u003ecfg_pending and validating queue configurations upon ring changes) and implements multi-page RX buffer descriptor support in the Meta fbnic driver.\n\n- Memory Initialization: All newly allocated kernel objects (dev-\u003ecfg via kzalloc_obj in netdev_alloc_config and cloned via kmemdup in netdev_reconfig_start) and stack structures (qcfg in __netdev_queue_config) are explicitly zero-initialized using kzalloc/kmemdup/memset prior to usage.\n- User-Kernel Boundary: No uninitialized kernel struct fields or padding bytes are exposed to user space. Ethtool notifications and ioctls use existing initialized data paths.\n- Driver Logic: Changes in fbnic modify descriptor indexing, page offset calculations, and ring sizing logic based on bd_page_shift. Any boundary or calculation errors here would involve out-of-bounds ring accesses or DMA descriptor management, which are detectable by KASAN or hardware/driver assertions, rather than reads of uninitialized memory.\n\nBecause no uninitialized memory risks or info-leaks are introduced or exposed, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|