| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/26 00:02 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch primarily modifies the Xilinx AXI Ethernet driver (a platform driver for Xilinx FPGAs/SoCs) to add support for the XXV (10G/25G) MAC. Platform devices require specific device tree nodes to be probed and are not discoverable like PCI/USB devices. Since standard fuzzing environments (e.g., x86_64 q35, arm64 virt) do not instantiate these Xilinx-specific platform devices, the modified driver code is unreachable. The only core change is the addition of `devm_clk_bulk_get_enable`, which is a trivial 5-line wrapper.",
"WorthFuzzing": false
} |
| 1/1 | 2026/07/26 00:02 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 742257010ef8257f84d443f4659d41c17caf2887\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sun Jul 26 00:02:14 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml\nindex fb02e579463c98..23b1a27c04e553 100644\n--- a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml\n+++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml\n@@ -4,36 +4,46 @@\n $id: http://devicetree.org/schemas/net/xlnx,axi-ethernet.yaml#\n $schema: http://devicetree.org/meta-schemas/core.yaml#\n \n-title: AXI 1G/2.5G Ethernet Subsystem\n+title: Xilinx AXI Ethernet Subsystem\n \n description: |\n- Also called AXI 1G/2.5G Ethernet Subsystem, the xilinx axi ethernet IP core\n- provides connectivity to an external ethernet PHY supporting different\n- interfaces: MII, GMII, RGMII, SGMII, 1000BaseX. It also includes two\n- segments of memory for buffering TX and RX, as well as the capability of\n- offloading TX/RX checksum calculation off the processor.\n+ This binding describes Xilinx AXI Ethernet subsystem IPs, including the\n+ AXI 1G/2.5G Ethernet Subsystem and the 10G/25G (XXV) Ethernet Subsystem.\n+\n+ The AXI 1G/2.5G Ethernet Subsystem provides connectivity to an external\n+ ethernet PHY supporting different interfaces: MII, GMII, RGMII, SGMII,\n+ 1000BaseX. It also includes two segments of memory for buffering TX and RX,\n+ as well as the capability of offloading TX/RX checksum calculation off the\n+ processor.\n \n Management configuration is done through the AXI interface, while payload is\n sent and received through means of an AXI DMA controller. This driver\n includes the DMA driver code, so this driver is incompatible with AXI DMA\n driver.\n \n+ The XXV Ethernet Subsystem integrates a 10G/25G Ethernet MAC and PCS/PMA\n+ connected to a high-speed serial transceiver. It supports the 10GBASE-R and\n+ 25GBASE-R line rates, with 25G operation following the 25G Ethernet\n+ Consortium specification. Its payload is moved by an external AXI DMA\n+ controller rather than a DMA engine integrated into the MAC.\n+\n maintainers:\n - Radhey Shyam Pandey \u003cradhey.shyam.pandey@xilinx.com\u003e\n \n properties:\n compatible:\n enum:\n- - xlnx,axi-ethernet-1.00.a\n- - xlnx,axi-ethernet-1.01.a\n- - xlnx,axi-ethernet-2.01.a\n+ - xlnx,axi-ethernet-1.00.a # AXI 1G/2.5G Ethernet Subsystem\n+ - xlnx,axi-ethernet-1.01.a # AXI 1G/2.5G Ethernet Subsystem\n+ - xlnx,axi-ethernet-2.01.a # AXI 1G/2.5G Ethernet Subsystem\n+ - xlnx,xxv-ethernet-1.0 # 10G/25G Ethernet Subsystem\n \n reg:\n description:\n- Address and length of the IO space, as well as the address\n- and length of the AXI DMA controller IO space, unless\n- axistream-connected is specified, in which case the reg\n- attribute of the node referenced by it is used.\n+ Address and length of the IO space. For AXI 1G/2.5G using the legacy\n+ embedded DMA, this also covers the AXI DMA controller IO space, unless\n+ axistream-connected is specified, in which case the reg attribute of\n+ the node referenced by it is used.\n minItems: 1\n maxItems: 2\n \n@@ -62,6 +72,8 @@ properties:\n - rgmii\n - sgmii\n - 1000base-x\n+ - 10gbase-r\n+ - 25gbase-r\n \n xlnx,phy-type:\n description:\n@@ -93,19 +105,12 @@ properties:\n selected on core reset (i.e. by the basex_or_sgmii core input line).\n \n clocks:\n- items:\n- - description: Clock for AXI register slave interface.\n- - description: AXI4-Stream clock for TXD RXD TXC and RXS interfaces.\n- - description: Ethernet reference clock, used by signal delay primitives\n- and transceivers.\n- - description: MGT reference clock (used by optional internal PCS/PMA PHY)\n+ minItems: 3\n+ maxItems: 4\n \n clock-names:\n- items:\n- - const: s_axi_lite_clk\n- - const: axis_clk\n- - const: ref_clk\n- - const: mgt_clk\n+ minItems: 3\n+ maxItems: 4\n \n axistream-connected:\n $ref: /schemas/types.yaml#/definitions/phandle\n@@ -139,15 +144,88 @@ properties:\n \n required:\n - compatible\n- - interrupts\n - reg\n - xlnx,rxmem\n- - phy-handle\n \n allOf:\n - $ref: /schemas/net/ethernet-controller.yaml#\n \n-additionalProperties: false\n+ - if:\n+ properties:\n+ compatible:\n+ contains:\n+ enum:\n+ - xlnx,axi-ethernet-1.00.a\n+ - xlnx,axi-ethernet-1.01.a\n+ - xlnx,axi-ethernet-2.01.a\n+ then:\n+ required:\n+ - interrupts\n+ - phy-handle\n+ properties:\n+ phy-mode:\n+ enum:\n+ - mii\n+ - gmii\n+ - rgmii\n+ - sgmii\n+ - 1000base-x\n+ clocks:\n+ items:\n+ - description: Clock for AXI register slave interface.\n+ - description: AXI4-Stream clock for TXD RXD TXC and RXS\n+ interfaces.\n+ - description: Ethernet reference clock, used by signal delay\n+ primitives and transceivers.\n+ - description: MGT reference clock (used by optional internal\n+ PCS/PMA PHY)\n+ clock-names:\n+ items:\n+ - const: s_axi_lite_clk\n+ - const: axis_clk\n+ - const: ref_clk\n+ - const: mgt_clk\n+\n+ - if:\n+ properties:\n+ compatible:\n+ contains:\n+ const: xlnx,xxv-ethernet-1.0\n+ then:\n+ required:\n+ - dmas\n+ - dma-names\n+ - phy-mode\n+ - clocks\n+ - clock-names\n+ properties:\n+ phy-mode:\n+ enum:\n+ - 10gbase-r\n+ - 25gbase-r\n+ interrupts: false\n+ phy-handle: false\n+ pcs-handle: false\n+ axistream-connected: false\n+ xlnx,phy-type: false\n+ xlnx,txcsum: false\n+ xlnx,rxcsum: false\n+ xlnx,switch-x-sgmii: false\n+ mdio: false\n+ clocks:\n+ maxItems: 3\n+ items:\n+ - description: RX AXI4-Stream clock (rx_core_clk).\n+ - description: GT DRP clock (dclk).\n+ - description: AXI4-Lite register clock (s_axi_aclk).\n+ clock-names:\n+ maxItems: 3\n+ items:\n+ - const: rx_core_clk\n+ - const: dclk\n+ - const: s_axi_aclk\n+\n+unevaluatedProperties: false\n \n examples:\n - |\n@@ -198,3 +276,15 @@ examples:\n };\n };\n };\n+\n+ - |\n+ ethernet@80000000 {\n+ compatible = \"xlnx,xxv-ethernet-1.0\";\n+ reg = \u003c0x80000000 0x10000\u003e;\n+ clock-names = \"rx_core_clk\", \"dclk\", \"s_axi_aclk\";\n+ clocks = \u003c\u0026rx_clk\u003e, \u003c\u0026drp_clk\u003e, \u003c\u0026axi_clk\u003e;\n+ dma-names = \"tx_chan0\", \"rx_chan0\";\n+ dmas = \u003c\u0026axi_dma 0\u003e, \u003c\u0026axi_dma 1\u003e;\n+ phy-mode = \"25gbase-r\";\n+ xlnx,rxmem = \u003c0x8000\u003e;\n+ };\ndiff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst\nindex 017fb155a5bc25..5067500ded5cc7 100644\n--- a/Documentation/driver-api/driver-model/devres.rst\n+++ b/Documentation/driver-api/driver-model/devres.rst\n@@ -248,6 +248,7 @@ CLOCK\n devm_clk_put()\n devm_clk_bulk_get()\n devm_clk_bulk_get_all()\n+ devm_clk_bulk_get_enable()\n devm_clk_bulk_get_optional()\n devm_get_clk_from_child()\n devm_clk_hw_register()\ndiff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c\nindex 994d5bc5168be9..49d4782991eb98 100644\n--- a/drivers/clk/clk-devres.c\n+++ b/drivers/clk/clk-devres.c\n@@ -222,6 +222,13 @@ static int __devm_clk_bulk_get_enable(struct device *dev, int num_clks,\n \treturn ret;\n }\n \n+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,\n+\t\t\t\t\t struct clk_bulk_data *clks)\n+{\n+\treturn __devm_clk_bulk_get_enable(dev, num_clks, clks, false);\n+}\n+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);\n+\n int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,\n \t\t\t\t\t\t struct clk_bulk_data *clks)\n {\ndiff --git a/drivers/net/ethernet/xilinx/Makefile b/drivers/net/ethernet/xilinx/Makefile\nindex 7d7dc1771423e8..db90e691fec580 100644\n--- a/drivers/net/ethernet/xilinx/Makefile\n+++ b/drivers/net/ethernet/xilinx/Makefile\n@@ -6,5 +6,6 @@\n ll_temac-objs := ll_temac_main.o ll_temac_mdio.o\n obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o\n obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o\n-xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o\n+xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o \\\n+\t\t xilinx_axienet_xxv.o\n obj-$(CONFIG_XILINX_AXI_EMAC) += xilinx_emac.o\ndiff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h\nindex fcd3aaef27fc32..2ea086fc4dc367 100644\n--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h\n+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h\n@@ -10,6 +10,7 @@\n #define XILINX_AXIENET_H\n \n #include \u003clinux/dim.h\u003e\n+#include \u003clinux/ethtool.h\u003e\n #include \u003clinux/netdevice.h\u003e\n #include \u003clinux/spinlock.h\u003e\n #include \u003clinux/interrupt.h\u003e\n@@ -17,6 +18,8 @@\n #include \u003clinux/phylink.h\u003e\n #include \u003clinux/skbuff.h\u003e\n \n+#include \"xilinx_axienet_xxv.h\"\n+\n /* Packet size info */\n #define XAE_HDR_SIZE\t\t\t14 /* Size of Ethernet header */\n #define XAE_TRL_SIZE\t\t\t 4 /* Size of Ethernet trailer (FCS) */\n@@ -545,6 +548,9 @@ struct skbuf_dma_descriptor {\n * @tx_ring_tail: TX skb ring buffer tail index.\n * @rx_ring_head: RX skb ring buffer head index.\n * @rx_ring_tail: RX skb ring buffer tail index.\n+ * @xxv_ip_version: XXV IP version.\n+ * @xxv_stat_base: Software accumulators for the XXV clear-on-tick counters.\n+ * @axienet_config: MAC-type specific configuration and operations.\n */\n struct axienet_local {\n \tstruct net_device *ndev;\n@@ -598,6 +604,7 @@ struct axienet_local {\n \n \tu64 hw_stat_base[STAT_COUNT];\n \tu32 hw_last_counter[STAT_COUNT];\n+\tu64 xxv_stat_base[XXV_STAT_COUNT];\n \tseqcount_mutex_t hw_stats_seqcount;\n \tstruct mutex stats_lock;\n \tstruct delayed_work stats_work;\n@@ -626,8 +633,88 @@ struct axienet_local {\n \tint tx_ring_tail;\n \tint rx_ring_head;\n \tint rx_ring_tail;\n+\tu32 xxv_ip_version;\n+\tconst struct axienet_config *axienet_config;\n };\n \n+/**\n+ * struct axienet_config - MAC-type specific configuration and operations\n+ * @mdio: MAC has an MDIO bus for external PHY management\n+ * @mac_irq: MAC has a dedicated core interrupt\n+ * @legacy_dma: MAC supports the legacy (non-dmaengine) DMA mode\n+ * @uc_filter: MAC has unicast address filter registers\n+ * @mc_filter: MAC has multicast address filter registers\n+ * @vlan: MAC supports VLAN frames by default\n+ * @jumbo: MAC supports jumbo frames\n+ * @dma_tx_csum: MAC supports TX checksum offload\n+ * @sw_padding: Short frames must be padded in software before transmit\n+ * @internal_pcs: MAC always drives an internal PCS\n+ * @regs_n: Number of MAC registers exposed through ethtool -d\n+ * @clk_init: Callback to get and enable the MAC-specific clocks\n+ * @setoptions: Callback to program MAC hardware options\n+ * @probe_init: Callback for MAC-specific probe-time init, or NULL if unused\n+ * @gt_reset: Callback to reset the serial transceiver (GT), or NULL if unused\n+ * @mac_init: Callback for MAC-specific bring-up after the DMA reset\n+ * @mac_link_up: Callback to program link speed and pause on link up, or NULL\n+ * @get_regs: Callback to dump the MAC registers for ethtool -d\n+ * @phylink_set_caps: Callback to set phylink MAC capabilities\n+ * @pcs_ops: phylink PCS operations for this MAC, or NULL if unused\n+ * @stats_update: Callback to latch/accumulate the periodic MAC counters\n+ * @get_stats64: Callback to read MAC counters into rtnl_link_stats64\n+ * @get_ethtool_stats: Callback to read MAC counters for ethtool -S\n+ * @get_strings: Callback to fill the ethtool -S statistic name strings\n+ * @get_sset_count: Callback returning the number of ethtool -S statistics\n+ * @get_pause_stats: Callback to read MAC pause-frame counters\n+ * @get_eth_mac_stats: Callback to read IEEE 802.3 MAC counters\n+ * @get_eth_ctrl_stats: Callback to read MAC-control frame counters, or NULL\n+ *\t\t\tif the MAC exposes no control-frame counters\n+ * @get_rmon_stats: Callback to read RMON counters and histogram ranges\n+ */\n+struct axienet_config {\n+\tbool mdio;\n+\tbool mac_irq;\n+\tbool legacy_dma;\n+\tbool uc_filter;\n+\tbool mc_filter;\n+\tbool vlan;\n+\tbool jumbo;\n+\tbool dma_tx_csum;\n+\tbool sw_padding;\n+\tbool internal_pcs;\n+\tunsigned int regs_n;\n+\tint (*clk_init)(struct axienet_local *lp);\n+\tvoid (*setoptions)(struct net_device *ndev, u32 options);\n+\tvoid (*probe_init)(struct axienet_local *lp);\n+\tvoid (*gt_reset)(struct axienet_local *lp);\n+\tint (*mac_init)(struct net_device *ndev);\n+\tvoid (*mac_link_up)(struct net_device *ndev, int speed,\n+\t\t\t bool tx_pause, bool rx_pause);\n+\tvoid (*get_regs)(struct axienet_local *lp, u32 *data);\n+\tvoid (*phylink_set_caps)(struct axienet_local *lp,\n+\t\t\t\t struct phylink_config *config);\n+\tconst struct phylink_pcs_ops *pcs_ops;\n+\tvoid (*stats_update)(struct axienet_local *lp);\n+\tvoid (*get_stats64)(struct axienet_local *lp,\n+\t\t\t struct rtnl_link_stats64 *stats);\n+\tvoid (*get_ethtool_stats)(struct axienet_local *lp, u64 *data);\n+\tvoid (*get_strings)(u8 *data);\n+\tint (*get_sset_count)(void);\n+\tvoid (*get_pause_stats)(struct axienet_local *lp,\n+\t\t\t\tstruct ethtool_pause_stats *pause_stats);\n+\tvoid (*get_eth_mac_stats)(struct axienet_local *lp,\n+\t\t\t\t struct ethtool_eth_mac_stats *mac_stats);\n+\tvoid (*get_eth_ctrl_stats)(struct axienet_local *lp,\n+\t\t\t\t struct ethtool_eth_ctrl_stats *ctrl_stats);\n+\tvoid (*get_rmon_stats)(struct axienet_local *lp,\n+\t\t\t struct ethtool_rmon_stats *rmon_stats,\n+\t\t\t const struct ethtool_rmon_hist_range **ranges);\n+};\n+\n+static inline struct axienet_local *pcs_to_axienet_local(struct phylink_pcs *pcs)\n+{\n+\treturn container_of(pcs, struct axienet_local, pcs);\n+}\n+\n /**\n * struct axienet_option - Used to set axi ethernet hardware options\n * @opt:\tOption to be set.\n@@ -741,4 +828,7 @@ static inline void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,\n int axienet_mdio_setup(struct axienet_local *lp);\n void axienet_mdio_teardown(struct axienet_local *lp);\n \n+/* RMON histogram ranges shared by all MAC types */\n+extern const struct ethtool_rmon_hist_range axienet_rmon_ranges[];\n+\n #endif /* XILINX_AXI_ENET_H */\ndiff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c\nindex fcf517069d161a..b715d13ccb8eec 100644\n--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c\n+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c\n@@ -33,6 +33,7 @@\n #include \u003clinux/of_irq.h\u003e\n #include \u003clinux/of_address.h\u003e\n #include \u003clinux/platform_device.h\u003e\n+#include \u003clinux/property.h\u003e\n #include \u003clinux/skbuff.h\u003e\n #include \u003clinux/math64.h\u003e\n #include \u003clinux/phy.h\u003e\n@@ -65,16 +66,6 @@\n \n static void axienet_rx_submit_desc(struct net_device *ndev);\n \n-/* Match table for of_platform binding */\n-static const struct of_device_id axienet_of_match[] = {\n-\t{ .compatible = \"xlnx,axi-ethernet-1.00.a\", },\n-\t{ .compatible = \"xlnx,axi-ethernet-1.01.a\", },\n-\t{ .compatible = \"xlnx,axi-ethernet-2.01.a\", },\n-\t{},\n-};\n-\n-MODULE_DEVICE_TABLE(of, axienet_of_match);\n-\n /* Option table for setting up Axi Ethernet hardware options */\n static struct axienet_option axienet_options[] = {\n \t/* Turn on jumbo packet support for both Rx and Tx */\n@@ -419,6 +410,9 @@ static void axienet_set_mac_address(struct net_device *ndev,\n \tif (!is_valid_ether_addr(ndev-\u003edev_addr))\n \t\teth_hw_addr_random(ndev);\n \n+\tif (!lp-\u003eaxienet_config-\u003euc_filter)\n+\t\treturn;\n+\n \t/* Set up unicast MAC address filter set its mac address */\n \taxienet_iow(lp, XAE_UAW0_OFFSET,\n \t\t (ndev-\u003edev_addr[0]) |\n@@ -468,6 +462,9 @@ static void axienet_set_multicast_list(struct net_device *ndev)\n \tu32 reg, af0reg, af1reg;\n \tstruct axienet_local *lp = netdev_priv(ndev);\n \n+\tif (!lp-\u003eaxienet_config-\u003emc_filter)\n+\t\treturn;\n+\n \treg = axienet_ior(lp, XAE_FMI_OFFSET);\n \treg \u0026= ~XAE_FMI_PM_MASK;\n \tif (ndev-\u003eflags \u0026 IFF_PROMISC)\n@@ -576,16 +573,31 @@ static void axienet_stats_update(struct axienet_local *lp, bool reset)\n \twrite_seqcount_end(\u0026lp-\u003ehw_stats_seqcount);\n }\n \n+/**\n+ * axienet_1g_stats_update - Refresh 1G MAC hardware statistics\n+ * @lp:\t\tPointer to the axienet_local structure\n+ */\n+static void axienet_1g_stats_update(struct axienet_local *lp)\n+{\n+\taxienet_stats_update(lp, false);\n+}\n+\n static void axienet_refresh_stats(struct work_struct *work)\n {\n \tstruct axienet_local *lp = container_of(work, struct axienet_local,\n \t\t\t\t\t\tstats_work.work);\n \n-\tmutex_lock(\u0026lp-\u003estats_lock);\n-\taxienet_stats_update(lp, false);\n-\tmutex_unlock(\u0026lp-\u003estats_lock);\n+\tif (lp-\u003eaxienet_config-\u003estats_update) {\n+\t\tmutex_lock(\u0026lp-\u003estats_lock);\n+\t\tlp-\u003eaxienet_config-\u003estats_update(lp);\n+\t\tmutex_unlock(\u0026lp-\u003estats_lock);\n+\t}\n \n-\t/* Just less than 2^32 bytes at 2.5 GBit/s */\n+\t/* Re-arm the poll before any counter can overflow between updates: the\n+\t * 1G byte counter reaches just under 2^32 in this interval at 2.5 Gbit/s,\n+\t * and the XXV internal accumulators must be latched (via TICK in\n+\t * axienet_xxv_stats_update()) before they saturate at line rate.\n+\t */\n \tschedule_delayed_work(\u0026lp-\u003estats_work, 13 * HZ);\n }\n \n@@ -594,7 +606,16 @@ static int __axienet_device_reset(struct axienet_local *lp)\n \tu32 value;\n \tint ret;\n \n-\t/* Save statistics counters in case they will be reset */\n+\t/* Save statistics counters in case they will be reset.\n+\t *\n+\t * The XAE_FEATURE_STATS blocks in this function read the TEMAC\n+\t * statistics registers at XAE_STATS_OFFSET, i.e. they assume the 1G\n+\t * counter layout. This is safe because __axienet_device_reset() is\n+\t * only reached on the legacy (non-dmaengine) DMA path, which the\n+\t * legacy_dma capability restricts to the 1G MAC. MACs that use their\n+\t * own statistics mechanism (e.g. XXV, which is dmaengine-only) never\n+\t * execute this path.\n+\t */\n \tmutex_lock(\u0026lp-\u003estats_lock);\n \tif (lp-\u003efeatures \u0026 XAE_FEATURE_STATS)\n \t\taxienet_stats_update(lp, true);\n@@ -694,6 +715,32 @@ static void axienet_dma_stop(struct axienet_local *lp)\n \taxienet_unlock_mii(lp);\n }\n \n+/**\n+ * axienet_1g_mac_init - 1G MAC-specific bring-up after the DMA reset\n+ * @ndev:\tPointer to the net_device structure\n+ *\n+ * Return: 0 on success or a negative error number otherwise.\n+ */\n+static int axienet_1g_mac_init(struct net_device *ndev)\n+{\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\tu32 axienet_status;\n+\n+\taxienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);\n+\taxienet_status \u0026= ~XAE_RCW1_RX_MASK;\n+\taxienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);\n+\n+\taxienet_status = axienet_ior(lp, XAE_IP_OFFSET);\n+\tif (axienet_status \u0026 XAE_INT_RXRJECT_MASK)\n+\t\taxienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);\n+\taxienet_iow(lp, XAE_IE_OFFSET, lp-\u003eeth_irq \u003e 0 ?\n+\t\t XAE_INT_RECV_ERROR_MASK : 0);\n+\n+\taxienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);\n+\n+\treturn 0;\n+}\n+\n /**\n * axienet_device_reset - Reset and initialize the Axi Ethernet hardware.\n * @ndev:\tPointer to the net_device structure\n@@ -709,19 +756,23 @@ static void axienet_dma_stop(struct axienet_local *lp)\n */\n static int axienet_device_reset(struct net_device *ndev)\n {\n-\tu32 axienet_status;\n \tstruct axienet_local *lp = netdev_priv(ndev);\n \tint ret;\n \n+\tif (lp-\u003eaxienet_config-\u003egt_reset)\n+\t\tlp-\u003eaxienet_config-\u003egt_reset(lp);\n+\n \tlp-\u003emax_frm_size = XAE_MAX_VLAN_FRAME_SIZE;\n-\tlp-\u003eoptions |= XAE_OPTION_VLAN;\n+\n+\tif (lp-\u003eaxienet_config-\u003evlan)\n+\t\tlp-\u003eoptions |= XAE_OPTION_VLAN;\n \tlp-\u003eoptions \u0026= (~XAE_OPTION_JUMBO);\n \n \tif (ndev-\u003emtu \u003e XAE_MTU \u0026\u0026 ndev-\u003emtu \u003c= XAE_JUMBO_MTU) {\n \t\tlp-\u003emax_frm_size = ndev-\u003emtu + VLAN_ETH_HLEN +\n \t\t\t\t\tXAE_TRL_SIZE;\n \n-\t\tif (lp-\u003emax_frm_size \u003c= lp-\u003erxmem)\n+\t\tif (lp-\u003emax_frm_size \u003c= lp-\u003erxmem \u0026\u0026 lp-\u003eaxienet_config-\u003ejumbo)\n \t\t\tlp-\u003eoptions |= XAE_OPTION_JUMBO;\n \t}\n \n@@ -738,26 +789,18 @@ static int axienet_device_reset(struct net_device *ndev)\n \t\t}\n \t}\n \n-\taxienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);\n-\taxienet_status \u0026= ~XAE_RCW1_RX_MASK;\n-\taxienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);\n-\n-\taxienet_status = axienet_ior(lp, XAE_IP_OFFSET);\n-\tif (axienet_status \u0026 XAE_INT_RXRJECT_MASK)\n-\t\taxienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);\n-\taxienet_iow(lp, XAE_IE_OFFSET, lp-\u003eeth_irq \u003e 0 ?\n-\t\t XAE_INT_RECV_ERROR_MASK : 0);\n-\n-\taxienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);\n+\tret = lp-\u003eaxienet_config-\u003emac_init(ndev);\n+\tif (ret)\n+\t\treturn ret;\n \n \t/* Sync default options with HW but leave receiver and\n \t * transmitter disabled.\n \t */\n-\taxienet_setoptions(ndev, lp-\u003eoptions \u0026\n-\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n+\tlp-\u003eaxienet_config-\u003esetoptions(ndev, lp-\u003eoptions \u0026\n+\t\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n \taxienet_set_mac_address(ndev, NULL);\n \taxienet_set_multicast_list(ndev);\n-\taxienet_setoptions(ndev, lp-\u003eoptions);\n+\tlp-\u003eaxienet_config-\u003esetoptions(ndev, lp-\u003eoptions);\n \n \tnetif_trans_update(ndev);\n \n@@ -915,6 +958,13 @@ axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev)\n \tint sg_len;\n \tint ret;\n \n+\tif (lp-\u003eaxienet_config-\u003esw_padding \u0026\u0026 eth_skb_pad(skb)) {\n+\t\t/* Pad short frames; the MAC does not append Ethernet padding. */\n+\t\tndev-\u003estats.tx_dropped++;\n+\t\tndev-\u003estats.tx_errors++;\n+\t\treturn NETDEV_TX_OK;\n+\t}\n+\n \tdma_dev = lp-\u003etx_chan-\u003edevice;\n \tsg_len = skb_shinfo(skb)-\u003enr_frags + 1;\n \tif (CIRC_SPACE(lp-\u003etx_ring_head, lp-\u003etx_ring_tail, TX_BD_NUM_MAX) \u003c= 1) {\n@@ -939,19 +989,21 @@ axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev)\n \t\tgoto xmit_error_drop_skb;\n \n \t/* Fill up app fields for checksum */\n-\tif (skb-\u003eip_summed == CHECKSUM_PARTIAL) {\n-\t\tif (lp-\u003efeatures \u0026 XAE_FEATURE_FULL_TX_CSUM) {\n-\t\t\t/* Tx Full Checksum Offload Enabled */\n-\t\t\tapp_metadata[0] |= 2;\n-\t\t} else if (lp-\u003efeatures \u0026 XAE_FEATURE_PARTIAL_TX_CSUM) {\n-\t\t\tcsum_start_off = skb_transport_offset(skb);\n-\t\t\tcsum_index_off = csum_start_off + skb-\u003ecsum_offset;\n-\t\t\t/* Tx Partial Checksum Offload Enabled */\n-\t\t\tapp_metadata[0] |= 1;\n-\t\t\tapp_metadata[1] = (csum_start_off \u003c\u003c 16) | csum_index_off;\n+\tif (lp-\u003eaxienet_config-\u003edma_tx_csum) {\n+\t\tif (skb-\u003eip_summed == CHECKSUM_PARTIAL) {\n+\t\t\tif (lp-\u003efeatures \u0026 XAE_FEATURE_FULL_TX_CSUM) {\n+\t\t\t\t/* Tx Full Checksum Offload Enabled */\n+\t\t\t\tapp_metadata[0] |= 2;\n+\t\t\t} else if (lp-\u003efeatures \u0026 XAE_FEATURE_PARTIAL_TX_CSUM) {\n+\t\t\t\tcsum_start_off = skb_transport_offset(skb);\n+\t\t\t\tcsum_index_off = csum_start_off + skb-\u003ecsum_offset;\n+\t\t\t\t/* Tx Partial Checksum Offload Enabled */\n+\t\t\t\tapp_metadata[0] |= 1;\n+\t\t\t\tapp_metadata[1] = (csum_start_off \u003c\u003c 16) | csum_index_off;\n+\t\t\t}\n+\t\t} else if (skb-\u003eip_summed == CHECKSUM_UNNECESSARY) {\n+\t\t\tapp_metadata[0] |= 2; /* Tx Full Checksum Offload Enabled */\n \t\t}\n-\t} else if (skb-\u003eip_summed == CHECKSUM_UNNECESSARY) {\n-\t\tapp_metadata[0] |= 2; /* Tx Full Checksum Offload Enabled */\n \t}\n \n \tdma_tx_desc = dma_dev-\u003edevice_prep_slave_sg(lp-\u003etx_chan, skbuf_dma-\u003esgl,\n@@ -1670,6 +1722,10 @@ static int axienet_open(struct net_device *ndev)\n \taxienet_lock_mii(lp);\n \tret = axienet_device_reset(ndev);\n \taxienet_unlock_mii(lp);\n+\tif (ret) {\n+\t\tdev_err(lp-\u003edev, \"axienet_device_reset() failed: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n \n \tret = phylink_of_phy_connect(lp-\u003ephylink, lp-\u003edev-\u003eof_node, 0);\n \tif (ret) {\n@@ -1738,12 +1794,17 @@ static int axienet_stop(struct net_device *ndev)\n \n \tcancel_work_sync(\u0026lp-\u003erx_dim.work);\n \tcancel_delayed_work_sync(\u0026lp-\u003estats_work);\n+\tif (lp-\u003eaxienet_config-\u003estats_update) {\n+\t\tmutex_lock(\u0026lp-\u003estats_lock);\n+\t\tlp-\u003eaxienet_config-\u003estats_update(lp);\n+\t\tmutex_unlock(\u0026lp-\u003estats_lock);\n+\t}\n \n \tphylink_stop(lp-\u003ephylink);\n \tphylink_disconnect_phy(lp-\u003ephylink);\n \n-\taxienet_setoptions(ndev, lp-\u003eoptions \u0026\n-\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n+\tlp-\u003eaxienet_config-\u003esetoptions(ndev, lp-\u003eoptions \u0026\n+\t\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n \n \tif (!lp-\u003euse_dmaengine) {\n \t\taxienet_dma_stop(lp);\n@@ -1769,7 +1830,8 @@ static int axienet_stop(struct net_device *ndev)\n \t}\n \n \tnetdev_reset_queue(ndev);\n-\taxienet_iow(lp, XAE_IE_OFFSET, 0);\n+\tif (lp-\u003eaxienet_config-\u003emac_irq)\n+\t\taxienet_iow(lp, XAE_IE_OFFSET, 0);\n \n \tif (lp-\u003eeth_irq \u003e 0)\n \t\tfree_irq(lp-\u003eeth_irq, ndev);\n@@ -1834,29 +1896,11 @@ static int axienet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)\n \treturn phylink_mii_ioctl(lp-\u003ephylink, rq, cmd);\n }\n \n-static void\n-axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)\n+static void axienet_1g_get_stats64(struct axienet_local *lp,\n+\t\t\t\t struct rtnl_link_stats64 *stats)\n {\n-\tstruct axienet_local *lp = netdev_priv(dev);\n \tunsigned int start;\n \n-\tnetdev_stats_to_stats64(stats, \u0026dev-\u003estats);\n-\n-\tdo {\n-\t\tstart = u64_stats_fetch_begin(\u0026lp-\u003erx_stat_sync);\n-\t\tstats-\u003erx_packets = u64_stats_read(\u0026lp-\u003erx_packets);\n-\t\tstats-\u003erx_bytes = u64_stats_read(\u0026lp-\u003erx_bytes);\n-\t} while (u64_stats_fetch_retry(\u0026lp-\u003erx_stat_sync, start));\n-\n-\tdo {\n-\t\tstart = u64_stats_fetch_begin(\u0026lp-\u003etx_stat_sync);\n-\t\tstats-\u003etx_packets = u64_stats_read(\u0026lp-\u003etx_packets);\n-\t\tstats-\u003etx_bytes = u64_stats_read(\u0026lp-\u003etx_bytes);\n-\t} while (u64_stats_fetch_retry(\u0026lp-\u003etx_stat_sync, start));\n-\n-\tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n-\t\treturn;\n-\n \tdo {\n \t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n \t\tstats-\u003erx_length_errors =\n@@ -1884,6 +1928,33 @@ axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)\n \t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n }\n \n+static void\n+axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)\n+{\n+\tstruct axienet_local *lp = netdev_priv(dev);\n+\tunsigned int start;\n+\n+\tnetdev_stats_to_stats64(stats, \u0026dev-\u003estats);\n+\n+\tdo {\n+\t\tstart = u64_stats_fetch_begin(\u0026lp-\u003erx_stat_sync);\n+\t\tstats-\u003erx_packets = u64_stats_read(\u0026lp-\u003erx_packets);\n+\t\tstats-\u003erx_bytes = u64_stats_read(\u0026lp-\u003erx_bytes);\n+\t} while (u64_stats_fetch_retry(\u0026lp-\u003erx_stat_sync, start));\n+\n+\tdo {\n+\t\tstart = u64_stats_fetch_begin(\u0026lp-\u003etx_stat_sync);\n+\t\tstats-\u003etx_packets = u64_stats_read(\u0026lp-\u003etx_packets);\n+\t\tstats-\u003etx_bytes = u64_stats_read(\u0026lp-\u003etx_bytes);\n+\t} while (u64_stats_fetch_retry(\u0026lp-\u003etx_stat_sync, start));\n+\n+\tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n+\t\treturn;\n+\n+\tif (lp-\u003eaxienet_config-\u003eget_stats64)\n+\t\tlp-\u003eaxienet_config-\u003eget_stats64(lp, stats);\n+}\n+\n static const struct net_device_ops axienet_netdev_ops = {\n \t.ndo_open = axienet_open,\n \t.ndo_stop = axienet_stop,\n@@ -1938,30 +2009,18 @@ static void axienet_ethtools_get_drvinfo(struct net_device *ndev,\n */\n static int axienet_ethtools_get_regs_len(struct net_device *ndev)\n {\n-\treturn sizeof(u32) * AXIENET_REGS_N;\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\n+\treturn sizeof(u32) * lp-\u003eaxienet_config-\u003eregs_n;\n }\n \n /**\n- * axienet_ethtools_get_regs - Dump the contents of all registers present\n- *\t\t\t in AxiEthernet core.\n- * @ndev:\tPointer to net_device structure\n- * @regs:\tPointer to ethtool_regs structure\n- * @ret:\tVoid pointer used to return the contents of the registers.\n- *\n- * This implements ethtool command for getting the Axi Ethernet register dump.\n- * Issue \"ethtool -d ethX\" to execute this function.\n+ * axienet_1g_get_regs - Dump 1G MAC registers for ethtool\n+ * @lp:\t\tPointer to the axienet_local structure\n+ * @data:\tBuffer for register values (zeroed and sized by the caller)\n */\n-static void axienet_ethtools_get_regs(struct net_device *ndev,\n-\t\t\t\t struct ethtool_regs *regs, void *ret)\n+static void axienet_1g_get_regs(struct axienet_local *lp, u32 *data)\n {\n-\tu32 *data = (u32 *)ret;\n-\tsize_t len = sizeof(u32) * AXIENET_REGS_N;\n-\tstruct axienet_local *lp = netdev_priv(ndev);\n-\n-\tregs-\u003eversion = 0;\n-\tregs-\u003elen = len;\n-\n-\tmemset(data, 0, len);\n \tdata[0] = axienet_ior(lp, XAE_RAF_OFFSET);\n \tdata[1] = axienet_ior(lp, XAE_TPF_OFFSET);\n \tdata[2] = axienet_ior(lp, XAE_IFGP_OFFSET);\n@@ -2002,6 +2061,31 @@ static void axienet_ethtools_get_regs(struct net_device *ndev,\n \t}\n }\n \n+/**\n+ * axienet_ethtools_get_regs - Dump the contents of all registers present\n+ *\t\t\t in AxiEthernet core.\n+ * @ndev:\tPointer to net_device structure\n+ * @regs:\tPointer to ethtool_regs structure\n+ * @ret:\tVoid pointer used to return the contents of the registers.\n+ *\n+ * This implements ethtool command for getting the Axi Ethernet register dump.\n+ * Issue \"ethtool -d ethX\" to execute this function.\n+ */\n+static void axienet_ethtools_get_regs(struct net_device *ndev,\n+\t\t\t\t struct ethtool_regs *regs, void *ret)\n+{\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\tu32 *data = (u32 *)ret;\n+\tsize_t len;\n+\n+\tlen = sizeof(u32) * lp-\u003eaxienet_config-\u003eregs_n;\n+\tregs-\u003eversion = 0;\n+\tregs-\u003elen = len;\n+\n+\tmemset(data, 0, len);\n+\tlp-\u003eaxienet_config-\u003eget_regs(lp, data);\n+}\n+\n static void\n axienet_ethtools_get_ringparam(struct net_device *ndev,\n \t\t\t struct ethtool_ringparam *ering,\n@@ -2303,11 +2387,8 @@ static int axienet_ethtools_nway_reset(struct net_device *dev)\n \treturn phylink_ethtool_nway_reset(lp-\u003ephylink);\n }\n \n-static void axienet_ethtools_get_ethtool_stats(struct net_device *dev,\n-\t\t\t\t\t struct ethtool_stats *stats,\n-\t\t\t\t\t u64 *data)\n+static void axienet_1g_get_ethtool_stats(struct axienet_local *lp, u64 *data)\n {\n-\tstruct axienet_local *lp = netdev_priv(dev);\n \tunsigned int start;\n \n \tdo {\n@@ -2324,6 +2405,17 @@ static void axienet_ethtools_get_ethtool_stats(struct net_device *dev,\n \t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n }\n \n+static void axienet_ethtools_get_ethtool_stats(struct net_device *dev,\n+\t\t\t\t\t struct ethtool_stats *stats,\n+\t\t\t\t\t u64 *data)\n+{\n+\tstruct axienet_local *lp = netdev_priv(dev);\n+\n+\tif (lp-\u003efeatures \u0026 XAE_FEATURE_STATS \u0026\u0026\n+\t lp-\u003eaxienet_config-\u003eget_ethtool_stats)\n+\t\tlp-\u003eaxienet_config-\u003eget_ethtool_stats(lp, data);\n+}\n+\n static const char axienet_ethtool_stats_strings[][ETH_GSTRING_LEN] = {\n \t\"Received bytes\",\n \t\"Transmitted bytes\",\n@@ -2336,12 +2428,26 @@ static const char axienet_ethtool_stats_strings[][ETH_GSTRING_LEN] = {\n \t\"User Defined Counter 2\",\n };\n \n+static void axienet_1g_get_strings(u8 *data)\n+{\n+\tmemcpy(data, axienet_ethtool_stats_strings,\n+\t sizeof(axienet_ethtool_stats_strings));\n+}\n+\n+static int axienet_1g_get_sset_count(void)\n+{\n+\treturn ARRAY_SIZE(axienet_ethtool_stats_strings);\n+}\n+\n static void axienet_ethtools_get_strings(struct net_device *dev, u32 stringset, u8 *data)\n {\n+\tstruct axienet_local *lp = netdev_priv(dev);\n+\n \tswitch (stringset) {\n \tcase ETH_SS_STATS:\n-\t\tmemcpy(data, axienet_ethtool_stats_strings,\n-\t\t sizeof(axienet_ethtool_stats_strings));\n+\t\tif (lp-\u003efeatures \u0026 XAE_FEATURE_STATS \u0026\u0026\n+\t\t lp-\u003eaxienet_config-\u003eget_strings)\n+\t\t\tlp-\u003eaxienet_config-\u003eget_strings(data);\n \t\tbreak;\n \t}\n }\n@@ -2352,24 +2458,20 @@ static int axienet_ethtools_get_sset_count(struct net_device *dev, int sset)\n \n \tswitch (sset) {\n \tcase ETH_SS_STATS:\n-\t\tif (lp-\u003efeatures \u0026 XAE_FEATURE_STATS)\n-\t\t\treturn ARRAY_SIZE(axienet_ethtool_stats_strings);\n+\t\tif (lp-\u003efeatures \u0026 XAE_FEATURE_STATS \u0026\u0026\n+\t\t lp-\u003eaxienet_config-\u003eget_sset_count)\n+\t\t\treturn lp-\u003eaxienet_config-\u003eget_sset_count();\n \t\tfallthrough;\n \tdefault:\n \t\treturn -EOPNOTSUPP;\n \t}\n }\n \n-static void\n-axienet_ethtools_get_pause_stats(struct net_device *dev,\n-\t\t\t\t struct ethtool_pause_stats *pause_stats)\n+static void axienet_1g_get_pause_stats(struct axienet_local *lp,\n+\t\t\t\t struct ethtool_pause_stats *pause_stats)\n {\n-\tstruct axienet_local *lp = netdev_priv(dev);\n \tunsigned int start;\n \n-\tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n-\t\treturn;\n-\n \tdo {\n \t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n \t\tpause_stats-\u003etx_pause_frames =\n@@ -2380,15 +2482,23 @@ axienet_ethtools_get_pause_stats(struct net_device *dev,\n }\n \n static void\n-axienet_ethtool_get_eth_mac_stats(struct net_device *dev,\n-\t\t\t\t struct ethtool_eth_mac_stats *mac_stats)\n+axienet_ethtools_get_pause_stats(struct net_device *dev,\n+\t\t\t\t struct ethtool_pause_stats *pause_stats)\n {\n \tstruct axienet_local *lp = netdev_priv(dev);\n-\tunsigned int start;\n \n \tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n \t\treturn;\n \n+\tif (lp-\u003eaxienet_config-\u003eget_pause_stats)\n+\t\tlp-\u003eaxienet_config-\u003eget_pause_stats(lp, pause_stats);\n+}\n+\n+static void axienet_1g_get_eth_mac_stats(struct axienet_local *lp,\n+\t\t\t\t\t struct ethtool_eth_mac_stats *mac_stats)\n+{\n+\tunsigned int start;\n+\n \tdo {\n \t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n \t\tmac_stats-\u003eFramesTransmittedOK =\n@@ -2425,15 +2535,24 @@ axienet_ethtool_get_eth_mac_stats(struct net_device *dev,\n }\n \n static void\n-axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,\n-\t\t\t\t struct ethtool_eth_ctrl_stats *ctrl_stats)\n+axienet_ethtool_get_eth_mac_stats(struct net_device *dev,\n+\t\t\t\t struct ethtool_eth_mac_stats *mac_stats)\n {\n \tstruct axienet_local *lp = netdev_priv(dev);\n-\tunsigned int start;\n \n \tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n \t\treturn;\n \n+\tif (lp-\u003eaxienet_config-\u003eget_eth_mac_stats)\n+\t\tlp-\u003eaxienet_config-\u003eget_eth_mac_stats(lp, mac_stats);\n+}\n+\n+static void\n+axienet_1g_get_eth_ctrl_stats(struct axienet_local *lp,\n+\t\t\t struct ethtool_eth_ctrl_stats *ctrl_stats)\n+{\n+\tunsigned int start;\n+\n \tdo {\n \t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n \t\tctrl_stats-\u003eMACControlFramesTransmitted =\n@@ -2445,7 +2564,20 @@ axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,\n \t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n }\n \n-static const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {\n+static void\n+axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,\n+\t\t\t\t struct ethtool_eth_ctrl_stats *ctrl_stats)\n+{\n+\tstruct axienet_local *lp = netdev_priv(dev);\n+\n+\tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n+\t\treturn;\n+\n+\tif (lp-\u003eaxienet_config-\u003eget_eth_ctrl_stats)\n+\t\tlp-\u003eaxienet_config-\u003eget_eth_ctrl_stats(lp, ctrl_stats);\n+}\n+\n+const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {\n \t{ 64, 64 },\n \t{ 65, 127 },\n \t{ 128, 255 },\n@@ -2457,16 +2589,12 @@ static const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {\n };\n \n static void\n-axienet_ethtool_get_rmon_stats(struct net_device *dev,\n-\t\t\t struct ethtool_rmon_stats *rmon_stats,\n-\t\t\t const struct ethtool_rmon_hist_range **ranges)\n+axienet_1g_get_rmon_stats(struct axienet_local *lp,\n+\t\t\t struct ethtool_rmon_stats *rmon_stats,\n+\t\t\t const struct ethtool_rmon_hist_range **ranges)\n {\n-\tstruct axienet_local *lp = netdev_priv(dev);\n \tunsigned int start;\n \n-\tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n-\t\treturn;\n-\n \tdo {\n \t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n \t\trmon_stats-\u003eundersize_pkts =\n@@ -2510,6 +2638,20 @@ axienet_ethtool_get_rmon_stats(struct net_device *dev,\n \t*ranges = axienet_rmon_ranges;\n }\n \n+static void\n+axienet_ethtool_get_rmon_stats(struct net_device *dev,\n+\t\t\t struct ethtool_rmon_stats *rmon_stats,\n+\t\t\t const struct ethtool_rmon_hist_range **ranges)\n+{\n+\tstruct axienet_local *lp = netdev_priv(dev);\n+\n+\tif (!(lp-\u003efeatures \u0026 XAE_FEATURE_STATS))\n+\t\treturn;\n+\n+\tif (lp-\u003eaxienet_config-\u003eget_rmon_stats)\n+\t\tlp-\u003eaxienet_config-\u003eget_rmon_stats(lp, rmon_stats, ranges);\n+}\n+\n static const struct ethtool_ops axienet_ethtool_ops = {\n \t.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |\n \t\t\t\t ETHTOOL_COALESCE_USECS |\n@@ -2555,11 +2697,6 @@ static const struct ethtool_ops axienet_ethtool_dmaengine_ops = {\n \t.get_rmon_stats = axienet_ethtool_get_rmon_stats,\n };\n \n-static struct axienet_local *pcs_to_axienet_local(struct phylink_pcs *pcs)\n-{\n-\treturn container_of(pcs, struct axienet_local, pcs);\n-}\n-\n static void axienet_pcs_get_state(struct phylink_pcs *pcs,\n \t\t\t\t unsigned int neg_mode,\n \t\t\t\t struct phylink_link_state *state)\n@@ -2619,7 +2756,9 @@ static struct phylink_pcs *axienet_mac_select_pcs(struct phylink_config *config,\n \tstruct axienet_local *lp = netdev_priv(ndev);\n \n \tif (interface == PHY_INTERFACE_MODE_1000BASEX ||\n-\t interface == PHY_INTERFACE_MODE_SGMII)\n+\t interface == PHY_INTERFACE_MODE_SGMII ||\n+\t interface == PHY_INTERFACE_MODE_10GBASER ||\n+\t interface == PHY_INTERFACE_MODE_25GBASER)\n \t\treturn \u0026lp-\u003epcs;\n \n \treturn NULL;\n@@ -2638,13 +2777,9 @@ static void axienet_mac_link_down(struct phylink_config *config,\n \t/* nothing meaningful to do */\n }\n \n-static void axienet_mac_link_up(struct phylink_config *config,\n-\t\t\t\tstruct phy_device *phy,\n-\t\t\t\tunsigned int mode, phy_interface_t interface,\n-\t\t\t\tint speed, int duplex,\n-\t\t\t\tbool tx_pause, bool rx_pause)\n+static void axienet_1g_mac_link_up(struct net_device *ndev, int speed,\n+\t\t\t\t bool tx_pause, bool rx_pause)\n {\n-\tstruct net_device *ndev = to_net_dev(config-\u003edev);\n \tstruct axienet_local *lp = netdev_priv(ndev);\n \tu32 emmc_reg, fcc_reg;\n \n@@ -2681,6 +2816,19 @@ static void axienet_mac_link_up(struct phylink_config *config,\n \taxienet_iow(lp, XAE_FCC_OFFSET, fcc_reg);\n }\n \n+static void axienet_mac_link_up(struct phylink_config *config,\n+\t\t\t\tstruct phy_device *phy,\n+\t\t\t\tunsigned int mode, phy_interface_t interface,\n+\t\t\t\tint speed, int duplex,\n+\t\t\t\tbool tx_pause, bool rx_pause)\n+{\n+\tstruct net_device *ndev = to_net_dev(config-\u003edev);\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\n+\tif (lp-\u003eaxienet_config-\u003emac_link_up)\n+\t\tlp-\u003eaxienet_config-\u003emac_link_up(ndev, speed, tx_pause, rx_pause);\n+}\n+\n static const struct phylink_mac_ops axienet_phylink_ops = {\n \t.mac_select_pcs = axienet_mac_select_pcs,\n \t.mac_config = axienet_mac_config,\n@@ -2698,7 +2846,6 @@ static const struct phylink_mac_ops axienet_phylink_ops = {\n static void axienet_dma_err_handler(struct work_struct *work)\n {\n \tu32 i;\n-\tu32 axienet_status;\n \tstruct axidma_bd *cur_p;\n \tstruct axienet_local *lp = container_of(work, struct axienet_local,\n \t\t\t\t\t\tdma_err_task);\n@@ -2711,8 +2858,8 @@ static void axienet_dma_err_handler(struct work_struct *work)\n \tnapi_disable(\u0026lp-\u003enapi_tx);\n \tnapi_disable(\u0026lp-\u003enapi_rx);\n \n-\taxienet_setoptions(ndev, lp-\u003eoptions \u0026\n-\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n+\tlp-\u003eaxienet_config-\u003esetoptions(ndev, lp-\u003eoptions \u0026\n+\t\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n \n \taxienet_dma_stop(lp);\n \tnetdev_reset_queue(ndev);\n@@ -2757,29 +2904,126 @@ static void axienet_dma_err_handler(struct work_struct *work)\n \n \taxienet_dma_start(lp);\n \n-\taxienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);\n-\taxienet_status \u0026= ~XAE_RCW1_RX_MASK;\n-\taxienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);\n-\n-\taxienet_status = axienet_ior(lp, XAE_IP_OFFSET);\n-\tif (axienet_status \u0026 XAE_INT_RXRJECT_MASK)\n-\t\taxienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);\n-\taxienet_iow(lp, XAE_IE_OFFSET, lp-\u003eeth_irq \u003e 0 ?\n-\t\t XAE_INT_RECV_ERROR_MASK : 0);\n-\taxienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);\n+\t/* This error handler runs only for the legacy embedded-DMA (1G) path,\n+\t * whose mac_init() cannot fail, so its return value is not checked.\n+\t */\n+\tlp-\u003eaxienet_config-\u003emac_init(ndev);\n \n \t/* Sync default options with HW but leave receiver and\n \t * transmitter disabled.\n \t */\n-\taxienet_setoptions(ndev, lp-\u003eoptions \u0026\n-\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n+\tlp-\u003eaxienet_config-\u003esetoptions(ndev, lp-\u003eoptions \u0026\n+\t\t\t\t ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));\n \taxienet_set_mac_address(ndev, NULL);\n \taxienet_set_multicast_list(ndev);\n \tnapi_enable(\u0026lp-\u003enapi_rx);\n \tnapi_enable(\u0026lp-\u003enapi_tx);\n-\taxienet_setoptions(ndev, lp-\u003eoptions);\n+\tlp-\u003eaxienet_config-\u003esetoptions(ndev, lp-\u003eoptions);\n+}\n+\n+/**\n+ * axienet_1g_phylink_set_caps - Set 1G phylink capabilities and interfaces\n+ * @lp:\t\tPointer to the axienet_local structure\n+ * @config:\tPointer to the phylink_config structure\n+ */\n+static void axienet_1g_phylink_set_caps(struct axienet_local *lp,\n+\t\t\t\t\tstruct phylink_config *config)\n+{\n+\tconfig-\u003emac_capabilities |= MAC_10FD | MAC_100FD | MAC_1000FD;\n+\t__set_bit(lp-\u003ephy_mode, config-\u003esupported_interfaces);\n+\tif (lp-\u003eswitch_x_sgmii) {\n+\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n+\t\t\t config-\u003esupported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n+\t\t\t config-\u003esupported_interfaces);\n+\t}\n+}\n+\n+/**\n+ * axienet_1g_clk_init - Get and enable the 1G MAC clocks\n+ * @lp:\t\tPointer to the axienet_local structure\n+ *\n+ * Return: 0 on success or a negative error number otherwise.\n+ */\n+static int axienet_1g_clk_init(struct axienet_local *lp)\n+{\n+\tstruct device *dev = lp-\u003edev;\n+\tint ret;\n+\n+\tlp-\u003eaxi_clk = devm_clk_get_optional_enabled(dev, \"s_axi_lite_clk\");\n+\tif (!lp-\u003eaxi_clk) {\n+\t\t/* For backward compatibility, if named AXI clock is not\n+\t\t * present, treat the first clock specified as the AXI clock.\n+\t\t */\n+\t\tlp-\u003eaxi_clk = devm_clk_get_optional_enabled(dev, NULL);\n+\t}\n+\tif (IS_ERR(lp-\u003eaxi_clk))\n+\t\treturn dev_err_probe(dev, PTR_ERR(lp-\u003eaxi_clk),\n+\t\t\t\t \"could not get AXI clock\\n\");\n+\n+\tlp-\u003emisc_clks[0].id = \"axis_clk\";\n+\tlp-\u003emisc_clks[1].id = \"ref_clk\";\n+\tlp-\u003emisc_clks[2].id = \"mgt_clk\";\n+\n+\tret = devm_clk_bulk_get_optional_enable(dev, XAE_NUM_MISC_CLOCKS,\n+\t\t\t\t\t\tlp-\u003emisc_clks);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret,\n+\t\t\t\t \"could not get/enable misc. clocks\\n\");\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * axienet_1g_probe_init - 1G MAC-specific probe-time initialization\n+ * @lp:\t\tPointer to the axienet_local structure\n+ */\n+static void axienet_1g_probe_init(struct axienet_local *lp)\n+{\n+\tif (axienet_ior(lp, XAE_ABILITY_OFFSET) \u0026 XAE_ABILITY_STATS)\n+\t\tlp-\u003efeatures |= XAE_FEATURE_STATS;\n }\n \n+static const struct axienet_config axienet_1g_config = {\n+\t.mdio = true,\n+\t.mac_irq = true,\n+\t.legacy_dma = true,\n+\t.uc_filter = true,\n+\t.mc_filter = true,\n+\t.vlan = true,\n+\t.jumbo = true,\n+\t.dma_tx_csum = true,\n+\t.regs_n = AXIENET_REGS_N,\n+\t.clk_init = axienet_1g_clk_init,\n+\t.setoptions = axienet_setoptions,\n+\t.probe_init = axienet_1g_probe_init,\n+\t.mac_init = axienet_1g_mac_init,\n+\t.mac_link_up = axienet_1g_mac_link_up,\n+\t.get_regs = axienet_1g_get_regs,\n+\t.phylink_set_caps = axienet_1g_phylink_set_caps,\n+\t.pcs_ops = \u0026axienet_pcs_ops,\n+\t.stats_update = axienet_1g_stats_update,\n+\t.get_stats64 = axienet_1g_get_stats64,\n+\t.get_ethtool_stats = axienet_1g_get_ethtool_stats,\n+\t.get_strings = axienet_1g_get_strings,\n+\t.get_sset_count = axienet_1g_get_sset_count,\n+\t.get_pause_stats = axienet_1g_get_pause_stats,\n+\t.get_eth_mac_stats = axienet_1g_get_eth_mac_stats,\n+\t.get_eth_ctrl_stats = axienet_1g_get_eth_ctrl_stats,\n+\t.get_rmon_stats = axienet_1g_get_rmon_stats,\n+};\n+\n+/* Match table for of_platform binding */\n+static const struct of_device_id axienet_of_match[] = {\n+\t{ .compatible = \"xlnx,axi-ethernet-1.00.a\", .data = \u0026axienet_1g_config },\n+\t{ .compatible = \"xlnx,axi-ethernet-1.01.a\", .data = \u0026axienet_1g_config },\n+\t{ .compatible = \"xlnx,axi-ethernet-2.01.a\", .data = \u0026axienet_1g_config },\n+\t{ .compatible = \"xlnx,xxv-ethernet-1.0\", .data = \u0026axienet_10g25g_config },\n+\t{},\n+};\n+\n+MODULE_DEVICE_TABLE(of, axienet_of_match);\n+\n /**\n * axienet_probe - Axi Ethernet probe function.\n * @pdev:\tPointer to platform device structure.\n@@ -2830,27 +3074,13 @@ static int axienet_probe(struct platform_device *pdev)\n \tseqcount_mutex_init(\u0026lp-\u003ehw_stats_seqcount, \u0026lp-\u003estats_lock);\n \tINIT_DEFERRABLE_WORK(\u0026lp-\u003estats_work, axienet_refresh_stats);\n \n-\tlp-\u003eaxi_clk = devm_clk_get_optional_enabled(\u0026pdev-\u003edev,\n-\t\t\t\t\t\t \"s_axi_lite_clk\");\n-\tif (!lp-\u003eaxi_clk) {\n-\t\t/* For backward compatibility, if named AXI clock is not present,\n-\t\t * treat the first clock specified as the AXI clock.\n-\t\t */\n-\t\tlp-\u003eaxi_clk = devm_clk_get_optional_enabled(\u0026pdev-\u003edev, NULL);\n-\t}\n-\tif (IS_ERR(lp-\u003eaxi_clk))\n-\t\treturn dev_err_probe(\u0026pdev-\u003edev, PTR_ERR(lp-\u003eaxi_clk),\n-\t\t\t\t \"could not get AXI clock\\n\");\n+\tlp-\u003eaxienet_config = device_get_match_data(\u0026pdev-\u003edev);\n+\tif (!lp-\u003eaxienet_config)\n+\t\treturn -ENODEV;\n \n-\tlp-\u003emisc_clks[0].id = \"axis_clk\";\n-\tlp-\u003emisc_clks[1].id = \"ref_clk\";\n-\tlp-\u003emisc_clks[2].id = \"mgt_clk\";\n-\n-\tret = devm_clk_bulk_get_optional_enable(\u0026pdev-\u003edev, XAE_NUM_MISC_CLOCKS,\n-\t\t\t\t\t\tlp-\u003emisc_clks);\n+\tret = lp-\u003eaxienet_config-\u003eclk_init(lp);\n \tif (ret)\n-\t\treturn dev_err_probe(\u0026pdev-\u003edev, ret,\n-\t\t\t\t \"could not get/enable misc. clocks\\n\");\n+\t\treturn ret;\n \n \t/* Map device registers */\n \tlp-\u003eregs = devm_platform_get_and_ioremap_resource(pdev, 0, \u0026ethres);\n@@ -2861,9 +3091,6 @@ static int axienet_probe(struct platform_device *pdev)\n \t/* Setup checksum offload, but default to off if not specified */\n \tlp-\u003efeatures = 0;\n \n-\tif (axienet_ior(lp, XAE_ABILITY_OFFSET) \u0026 XAE_ABILITY_STATS)\n-\t\tlp-\u003efeatures |= XAE_FEATURE_STATS;\n-\n \tret = of_property_read_u32(pdev-\u003edev.of_node, \"xlnx,txcsum\", \u0026value);\n \tif (!ret) {\n \t\tswitch (value) {\n@@ -2937,7 +3164,17 @@ static int axienet_probe(struct platform_device *pdev)\n \t\treturn -EINVAL;\n \t}\n \n+\tif (lp-\u003eaxienet_config-\u003eprobe_init)\n+\t\tlp-\u003eaxienet_config-\u003eprobe_init(lp);\n+\n \tif (!of_property_present(pdev-\u003edev.of_node, \"dmas\")) {\n+\t\t/* Non-dmaengine (legacy DMA) mode is only supported by some MACs */\n+\t\tif (!lp-\u003eaxienet_config-\u003elegacy_dma) {\n+\t\t\tdev_err(\u0026pdev-\u003edev,\n+\t\t\t\t\"Legacy DMA mode not supported by this MAC, use dmaengine\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n \t\t/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */\n \t\tnp = of_parse_phandle(pdev-\u003edev.of_node, \"axistream-connected\", 0);\n \n@@ -3017,7 +3254,10 @@ static int axienet_probe(struct platform_device *pdev)\n \t\tstruct xilinx_vdma_config cfg;\n \t\tstruct dma_chan *tx_chan;\n \n-\t\tlp-\u003eeth_irq = platform_get_irq_optional(pdev, 0);\n+\t\tif (lp-\u003eaxienet_config-\u003emac_irq)\n+\t\t\tlp-\u003eeth_irq = platform_get_irq_optional(pdev, 0);\n+\t\telse\n+\t\t\tlp-\u003eeth_irq = -ENXIO;\n \t\tif (lp-\u003eeth_irq \u003c 0 \u0026\u0026 lp-\u003eeth_irq != -ENXIO) {\n \t\t\treturn lp-\u003eeth_irq;\n \t\t}\n@@ -3070,10 +3310,12 @@ static int axienet_probe(struct platform_device *pdev)\n \tlp-\u003etx_dma_cr = axienet_calc_cr(lp, XAXIDMA_DFT_TX_THRESHOLD,\n \t\t\t\t\tXAXIDMA_DFT_TX_USEC);\n \n-\tret = axienet_mdio_setup(lp);\n-\tif (ret)\n-\t\tdev_warn(\u0026pdev-\u003edev,\n-\t\t\t \"error registering MDIO bus: %d\\n\", ret);\n+\tif (lp-\u003eaxienet_config-\u003emdio) {\n+\t\tret = axienet_mdio_setup(lp);\n+\t\tif (ret)\n+\t\t\tdev_warn(\u0026pdev-\u003edev,\n+\t\t\t\t \"error registering MDIO bus: %d\\n\", ret);\n+\t}\n \n \tif (lp-\u003ephy_mode == PHY_INTERFACE_MODE_SGMII ||\n \t lp-\u003ephy_mode == PHY_INTERFACE_MODE_1000BASEX) {\n@@ -3097,23 +3339,21 @@ static int axienet_probe(struct platform_device *pdev)\n \t\t\tgoto cleanup_mdio;\n \t\t}\n \t\tof_node_put(np);\n-\t\tlp-\u003epcs.ops = \u0026axienet_pcs_ops;\n+\t\tlp-\u003epcs.ops = lp-\u003eaxienet_config-\u003epcs_ops;\n+\t\tlp-\u003epcs.poll = true;\n+\t}\n+\n+\tif (lp-\u003eaxienet_config-\u003einternal_pcs) {\n+\t\tlp-\u003epcs.ops = lp-\u003eaxienet_config-\u003epcs_ops;\n \t\tlp-\u003epcs.poll = true;\n \t}\n \n \tlp-\u003ephylink_config.dev = \u0026ndev-\u003edev;\n \tlp-\u003ephylink_config.type = PHYLINK_NETDEV;\n \tlp-\u003ephylink_config.mac_managed_pm = true;\n-\tlp-\u003ephylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |\n-\t\tMAC_10FD | MAC_100FD | MAC_1000FD;\n+\tlp-\u003ephylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;\n \n-\t__set_bit(lp-\u003ephy_mode, lp-\u003ephylink_config.supported_interfaces);\n-\tif (lp-\u003eswitch_x_sgmii) {\n-\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n-\t\t\t lp-\u003ephylink_config.supported_interfaces);\n-\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n-\t\t\t lp-\u003ephylink_config.supported_interfaces);\n-\t}\n+\tlp-\u003eaxienet_config-\u003ephylink_set_caps(lp, \u0026lp-\u003ephylink_config);\n \n \tlp-\u003ephylink = phylink_create(\u0026lp-\u003ephylink_config, pdev-\u003edev.fwnode,\n \t\t\t\t lp-\u003ephy_mode,\n@@ -3156,7 +3396,8 @@ static void axienet_remove(struct platform_device *pdev)\n \tif (lp-\u003epcs_phy)\n \t\tput_device(\u0026lp-\u003epcs_phy-\u003edev);\n \n-\taxienet_mdio_teardown(lp);\n+\tif (lp-\u003emii_bus)\n+\t\taxienet_mdio_teardown(lp);\n }\n \n static void axienet_shutdown(struct platform_device *pdev)\ndiff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c\nnew file mode 100644\nindex 00000000000000..ea4bf99fddfa48\n--- /dev/null\n+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c\n@@ -0,0 +1,594 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * XXV (10G/25G) support\n+ *\n+ * Copyright (C) 2026 Advanced Micro Devices, Inc.\n+ */\n+\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/clk.h\u003e\n+#include \u003clinux/delay.h\u003e\n+#include \u003clinux/ethtool.h\u003e\n+#include \u003clinux/iopoll.h\u003e\n+#include \u003clinux/netdevice.h\u003e\n+#include \u003clinux/phylink.h\u003e\n+#include \u003clinux/string.h\u003e\n+\n+#include \"xilinx_axienet.h\"\n+#include \"xilinx_axienet_xxv.h\"\n+\n+/* readl_poll_timeout() sleep interval (us) and 1 ms total timeout for GT\n+ * reset-done and PCS block-lock polls. Values from ZynqMP/Versal bring-up;\n+ * PG210 does not specify these bounds.\n+ */\n+#define XXV_LINK_POLL_INTERVAL_US\t10\n+\n+/* Number of XXV (10G/25G) MAC registers exposed via ethtool -d.\n+ * Covers configuration and status registers per Xilinx PG210.\n+ */\n+static const u32 axienet_xxv_reg_dump_offsets[XXV_REGS_N] = {\n+\tXXV_GT_RESET_OFFSET,\n+\tXXV_RESET_OFFSET,\n+\tXXV_MODE_OFFSET,\n+\tXXV_TC_OFFSET,\n+\tXXV_RCW1_OFFSET,\n+\tXXV_JUM_OFFSET,\n+\tXXV_VL_LENGTH_OFFSET,\n+\tXXV_TICKREG_OFFSET,\n+\tXXV_CONFIG_REVISION,\n+\tXXV_CONFIG_1588_OFFSET,\n+\tXXV_CONFIG_TX_FLOW_CTRL1_OFFSET,\n+\tXXV_CONFIG_RX_FLOW_CTRL1_OFFSET,\n+\tXXV_CONFIG_RX_FLOW_CTRL2_OFFSET,\n+\tXXV_CONFIG_RSFEC_OFFSET,\n+\tXXV_CONFIG_FEC_OFFSET,\n+\tXXV_AN_CTL1_OFFSET,\n+\tXXV_AN_CTL2_OFFSET,\n+\tXXV_AN_ABILITY_OFFSET,\n+\tXXV_LT_CTL1_OFFSET,\n+\tXXV_SWITCH_CORE_SPEED_OFFSET,\n+\tXXV_CONFIG_1588_32BIT_OFFSET,\n+\tXXV_TX_CONFIG_1588_OFFSET,\n+\tXXV_RX_CONFIG_1588_OFFSET,\n+\tXXV_GTWIZ_CTRL_OFFSET,\n+\tXXV_STATRX_STATUS0_OFFSET,\n+\tXXV_RX_STATUS_REG1,\n+\tXXV_STATRX_STATUS2_OFFSET,\n+\tXXV_STATRX_BLKLCK_OFFSET,\n+\tXXV_STAT_RX_RSFEC_STATUS_OFFSET,\n+\tXXV_STAT_RX_FEC_STATUS_OFFSET,\n+\tXXV_STAT_TX_RSFEC_STATUS_OFFSET,\n+\tXXV_STAT_TX_FLOW_CTRL1_OFFSET,\n+\tXXV_STAT_RX_FLOW_CTRL1_OFFSET,\n+\tXXV_STAT_AN_STS_OFFSET,\n+\tXXV_STAT_AN_LP_STATUS_OFFSET,\n+\tXXV_STAT_AN_LINK_CTL_OFFSET,\n+\tXXV_STAT_LT_STATUS1_OFFSET,\n+\tXXV_STAT_LT_STATUS2_OFFSET,\n+\tXXV_STAT_LT_STATUS3_OFFSET,\n+\tXXV_STAT_LT_STATUS4_OFFSET,\n+\tXXV_STAT_LT_COEFF0_OFFSET,\n+\tXXV_STAT_RX_VALID_CTRL_CODE_OFFSET,\n+\tXXV_STAT_CORE_SPEED_OFFSET,\n+\tXXV_STAT_TSN_OFFSET,\n+\tXXV_STAT_GTWIZ_OFFSET,\n+\tXXV_STAT_AN_LINK_CTL2_OFFSET,\n+};\n+\n+/* Option table for setting up XXV Ethernet hardware options */\n+static struct axienet_option xxvenet_options[] = {\n+\t{ /* Turn on FCS stripping on receive packets */\n+\t\t.opt = XAE_OPTION_FCS_STRIP,\n+\t\t.reg = XXV_RCW1_OFFSET,\n+\t\t.m_or = XXV_RCW1_FCS_MASK,\n+\t}, { /* Turn on FCS insertion on transmit packets */\n+\t\t.opt = XAE_OPTION_FCS_INSERT,\n+\t\t.reg = XXV_TC_OFFSET,\n+\t\t.m_or = XXV_TC_FCS_MASK,\n+\t}, { /* Enable transmitter */\n+\t\t.opt = XAE_OPTION_TXEN,\n+\t\t.reg = XXV_TC_OFFSET,\n+\t\t.m_or = XXV_TC_TX_MASK,\n+\t}, { /* Enable receiver */\n+\t\t.opt = XAE_OPTION_RXEN,\n+\t\t.reg = XXV_RCW1_OFFSET,\n+\t\t.m_or = XXV_RCW1_RX_MASK,\n+\t},\n+\t{}\n+};\n+\n+/* PG210 statistics-block offsets indexed by enum xxv_stat. Each entry is\n+ * the 32-bit LSB register address; the corresponding MSB is at +4.\n+ */\n+static const u32 axienet_xxv_stat_offsets[XXV_STAT_COUNT] = {\n+\t[XXV_STAT_RX_TOTAL_PACKETS]\t = XXV_STAT_RX_TOTAL_PACKETS_OFFSET,\n+\t[XXV_STAT_RX_TOTAL_GOOD_PACKETS] = XXV_STAT_RX_TOTAL_GOOD_PACKETS_OFFSET,\n+\t[XXV_STAT_RX_TOTAL_BYTES]\t = XXV_STAT_RX_TOTAL_BYTES_OFFSET,\n+\t[XXV_STAT_RX_TOTAL_GOOD_BYTES]\t = XXV_STAT_RX_TOTAL_GOOD_BYTES_OFFSET,\n+\t[XXV_STAT_RX_BAD_FCS]\t\t = XXV_STAT_RX_BAD_FCS_OFFSET,\n+\t[XXV_STAT_RX_INRANGEERR]\t = XXV_STAT_RX_INRANGEERR_OFFSET,\n+\t[XXV_STAT_RX_MULTICAST]\t\t = XXV_STAT_RX_MULTICAST_OFFSET,\n+\t[XXV_STAT_RX_BROADCAST]\t\t = XXV_STAT_RX_BROADCAST_OFFSET,\n+\t[XXV_STAT_RX_UNDERSIZE]\t\t = XXV_STAT_RX_UNDERSIZE_OFFSET,\n+\t[XXV_STAT_RX_FRAGMENT]\t\t = XXV_STAT_RX_FRAGMENT_OFFSET,\n+\t[XXV_STAT_RX_JABBER]\t\t = XXV_STAT_RX_JABBER_OFFSET,\n+\t[XXV_STAT_RX_OVERSIZE]\t\t = XXV_STAT_RX_OVERSIZE_OFFSET,\n+\t[XXV_STAT_RX_PAUSE]\t\t = XXV_STAT_RX_PAUSE_OFFSET,\n+\t[XXV_STAT_TX_TOTAL_PACKETS]\t = XXV_STAT_TX_TOTAL_PACKETS_OFFSET,\n+\t[XXV_STAT_TX_TOTAL_GOOD_PACKETS] = XXV_STAT_TX_TOTAL_GOOD_PACKETS_OFFSET,\n+\t[XXV_STAT_TX_TOTAL_BYTES]\t = XXV_STAT_TX_TOTAL_BYTES_OFFSET,\n+\t[XXV_STAT_TX_TOTAL_GOOD_BYTES]\t = XXV_STAT_TX_TOTAL_GOOD_BYTES_OFFSET,\n+\t[XXV_STAT_TX_BAD_FCS]\t\t = XXV_STAT_TX_BAD_FCS_OFFSET,\n+\t[XXV_STAT_TX_FRAME_ERROR]\t = XXV_STAT_TX_FRAME_ERROR_OFFSET,\n+\t[XXV_STAT_TX_MULTICAST]\t\t = XXV_STAT_TX_MULTICAST_OFFSET,\n+\t[XXV_STAT_TX_BROADCAST]\t\t = XXV_STAT_TX_BROADCAST_OFFSET,\n+\t[XXV_STAT_TX_PAUSE]\t\t = XXV_STAT_TX_PAUSE_OFFSET,\n+};\n+\n+/* XXV (PG210) counters exposed via ethtool -S. Only counters that have no\n+ * standard uAPI are listed here; the totals include errored frames, so they\n+ * are distinct from the good-frame counts in rtnl_link_stats64 and the\n+ * IEEE MAC statistics. Every other XXV counter is reported through the\n+ * dedicated stats64, pause, MAC and RMON callbacks instead.\n+ */\n+static const enum xxv_stat axienet_xxv_priv_stats[] = {\n+\tXXV_STAT_RX_TOTAL_PACKETS,\n+\tXXV_STAT_RX_TOTAL_BYTES,\n+\tXXV_STAT_TX_TOTAL_PACKETS,\n+\tXXV_STAT_TX_TOTAL_BYTES,\n+\tXXV_STAT_TX_BAD_FCS,\n+\tXXV_STAT_TX_FRAME_ERROR,\n+};\n+\n+static const char axienet_xxv_ethtool_stats_strings[][ETH_GSTRING_LEN] = {\n+\t\"RX Total Packets\",\n+\t\"RX Total Bytes\",\n+\t\"TX Total Packets\",\n+\t\"TX Total Bytes\",\n+\t\"TX Bad FCS\",\n+\t\"TX Frame Error\",\n+};\n+\n+static u64 axienet_xxv_read_counter(struct axienet_local *lp, enum xxv_stat stat)\n+{\n+\tu32 off = axienet_xxv_stat_offsets[stat];\n+\tu32 lsb, msb;\n+\n+\tlsb = axienet_ior(lp, off);\n+\tmsb = axienet_ior(lp, off + XXV_STAT_MSB_OFFSET);\n+\n+\treturn ((u64)msb \u003c\u003c 32) | lsb;\n+}\n+\n+static bool axienet_xxv_ip_has_gtwiz_status(u32 ip_version)\n+{\n+\tu8 minor = FIELD_GET(XXV_MIN_MASK, ip_version);\n+\tu8 maj = ip_version \u0026 XXV_MAJ_MASK;\n+\n+\tif (maj == XXV_IP_VER_GTWIZ_MAJ_MIN)\n+\t\treturn minor \u003e= XXV_IP_VER_GTWIZ_MIN_MIN;\n+\treturn maj \u003e XXV_IP_VER_GTWIZ_MAJ_MIN;\n+}\n+\n+/**\n+ * axienet_xxv_setoptions - Set XXV MAC options from the option table\n+ * @ndev: Pointer to the net_device structure\n+ * @options: Option flags to apply\n+ */\n+static void axienet_xxv_setoptions(struct net_device *ndev, u32 options)\n+{\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\tstruct axienet_option *tp = xxvenet_options;\n+\tu32 reg;\n+\n+\twhile (tp-\u003eopt) {\n+\t\treg = axienet_ior(lp, tp-\u003ereg) \u0026 ~tp-\u003em_or;\n+\t\tif (options \u0026 tp-\u003eopt)\n+\t\t\treg |= tp-\u003em_or;\n+\t\taxienet_iow(lp, tp-\u003ereg, reg);\n+\t\ttp++;\n+\t}\n+\n+\tlp-\u003eoptions |= options;\n+}\n+\n+/**\n+ * axienet_xxv_probe_init - Initialize XXV-specific state at probe time\n+ * @lp: Pointer to the axienet_local structure\n+ */\n+static void axienet_xxv_probe_init(struct axienet_local *lp)\n+{\n+\tlp-\u003exxv_ip_version = axienet_ior(lp, XXV_CONFIG_REVISION);\n+\tlp-\u003efeatures |= XAE_FEATURE_STATS;\n+}\n+\n+/**\n+ * axienet_xxv_gt_reset - Pulse the XXV GT reset line\n+ * @lp: Pointer to the axienet_local structure\n+ */\n+static void axienet_xxv_gt_reset(struct axienet_local *lp)\n+{\n+\tu32 val;\n+\n+\t/* Reset GT */\n+\tval = axienet_ior(lp, XXV_GT_RESET_OFFSET);\n+\tval |= XXV_GT_RESET_MASK;\n+\taxienet_iow(lp, XXV_GT_RESET_OFFSET, val);\n+\t/* Allow 1 ms for the GT reset to settle (see timeout note above) */\n+\tmdelay(1);\n+\tval = axienet_ior(lp, XXV_GT_RESET_OFFSET);\n+\tval \u0026= ~XXV_GT_RESET_MASK;\n+\taxienet_iow(lp, XXV_GT_RESET_OFFSET, val);\n+}\n+\n+/**\n+ * axienet_xxv_poll_link_ready - Wait for XXV GT and PCS block lock\n+ * @ndev: Pointer to the net_device structure\n+ *\n+ * Poll GT wizard reset-done on IP v3.2+, then RX PCS block lock. Block-lock\n+ * failure is logged but not propagated: it depends on a live link partner and\n+ * reference clock, so an unplugged cable must not fail device bring-up.\n+ *\n+ * Return: 0 on success, or a negative error if GT reset-done times out.\n+ */\n+static int axienet_xxv_poll_link_ready(struct net_device *ndev)\n+{\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\tu32 val;\n+\tint ret;\n+\n+\t/* Confirm XXV Ethernet is up: on IP v3.2+, wait for GT\n+\t * reset-done before further register access, then poll until\n+\t * RX PCS block lock is asserted.\n+\t */\n+\tif (axienet_xxv_ip_has_gtwiz_status(lp-\u003exxv_ip_version)) {\n+\t\tret = readl_poll_timeout(lp-\u003eregs + XXV_STAT_GTWIZ_OFFSET,\n+\t\t\t\t\t val, (val \u0026 XXV_GTWIZ_RESET_DONE),\n+\t\t\t\t\t XXV_LINK_POLL_INTERVAL_US,\n+\t\t\t\t\t DELAY_OF_ONE_MILLISEC);\n+\t\tif (ret) {\n+\t\t\tnetdev_err(ndev, \"XXV MAC GT reset not complete! Cross-check the MAC ref clock configuration\\n\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tret = readl_poll_timeout(lp-\u003eregs + XXV_STATRX_BLKLCK_OFFSET,\n+\t\t\t\t val, (val \u0026 XXV_RX_BLKLCK_MASK),\n+\t\t\t\t XXV_LINK_POLL_INTERVAL_US,\n+\t\t\t\t DELAY_OF_ONE_MILLISEC);\n+\tif (ret)\n+\t\tnetdev_err(ndev, \"XXV MAC block lock not complete! Cross-check the MAC ref clock configuration\\n\");\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * axienet_xxv_mac_init - XXV MAC-specific bring-up after the DMA reset\n+ * @ndev: Pointer to the net_device structure\n+ *\n+ * Return: 0 on success or a negative error number otherwise.\n+ */\n+static int axienet_xxv_mac_init(struct net_device *ndev)\n+{\n+\tstruct axienet_local *lp = netdev_priv(ndev);\n+\tint ret;\n+\n+\tret = axienet_xxv_poll_link_ready(ndev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tlp-\u003eoptions |= XAE_OPTION_FCS_STRIP;\n+\tlp-\u003eoptions |= XAE_OPTION_FCS_INSERT;\n+\n+\treturn 0;\n+}\n+\n+static void axienet_xxv_phylink_set_capabilities(struct axienet_local *lp,\n+\t\t\t\t\t\t struct phylink_config *cfg)\n+{\n+\tu32 core_speed;\n+\tbool rtsw;\n+\n+\tcore_speed = axienet_ior(lp, XXV_STAT_CORE_SPEED_OFFSET);\n+\t/* Bit[1:0]: 00=25G, 01=10G, 10=runtime-switchable 25G,\n+\t * 11=runtime-switchable 10G. A runtime-switchable core can operate at\n+\t * either speed, so advertise both; a fixed core advertises only its\n+\t * configured speed.\n+\t */\n+\trtsw = core_speed \u0026 XXV_STAT_CORE_SPEED_RTSW_MASK;\n+\n+\tif (rtsw || (core_speed \u0026 XXV_STAT_CORE_SPEED_10G_MASK)) {\n+\t\tcfg-\u003emac_capabilities |= MAC_10000FD;\n+\t\t__set_bit(PHY_INTERFACE_MODE_10GBASER,\n+\t\t\t cfg-\u003esupported_interfaces);\n+\t}\n+\n+\tif (rtsw || !(core_speed \u0026 XXV_STAT_CORE_SPEED_10G_MASK)) {\n+\t\tcfg-\u003emac_capabilities |= MAC_25000FD;\n+\t\t__set_bit(PHY_INTERFACE_MODE_25GBASER,\n+\t\t\t cfg-\u003esupported_interfaces);\n+\t}\n+}\n+\n+static void axienet_xxv_pcs_get_state(struct phylink_pcs *pcs,\n+\t\t\t\t unsigned int neg_mode,\n+\t\t\t\t struct phylink_link_state *state)\n+{\n+\tstruct axienet_local *lp = pcs_to_axienet_local(pcs);\n+\n+\tstate-\u003eduplex = DUPLEX_FULL;\n+\tstate-\u003ean_complete = !!(axienet_ior(lp, XXV_STAT_AN_STS_OFFSET) \u0026\n+\t\t\t\tXXV_AN_COMPLETE_MASK);\n+\tstate-\u003elink = axienet_ior(lp, XXV_RX_STATUS_REG1) \u0026\n+\t\t XXV_RX_STATUS_MASK;\n+\n+\tif (axienet_ior(lp, XXV_STAT_CORE_SPEED_OFFSET) \u0026\n+\t XXV_STAT_CORE_SPEED_10G_MASK)\n+\t\tstate-\u003espeed = SPEED_10000;\n+\telse\n+\t\tstate-\u003espeed = SPEED_25000;\n+}\n+\n+static int axienet_xxv_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,\n+\t\t\t\t phy_interface_t interface,\n+\t\t\t\t const unsigned long *advertising,\n+\t\t\t\t bool permit_pause_to_mac)\n+{\n+\treturn 0;\n+}\n+\n+static const struct phylink_pcs_ops axienet_xxv_pcs_ops = {\n+\t.pcs_get_state = axienet_xxv_pcs_get_state,\n+\t.pcs_config = axienet_xxv_pcs_config,\n+};\n+\n+/**\n+ * axienet_xxv_get_regs - Dump XXV MAC registers for ethtool\n+ * @lp: Pointer to the axienet_local structure\n+ * @data: Buffer for register values (zeroed and sized by the caller)\n+ */\n+static void axienet_xxv_get_regs(struct axienet_local *lp, u32 *data)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(axienet_xxv_reg_dump_offsets); i++)\n+\t\tdata[i] = axienet_ior(lp, axienet_xxv_reg_dump_offsets[i]);\n+}\n+\n+static int axienet_10g25g_clk_init(struct axienet_local *lp)\n+{\n+\tstruct device *dev = lp-\u003edev;\n+\tint ret;\n+\n+\t/* The register, RX and GT DRP clocks are mandatory for MAC+PCS\n+\t * operation, so fetch them as required.\n+\t */\n+\tlp-\u003eaxi_clk = devm_clk_get_enabled(dev, \"s_axi_aclk\");\n+\tif (IS_ERR(lp-\u003eaxi_clk))\n+\t\treturn dev_err_probe(dev, PTR_ERR(lp-\u003eaxi_clk),\n+\t\t\t\t \"could not get AXI clock\\n\");\n+\n+\tlp-\u003emisc_clks[0].id = \"rx_core_clk\";\n+\tlp-\u003emisc_clks[1].id = \"dclk\";\n+\n+\tret = devm_clk_bulk_get_enable(dev, 2, lp-\u003emisc_clks);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret,\n+\t\t\t\t \"could not get/enable XXV clocks\\n\");\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * axienet_xxv_stats_update - Latch and accumulate XXV hardware counters\n+ * @lp: Pointer to the axienet_local structure\n+ *\n+ * The XXV statistics counters are clear-on-tick (PG210): writing TICK_REG\n+ * latches the internal accumulators into the readable STAT_*_LSB/MSB registers\n+ * and clears the internal accumulators. Each post-TICK read therefore returns\n+ * the count for the interval since the previous TICK, so software accumulates\n+ * those intervals into lp-\u003exxv_stat_base. A last-counter delta (as used by the\n+ * free-running 1G MAC path) is not needed.\n+ */\n+static void axienet_xxv_stats_update(struct axienet_local *lp)\n+{\n+\tu64 counter[XXV_STAT_COUNT];\n+\tenum xxv_stat stat;\n+\n+\t/* Latch the clear-on-tick snapshot and read the counters outside the\n+\t * seqcount write section, so only the accumulator updates run inside it\n+\t * and the reader retry window stays short.\n+\t */\n+\taxienet_iow(lp, XXV_TICKREG_OFFSET, XXV_TICKREG_STATEN_MASK);\n+\tfor (stat = 0; stat \u003c XXV_STAT_COUNT; stat++)\n+\t\tcounter[stat] = axienet_xxv_read_counter(lp, stat);\n+\n+\twrite_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n+\tfor (stat = 0; stat \u003c XXV_STAT_COUNT; stat++)\n+\t\tlp-\u003exxv_stat_base[stat] += counter[stat];\n+\twrite_seqcount_end(\u0026lp-\u003ehw_stats_seqcount);\n+}\n+\n+/**\n+ * axienet_xxv_get_stats64 - Fill rtnl_link_stats64 from XXV counters\n+ * @lp: Pointer to the axienet_local structure\n+ * @stats: Output rtnl_link_stats64 structure to populate\n+ */\n+static void axienet_xxv_get_stats64(struct axienet_local *lp,\n+\t\t\t\t struct rtnl_link_stats64 *stats)\n+{\n+\tunsigned int start;\n+\tu64 tx_hw_errors;\n+\n+\tdo {\n+\t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n+\t\tstats-\u003erx_crc_errors = lp-\u003exxv_stat_base[XXV_STAT_RX_BAD_FCS];\n+\t\t/* Both in-range length errors and frame-too-long (oversize)\n+\t\t * frames are IEEE 802.3 length errors, so fold them together\n+\t\t * into rx_length_errors; rx_over_errors is reserved for receiver\n+\t\t * FIFO/ring overflow, which the XXV MAC does not expose.\n+\t\t */\n+\t\tstats-\u003erx_length_errors =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_INRANGEERR] +\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_OVERSIZE];\n+\t\tstats-\u003erx_errors = lp-\u003exxv_stat_base[XXV_STAT_RX_UNDERSIZE] +\n+\t\t\t\t lp-\u003exxv_stat_base[XXV_STAT_RX_FRAGMENT] +\n+\t\t\t\t lp-\u003exxv_stat_base[XXV_STAT_RX_JABBER] +\n+\t\t\t\t stats-\u003erx_crc_errors +\n+\t\t\t\t stats-\u003erx_length_errors;\n+\t\tstats-\u003emulticast = lp-\u003exxv_stat_base[XXV_STAT_RX_MULTICAST];\n+\t\ttx_hw_errors = lp-\u003exxv_stat_base[XXV_STAT_TX_BAD_FCS] +\n+\t\t\t lp-\u003exxv_stat_base[XXV_STAT_TX_FRAME_ERROR];\n+\t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n+\n+\t/* Fold the HW TX error count into the software tx_errors seeded from\n+\t * dev-\u003estats by the caller. The XXV xmit path bumps dev-\u003estats.tx_errors\n+\t * for frames dropped on pad failure before they reach the MAC, while the\n+\t * HW counters only cover frames the MAC actually transmitted; the two are\n+\t * disjoint. This runs once, outside the seqcount retry loop, so a racing\n+\t * stats update cannot make the accumulation re-add on retry.\n+\t */\n+\tstats-\u003etx_errors += tx_hw_errors;\n+}\n+\n+/**\n+ * axienet_xxv_get_ethtool_stats - Copy XXV counters for ethtool -S\n+ * @lp: Pointer to the axienet_local structure\n+ * @data: Output buffer sized for ARRAY_SIZE(axienet_xxv_priv_stats) u64 values\n+ */\n+static void axienet_xxv_get_ethtool_stats(struct axienet_local *lp, u64 *data)\n+{\n+\tunsigned int i, start;\n+\n+\tdo {\n+\t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n+\t\tfor (i = 0; i \u003c ARRAY_SIZE(axienet_xxv_priv_stats); i++)\n+\t\t\tdata[i] = lp-\u003exxv_stat_base[axienet_xxv_priv_stats[i]];\n+\t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n+}\n+\n+/**\n+ * axienet_xxv_get_strings - Copy XXV ethtool statistics name strings\n+ * @data: Output buffer for the statistics name strings\n+ */\n+static void axienet_xxv_get_strings(u8 *data)\n+{\n+\tmemcpy(data, axienet_xxv_ethtool_stats_strings,\n+\t sizeof(axienet_xxv_ethtool_stats_strings));\n+}\n+\n+/**\n+ * axienet_xxv_get_sset_count - Number of XXV ethtool statistics\n+ *\n+ * Return: Count of XXV hardware statistics reported via ethtool -S.\n+ */\n+static int axienet_xxv_get_sset_count(void)\n+{\n+\treturn ARRAY_SIZE(axienet_xxv_ethtool_stats_strings);\n+}\n+\n+/**\n+ * axienet_xxv_get_pause_stats - Fill ethtool pause frame statistics\n+ * @lp: Pointer to the axienet_local structure\n+ * @pause_stats: Output ethtool_pause_stats structure to populate\n+ */\n+static void axienet_xxv_get_pause_stats(struct axienet_local *lp,\n+\t\t\t\t\tstruct ethtool_pause_stats *pause_stats)\n+{\n+\tunsigned int start;\n+\n+\tdo {\n+\t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n+\t\tpause_stats-\u003etx_pause_frames =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_TX_PAUSE];\n+\t\tpause_stats-\u003erx_pause_frames =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_PAUSE];\n+\t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n+}\n+\n+/**\n+ * axienet_xxv_get_eth_mac_stats - Fill IEEE 802.3 MAC statistics\n+ * @lp: Pointer to the axienet_local structure\n+ * @mac_stats: Output ethtool_eth_mac_stats structure to populate\n+ */\n+static void axienet_xxv_get_eth_mac_stats(struct axienet_local *lp,\n+\t\t\t\t\t struct ethtool_eth_mac_stats *mac_stats)\n+{\n+\tunsigned int start;\n+\n+\tdo {\n+\t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n+\t\tmac_stats-\u003eFramesTransmittedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_TX_TOTAL_GOOD_PACKETS];\n+\t\tmac_stats-\u003eFramesReceivedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_TOTAL_GOOD_PACKETS];\n+\t\tmac_stats-\u003eOctetsTransmittedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_TX_TOTAL_GOOD_BYTES];\n+\t\tmac_stats-\u003eOctetsReceivedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_TOTAL_GOOD_BYTES];\n+\t\tmac_stats-\u003eFrameCheckSequenceErrors =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_BAD_FCS];\n+\t\tmac_stats-\u003eMulticastFramesXmittedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_TX_MULTICAST];\n+\t\tmac_stats-\u003eBroadcastFramesXmittedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_TX_BROADCAST];\n+\t\tmac_stats-\u003eMulticastFramesReceivedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_MULTICAST];\n+\t\tmac_stats-\u003eBroadcastFramesReceivedOK =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_BROADCAST];\n+\t\tmac_stats-\u003eInRangeLengthErrors =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_INRANGEERR];\n+\t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n+}\n+\n+/**\n+ * axienet_xxv_get_rmon_stats - Fill RMON statistics and histogram ranges\n+ * @lp: Pointer to the axienet_local structure\n+ * @rmon_stats: Output ethtool_rmon_stats structure to populate\n+ * @ranges: Set to the RMON histogram range table\n+ */\n+static void axienet_xxv_get_rmon_stats(struct axienet_local *lp,\n+\t\t\t\t struct ethtool_rmon_stats *rmon_stats,\n+\t\t\t\t const struct ethtool_rmon_hist_range **ranges)\n+{\n+\tunsigned int start;\n+\n+\tdo {\n+\t\tstart = read_seqcount_begin(\u0026lp-\u003ehw_stats_seqcount);\n+\t\trmon_stats-\u003eundersize_pkts =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_UNDERSIZE];\n+\t\trmon_stats-\u003eoversize_pkts =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_OVERSIZE];\n+\t\trmon_stats-\u003efragments =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_FRAGMENT];\n+\t\trmon_stats-\u003ejabbers =\n+\t\t\tlp-\u003exxv_stat_base[XXV_STAT_RX_JABBER];\n+\t} while (read_seqcount_retry(\u0026lp-\u003ehw_stats_seqcount, start));\n+\n+\t/* XXV currently exposes only aggregate RMON counters, not per-bin\n+\t * histogram buckets. Keep ranges NULL until histogram bins are wired.\n+\t */\n+\t*ranges = NULL;\n+}\n+\n+const struct axienet_config axienet_10g25g_config = {\n+\t.sw_padding = true,\n+\t.internal_pcs = true,\n+\t.regs_n = XXV_REGS_N,\n+\t.clk_init = axienet_10g25g_clk_init,\n+\t.setoptions = axienet_xxv_setoptions,\n+\t.probe_init = axienet_xxv_probe_init,\n+\t.gt_reset = axienet_xxv_gt_reset,\n+\t.mac_init = axienet_xxv_mac_init,\n+\t.get_regs = axienet_xxv_get_regs,\n+\t.phylink_set_caps = axienet_xxv_phylink_set_capabilities,\n+\t.pcs_ops = \u0026axienet_xxv_pcs_ops,\n+\t.stats_update = axienet_xxv_stats_update,\n+\t.get_stats64 = axienet_xxv_get_stats64,\n+\t.get_ethtool_stats = axienet_xxv_get_ethtool_stats,\n+\t.get_strings = axienet_xxv_get_strings,\n+\t.get_sset_count = axienet_xxv_get_sset_count,\n+\t.get_pause_stats = axienet_xxv_get_pause_stats,\n+\t.get_eth_mac_stats = axienet_xxv_get_eth_mac_stats,\n+\t.get_rmon_stats = axienet_xxv_get_rmon_stats,\n+};\ndiff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h\nnew file mode 100644\nindex 00000000000000..ebfa7d57a85915\n--- /dev/null\n+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h\n@@ -0,0 +1,141 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/*\n+ * XXV (10G/25G) support\n+ *\n+ * Copyright (C) 2026 Advanced Micro Devices, Inc.\n+ */\n+\n+#ifndef XILINX_AXIENET_XXV_H\n+#define XILINX_AXIENET_XXV_H\n+\n+#include \u003clinux/bits.h\u003e\n+\n+struct axienet_local;\n+struct axienet_config;\n+\n+#define XXV_REGS_N\t\t46\n+\n+/* XXV MAC Register Definitions */\n+#define XXV_GT_RESET_OFFSET\t\t0x00000000\n+#define XXV_RESET_OFFSET\t\t0x00000004\n+#define XXV_MODE_OFFSET\t\t\t0x00000008\n+#define XXV_TC_OFFSET\t\t\t0x0000000C\n+#define XXV_RCW1_OFFSET\t\t\t0x00000014\n+#define XXV_JUM_OFFSET\t\t\t0x00000018\n+#define XXV_VL_LENGTH_OFFSET\t\t0x0000001C\n+#define XXV_TICKREG_OFFSET\t\t0x00000020\n+#define XXV_CONFIG_REVISION\t\t0x00000024\n+#define XXV_CONFIG_1588_OFFSET\t\t0x00000038\n+#define XXV_CONFIG_TX_FLOW_CTRL1_OFFSET\t0x00000040\n+#define XXV_CONFIG_RX_FLOW_CTRL1_OFFSET\t0x00000094\n+#define XXV_CONFIG_RX_FLOW_CTRL2_OFFSET\t0x00000098\n+#define XXV_CONFIG_RSFEC_OFFSET\t\t0x000000D0\n+#define XXV_CONFIG_FEC_OFFSET\t\t0x000000D4\n+#define XXV_AN_CTL1_OFFSET\t\t0x000000E0\n+#define XXV_AN_CTL2_OFFSET\t\t0x000000E4\n+#define XXV_AN_ABILITY_OFFSET\t\t0x000000F8\n+#define XXV_LT_CTL1_OFFSET\t\t0x00000100\n+#define XXV_SWITCH_CORE_SPEED_OFFSET\t0x00000138\n+#define XXV_CONFIG_1588_32BIT_OFFSET\t0x0000013C\n+#define XXV_TX_CONFIG_1588_OFFSET\t0x00000140\n+#define XXV_RX_CONFIG_1588_OFFSET\t0x00000144\n+#define XXV_GTWIZ_CTRL_OFFSET\t\t0x00000154\n+#define XXV_STATRX_STATUS0_OFFSET\t0x00000400\n+#define XXV_RX_STATUS_REG1\t\t0x00000404\n+#define XXV_STATRX_STATUS2_OFFSET\t0x00000408\n+#define XXV_STATRX_BLKLCK_OFFSET\t0x0000040C\n+#define XXV_STAT_RX_RSFEC_STATUS_OFFSET\t0x0000043C\n+#define XXV_STAT_RX_FEC_STATUS_OFFSET\t0x00000448\n+#define XXV_STAT_TX_RSFEC_STATUS_OFFSET\t0x0000044C\n+#define XXV_STAT_TX_FLOW_CTRL1_OFFSET\t0x00000450\n+#define XXV_STAT_RX_FLOW_CTRL1_OFFSET\t0x00000454\n+#define XXV_STAT_AN_STS_OFFSET\t\t0x00000458\n+#define XXV_STAT_AN_LP_STATUS_OFFSET\t0x0000045C\n+#define XXV_STAT_AN_LINK_CTL_OFFSET\t0x00000460\n+#define XXV_STAT_LT_STATUS1_OFFSET\t0x00000464\n+#define XXV_STAT_LT_STATUS2_OFFSET\t0x00000468\n+#define XXV_STAT_LT_STATUS3_OFFSET\t0x0000046C\n+#define XXV_STAT_LT_STATUS4_OFFSET\t0x00000470\n+#define XXV_STAT_LT_COEFF0_OFFSET\t0x00000474\n+#define XXV_STAT_RX_VALID_CTRL_CODE_OFFSET\t0x00000494\n+#define XXV_STAT_CORE_SPEED_OFFSET\t0x00000498\n+#define XXV_STAT_TSN_OFFSET\t\t0x0000049C\n+#define XXV_STAT_GTWIZ_OFFSET\t\t0x000004A0\n+#define XXV_STAT_AN_LINK_CTL2_OFFSET\t0x000009F0\n+\n+/* XXV statistics counter registers (PG210). Each counter is a pair of 32-bit\n+ * registers; the MSB register is XXV_STAT_MSB_OFFSET bytes above the LSB.\n+ */\n+#define XXV_STAT_MSB_OFFSET\t\t\t4\n+#define XXV_STAT_TX_FRAME_ERROR_OFFSET\t\t0x000006A0\n+#define XXV_STAT_TX_TOTAL_PACKETS_OFFSET\t0x00000700\n+#define XXV_STAT_TX_TOTAL_GOOD_PACKETS_OFFSET\t0x00000708\n+#define XXV_STAT_TX_TOTAL_BYTES_OFFSET\t\t0x00000710\n+#define XXV_STAT_TX_TOTAL_GOOD_BYTES_OFFSET\t0x00000718\n+#define XXV_STAT_TX_BAD_FCS_OFFSET\t\t0x000007B8\n+#define XXV_STAT_TX_MULTICAST_OFFSET\t\t0x000007D8\n+#define XXV_STAT_TX_BROADCAST_OFFSET\t\t0x000007E0\n+#define XXV_STAT_TX_PAUSE_OFFSET\t\t0x000007F0\n+#define XXV_STAT_RX_TOTAL_PACKETS_OFFSET\t0x00000808\n+#define XXV_STAT_RX_TOTAL_GOOD_PACKETS_OFFSET\t0x00000810\n+#define XXV_STAT_RX_TOTAL_BYTES_OFFSET\t\t0x00000818\n+#define XXV_STAT_RX_TOTAL_GOOD_BYTES_OFFSET\t0x00000820\n+#define XXV_STAT_RX_UNDERSIZE_OFFSET\t\t0x00000898\n+#define XXV_STAT_RX_FRAGMENT_OFFSET\t\t0x000008A0\n+#define XXV_STAT_RX_OVERSIZE_OFFSET\t\t0x000008A8\n+#define XXV_STAT_RX_JABBER_OFFSET\t\t0x000008B8\n+#define XXV_STAT_RX_BAD_FCS_OFFSET\t\t0x000008C0\n+#define XXV_STAT_RX_MULTICAST_OFFSET\t\t0x000008E0\n+#define XXV_STAT_RX_BROADCAST_OFFSET\t\t0x000008E8\n+#define XXV_STAT_RX_PAUSE_OFFSET\t\t0x000008F8\n+#define XXV_STAT_RX_INRANGEERR_OFFSET\t\t0x00000908\n+\n+/* XXV MAC Register Mask Definitions */\n+#define XXV_GT_RESET_MASK\t\tBIT(0)\n+#define XXV_TC_TX_MASK\t\t\tBIT(0)\n+#define XXV_RCW1_RX_MASK\t\tBIT(0)\n+#define XXV_RCW1_FCS_MASK\t\tBIT(1)\n+#define XXV_TC_FCS_MASK\t\t\tBIT(1)\n+#define XXV_RX_BLKLCK_MASK\t\tBIT(0)\n+#define XXV_TICKREG_STATEN_MASK\t\tBIT(0)\n+#define XXV_GTWIZ_RESET_DONE\t\t(BIT(0) | BIT(1))\n+#define XXV_MAJ_MASK\t\t\tGENMASK(7, 0)\n+#define XXV_MIN_MASK\t\t\tGENMASK(15, 8)\n+/* IP v3.2+ exposes GT wizard status before other register access (PG210). */\n+#define XXV_IP_VER_GTWIZ_MAJ_MIN\t3\n+#define XXV_IP_VER_GTWIZ_MIN_MIN\t2\n+#define XXV_AN_COMPLETE_MASK\t\tBIT(2)\n+#define XXV_STAT_CORE_SPEED_RTSW_MASK\tBIT(1)\n+#define XXV_STAT_CORE_SPEED_10G_MASK\tBIT(0)\n+#define XXV_RX_STATUS_MASK\t\tBIT(0)\n+\n+/* XXV (10G/25G) MAC statistics counters, used to index xxv_stat_base[]. */\n+enum xxv_stat {\n+\tXXV_STAT_RX_TOTAL_PACKETS = 0,\n+\tXXV_STAT_RX_TOTAL_GOOD_PACKETS,\n+\tXXV_STAT_RX_TOTAL_BYTES,\n+\tXXV_STAT_RX_TOTAL_GOOD_BYTES,\n+\tXXV_STAT_RX_BAD_FCS,\n+\tXXV_STAT_RX_INRANGEERR,\n+\tXXV_STAT_RX_MULTICAST,\n+\tXXV_STAT_RX_BROADCAST,\n+\tXXV_STAT_RX_UNDERSIZE,\n+\tXXV_STAT_RX_FRAGMENT,\n+\tXXV_STAT_RX_JABBER,\n+\tXXV_STAT_RX_OVERSIZE,\n+\tXXV_STAT_RX_PAUSE,\n+\tXXV_STAT_TX_TOTAL_PACKETS,\n+\tXXV_STAT_TX_TOTAL_GOOD_PACKETS,\n+\tXXV_STAT_TX_TOTAL_BYTES,\n+\tXXV_STAT_TX_TOTAL_GOOD_BYTES,\n+\tXXV_STAT_TX_BAD_FCS,\n+\tXXV_STAT_TX_FRAME_ERROR,\n+\tXXV_STAT_TX_MULTICAST,\n+\tXXV_STAT_TX_BROADCAST,\n+\tXXV_STAT_TX_PAUSE,\n+\tXXV_STAT_COUNT,\n+};\n+\n+extern const struct axienet_config axienet_10g25g_config;\n+\n+#endif /* XILINX_AXIENET_XXV_H */\ndiff --git a/include/linux/clk.h b/include/linux/clk.h\nindex 998ba3f261dac7..0289ac4c6e48ef 100644\n--- a/include/linux/clk.h\n+++ b/include/linux/clk.h\n@@ -502,6 +502,22 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,\n */\n int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,\n \t\t\t\t\t struct clk_bulk_data *clks);\n+/**\n+ * devm_clk_bulk_get_enable - Get and enable bulk clocks (managed)\n+ * @dev: device for clock \"consumer\"\n+ * @num_clks: the number of clk_bulk_data\n+ * @clks: pointer to the clk_bulk_data table of consumer\n+ *\n+ * Behaves the same as devm_clk_bulk_get() but also prepares and enables the\n+ * clocks in one operation with management. The clks will automatically be\n+ * disabled, unprepared and freed when the device is unbound.\n+ *\n+ * Return: 0 if all clocks specified in clk_bulk_data table are obtained and\n+ * enabled successfully. Otherwise returns valid IS_ERR() condition containing\n+ * errno.\n+ */\n+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,\n+\t\t\t\t\t struct clk_bulk_data *clks);\n /**\n * devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed)\n * @dev: device for clock \"consumer\"\n@@ -1052,6 +1068,13 @@ static inline int __must_check devm_clk_bulk_get_optional(struct device *dev,\n \treturn 0;\n }\n \n+static inline int __must_check devm_clk_bulk_get_enable(struct device *dev,\n+\t\t\t\t\t\t\tint num_clks,\n+\t\t\t\t\t\t\tstruct clk_bulk_data *clks)\n+{\n+\treturn 0;\n+}\n+\n static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev,\n \t\t\t\t\t\t\t\t int num_clks,\n \t\t\t\t\t\t\t\t struct clk_bulk_data *clks)\n"
} |
| 2/1 | 2026/07/26 00:02 | agent | patch-evaluator |
1mModel:best-expensive Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch primarily modifies the Xilinx AXI Ethernet driver (a platform driver for Xilinx FPGAs/SoCs) to add support for the XXV (10G/25G) MAC. Platform devices require specific device tree nodes to be probed and are not discoverable like PCI/USB devices. Since standard fuzzing environments (e.g., x86_64 q35, arm64 virt) do not instantiate these Xilinx-specific platform devices, the modified driver code is unreachable. The only core change is the addition of `devm_clk_bulk_get_enable`, which is a trivial 5-line wrapper.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 742257010ef8257f84d443f4659d41c17caf2887
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Jul 26 00:02:14 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
index fb02e579463c98..23b1a27c04e553 100644
--- a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
+++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
@@ -4,36 +4,46 @@
$id: http://devicetree.org/schemas/net/xlnx,axi-ethernet.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: AXI 1G/2.5G Ethernet Subsystem
+title: Xilinx AXI Ethernet Subsystem
description: |
- Also called AXI 1G/2.5G Ethernet Subsystem, the xilinx axi ethernet IP core
- provides connectivity to an external ethernet PHY supporting different
- interfaces: MII, GMII, RGMII, SGMII, 1000BaseX. It also includes two
- segments of memory for buffering TX and RX, as well as the capability of
- offloading TX/RX checksum calculation off the processor.
+ This binding describes Xilinx AXI Ethernet subsystem IPs, including the
+ AXI 1G/2.5G Ethernet Subsystem and the 10G/25G (XXV) Ethernet Subsystem.
+
+ The AXI 1G/2.5G Ethernet Subsystem provides connectivity to an external
+ ethernet PHY supporting different interfaces: MII, GMII, RGMII, SGMII,
+ 1000BaseX. It also includes two segments of memory for buffering TX and RX,
+ as well as the capability of offloading TX/RX checksum calculation off the
+ processor.
Management configuration is done through the AXI interface, while payload is
sent and received through means of an AXI DMA controller. This driver
includes the DMA driver code, so this driver is incompatible with AXI DMA
driver.
+ The XXV Ethernet Subsystem integrates a 10G/25G Ethernet MAC and PCS/PMA
+ connected to a high-speed serial transceiver. It supports the 10GBASE-R and
+ 25GBASE-R line rates, with 25G operation following the 25G Ethernet
+ Consortium specification. Its payload is moved by an external AXI DMA
+ controller rather than a DMA engine integrated into the MAC.
+
maintainers:
- Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
properties:
compatible:
enum:
- - xlnx,axi-ethernet-1.00.a
- - xlnx,axi-ethernet-1.01.a
- - xlnx,axi-ethernet-2.01.a
+ - xlnx,axi-ethernet-1.00.a # AXI 1G/2.5G Ethernet Subsystem
+ - xlnx,axi-ethernet-1.01.a # AXI 1G/2.5G Ethernet Subsystem
+ - xlnx,axi-ethernet-2.01.a # AXI 1G/2.5G Ethernet Subsystem
+ - xlnx,xxv-ethernet-1.0 # 10G/25G Ethernet Subsystem
reg:
description:
- Address and length of the IO space, as well as the address
- and length of the AXI DMA controller IO space, unless
- axistream-connected is specified, in which case the reg
- attribute of the node referenced by it is used.
+ Address and length of the IO space. For AXI 1G/2.5G using the legacy
+ embedded DMA, this also covers the AXI DMA controller IO space, unless
+ axistream-connected is specified, in which case the reg attribute of
+ the node referenced by it is used.
minItems: 1
maxItems: 2
@@ -62,6 +72,8 @@ properties:
- rgmii
- sgmii
- 1000base-x
+ - 10gbase-r
+ - 25gbase-r
xlnx,phy-type:
description:
@@ -93,19 +105,12 @@ properties:
selected on core reset (i.e. by the basex_or_sgmii core input line).
clocks:
- items:
- - description: Clock for AXI register slave interface.
- - description: AXI4-Stream clock for TXD RXD TXC and RXS interfaces.
- - description: Ethernet reference clock, used by signal delay primitives
- and transceivers.
- - description: MGT reference clock (used by optional internal PCS/PMA PHY)
+ minItems: 3
+ maxItems: 4
clock-names:
- items:
- - const: s_axi_lite_clk
- - const: axis_clk
- - const: ref_clk
- - const: mgt_clk
+ minItems: 3
+ maxItems: 4
axistream-connected:
$ref: /schemas/types.yaml#/definitions/phandle
@@ -139,15 +144,88 @@ properties:
required:
- compatible
- - interrupts
- reg
- xlnx,rxmem
- - phy-handle
allOf:
- $ref: /schemas/net/ethernet-controller.yaml#
-additionalProperties: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - xlnx,axi-ethernet-1.00.a
+ - xlnx,axi-ethernet-1.01.a
+ - xlnx,axi-ethernet-2.01.a
+ then:
+ required:
+ - interrupts
+ - phy-handle
+ properties:
+ phy-mode:
+ enum:
+ - mii
+ - gmii
+ - rgmii
+ - sgmii
+ - 1000base-x
+ clocks:
+ items:
+ - description: Clock for AXI register slave interface.
+ - description: AXI4-Stream clock for TXD RXD TXC and RXS
+ interfaces.
+ - description: Ethernet reference clock, used by signal delay
+ primitives and transceivers.
+ - description: MGT reference clock (used by optional internal
+ PCS/PMA PHY)
+ clock-names:
+ items:
+ - const: s_axi_lite_clk
+ - const: axis_clk
+ - const: ref_clk
+ - const: mgt_clk
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: xlnx,xxv-ethernet-1.0
+ then:
+ required:
+ - dmas
+ - dma-names
+ - phy-mode
+ - clocks
+ - clock-names
+ properties:
+ phy-mode:
+ enum:
+ - 10gbase-r
+ - 25gbase-r
+ interrupts: false
+ phy-handle: false
+ pcs-handle: false
+ axistream-connected: false
+ xlnx,phy-type: false
+ xlnx,txcsum: false
+ xlnx,rxcsum: false
+ xlnx,switch-x-sgmii: false
+ mdio: false
+ clocks:
+ maxItems: 3
+ items:
+ - description: RX AXI4-Stream clock (rx_core_clk).
+ - description: GT DRP clock (dclk).
+ - description: AXI4-Lite register clock (s_axi_aclk).
+ clock-names:
+ maxItems: 3
+ items:
+ - const: rx_core_clk
+ - const: dclk
+ - const: s_axi_aclk
+
+unevaluatedProperties: false
examples:
- |
@@ -198,3 +276,15 @@ examples:
};
};
};
+
+ - |
+ ethernet@80000000 {
+ compatible = "xlnx,xxv-ethernet-1.0";
+ reg = <0x80000000 0x10000>;
+ clock-names = "rx_core_clk", "dclk", "s_axi_aclk";
+ clocks = <&rx_clk>, <&drp_clk>, <&axi_clk>;
+ dma-names = "tx_chan0", "rx_chan0";
+ dmas = <&axi_dma 0>, <&axi_dma 1>;
+ phy-mode = "25gbase-r";
+ xlnx,rxmem = <0x8000>;
+ };
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index 017fb155a5bc25..5067500ded5cc7 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -248,6 +248,7 @@ CLOCK
devm_clk_put()
devm_clk_bulk_get()
devm_clk_bulk_get_all()
+ devm_clk_bulk_get_enable()
devm_clk_bulk_get_optional()
devm_get_clk_from_child()
devm_clk_hw_register()
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index 994d5bc5168be9..49d4782991eb98 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -222,6 +222,13 @@ static int __devm_clk_bulk_get_enable(struct device *dev, int num_clks,
return ret;
}
+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return __devm_clk_bulk_get_enable(dev, num_clks, clks, false);
+}
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);
+
int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,
struct clk_bulk_data *clks)
{
diff --git a/drivers/net/ethernet/xilinx/Makefile b/drivers/net/ethernet/xilinx/Makefile
index 7d7dc1771423e8..db90e691fec580 100644
--- a/drivers/net/ethernet/xilinx/Makefile
+++ b/drivers/net/ethernet/xilinx/Makefile
@@ -6,5 +6,6 @@
ll_temac-objs := ll_temac_main.o ll_temac_mdio.o
obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o
obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
-xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o
+xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o \
+ xilinx_axienet_xxv.o
obj-$(CONFIG_XILINX_AXI_EMAC) += xilinx_emac.o
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index fcd3aaef27fc32..2ea086fc4dc367 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -10,6 +10,7 @@
#define XILINX_AXIENET_H
#include <linux/dim.h>
+#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
@@ -17,6 +18,8 @@
#include <linux/phylink.h>
#include <linux/skbuff.h>
+#include "xilinx_axienet_xxv.h"
+
/* Packet size info */
#define XAE_HDR_SIZE 14 /* Size of Ethernet header */
#define XAE_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */
@@ -545,6 +548,9 @@ struct skbuf_dma_descriptor {
* @tx_ring_tail: TX skb ring buffer tail index.
* @rx_ring_head: RX skb ring buffer head index.
* @rx_ring_tail: RX skb ring buffer tail index.
+ * @xxv_ip_version: XXV IP version.
+ * @xxv_stat_base: Software accumulators for the XXV clear-on-tick counters.
+ * @axienet_config: MAC-type specific configuration and operations.
*/
struct axienet_local {
struct net_device *ndev;
@@ -598,6 +604,7 @@ struct axienet_local {
u64 hw_stat_base[STAT_COUNT];
u32 hw_last_counter[STAT_COUNT];
+ u64 xxv_stat_base[XXV_STAT_COUNT];
seqcount_mutex_t hw_stats_seqcount;
struct mutex stats_lock;
struct delayed_work stats_work;
@@ -626,8 +633,88 @@ struct axienet_local {
int tx_ring_tail;
int rx_ring_head;
int rx_ring_tail;
+ u32 xxv_ip_version;
+ const struct axienet_config *axienet_config;
};
+/**
+ * struct axienet_config - MAC-type specific configuration and operations
+ * @mdio: MAC has an MDIO bus for external PHY management
+ * @mac_irq: MAC has a dedicated core interrupt
+ * @legacy_dma: MAC supports the legacy (non-dmaengine) DMA mode
+ * @uc_filter: MAC has unicast address filter registers
+ * @mc_filter: MAC has multicast address filter registers
+ * @vlan: MAC supports VLAN frames by default
+ * @jumbo: MAC supports jumbo frames
+ * @dma_tx_csum: MAC supports TX checksum offload
+ * @sw_padding: Short frames must be padded in software before transmit
+ * @internal_pcs: MAC always drives an internal PCS
+ * @regs_n: Number of MAC registers exposed through ethtool -d
+ * @clk_init: Callback to get and enable the MAC-specific clocks
+ * @setoptions: Callback to program MAC hardware options
+ * @probe_init: Callback for MAC-specific probe-time init, or NULL if unused
+ * @gt_reset: Callback to reset the serial transceiver (GT), or NULL if unused
+ * @mac_init: Callback for MAC-specific bring-up after the DMA reset
+ * @mac_link_up: Callback to program link speed and pause on link up, or NULL
+ * @get_regs: Callback to dump the MAC registers for ethtool -d
+ * @phylink_set_caps: Callback to set phylink MAC capabilities
+ * @pcs_ops: phylink PCS operations for this MAC, or NULL if unused
+ * @stats_update: Callback to latch/accumulate the periodic MAC counters
+ * @get_stats64: Callback to read MAC counters into rtnl_link_stats64
+ * @get_ethtool_stats: Callback to read MAC counters for ethtool -S
+ * @get_strings: Callback to fill the ethtool -S statistic name strings
+ * @get_sset_count: Callback returning the number of ethtool -S statistics
+ * @get_pause_stats: Callback to read MAC pause-frame counters
+ * @get_eth_mac_stats: Callback to read IEEE 802.3 MAC counters
+ * @get_eth_ctrl_stats: Callback to read MAC-control frame counters, or NULL
+ * if the MAC exposes no control-frame counters
+ * @get_rmon_stats: Callback to read RMON counters and histogram ranges
+ */
+struct axienet_config {
+ bool mdio;
+ bool mac_irq;
+ bool legacy_dma;
+ bool uc_filter;
+ bool mc_filter;
+ bool vlan;
+ bool jumbo;
+ bool dma_tx_csum;
+ bool sw_padding;
+ bool internal_pcs;
+ unsigned int regs_n;
+ int (*clk_init)(struct axienet_local *lp);
+ void (*setoptions)(struct net_device *ndev, u32 options);
+ void (*probe_init)(struct axienet_local *lp);
+ void (*gt_reset)(struct axienet_local *lp);
+ int (*mac_init)(struct net_device *ndev);
+ void (*mac_link_up)(struct net_device *ndev, int speed,
+ bool tx_pause, bool rx_pause);
+ void (*get_regs)(struct axienet_local *lp, u32 *data);
+ void (*phylink_set_caps)(struct axienet_local *lp,
+ struct phylink_config *config);
+ const struct phylink_pcs_ops *pcs_ops;
+ void (*stats_update)(struct axienet_local *lp);
+ void (*get_stats64)(struct axienet_local *lp,
+ struct rtnl_link_stats64 *stats);
+ void (*get_ethtool_stats)(struct axienet_local *lp, u64 *data);
+ void (*get_strings)(u8 *data);
+ int (*get_sset_count)(void);
+ void (*get_pause_stats)(struct axienet_local *lp,
+ struct ethtool_pause_stats *pause_stats);
+ void (*get_eth_mac_stats)(struct axienet_local *lp,
+ struct ethtool_eth_mac_stats *mac_stats);
+ void (*get_eth_ctrl_stats)(struct axienet_local *lp,
+ struct ethtool_eth_ctrl_stats *ctrl_stats);
+ void (*get_rmon_stats)(struct axienet_local *lp,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges);
+};
+
+static inline struct axienet_local *pcs_to_axienet_local(struct phylink_pcs *pcs)
+{
+ return container_of(pcs, struct axienet_local, pcs);
+}
+
/**
* struct axienet_option - Used to set axi ethernet hardware options
* @opt: Option to be set.
@@ -741,4 +828,7 @@ static inline void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
int axienet_mdio_setup(struct axienet_local *lp);
void axienet_mdio_teardown(struct axienet_local *lp);
+/* RMON histogram ranges shared by all MAC types */
+extern const struct ethtool_rmon_hist_range axienet_rmon_ranges[];
+
#endif /* XILINX_AXI_ENET_H */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index fcf517069d161a..b715d13ccb8eec 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -33,6 +33,7 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/skbuff.h>
#include <linux/math64.h>
#include <linux/phy.h>
@@ -65,16 +66,6 @@
static void axienet_rx_submit_desc(struct net_device *ndev);
-/* Match table for of_platform binding */
-static const struct of_device_id axienet_of_match[] = {
- { .compatible = "xlnx,axi-ethernet-1.00.a", },
- { .compatible = "xlnx,axi-ethernet-1.01.a", },
- { .compatible = "xlnx,axi-ethernet-2.01.a", },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, axienet_of_match);
-
/* Option table for setting up Axi Ethernet hardware options */
static struct axienet_option axienet_options[] = {
/* Turn on jumbo packet support for both Rx and Tx */
@@ -419,6 +410,9 @@ static void axienet_set_mac_address(struct net_device *ndev,
if (!is_valid_ether_addr(ndev->dev_addr))
eth_hw_addr_random(ndev);
+ if (!lp->axienet_config->uc_filter)
+ return;
+
/* Set up unicast MAC address filter set its mac address */
axienet_iow(lp, XAE_UAW0_OFFSET,
(ndev->dev_addr[0]) |
@@ -468,6 +462,9 @@ static void axienet_set_multicast_list(struct net_device *ndev)
u32 reg, af0reg, af1reg;
struct axienet_local *lp = netdev_priv(ndev);
+ if (!lp->axienet_config->mc_filter)
+ return;
+
reg = axienet_ior(lp, XAE_FMI_OFFSET);
reg &= ~XAE_FMI_PM_MASK;
if (ndev->flags & IFF_PROMISC)
@@ -576,16 +573,31 @@ static void axienet_stats_update(struct axienet_local *lp, bool reset)
write_seqcount_end(&lp->hw_stats_seqcount);
}
+/**
+ * axienet_1g_stats_update - Refresh 1G MAC hardware statistics
+ * @lp: Pointer to the axienet_local structure
+ */
+static void axienet_1g_stats_update(struct axienet_local *lp)
+{
+ axienet_stats_update(lp, false);
+}
+
static void axienet_refresh_stats(struct work_struct *work)
{
struct axienet_local *lp = container_of(work, struct axienet_local,
stats_work.work);
- mutex_lock(&lp->stats_lock);
- axienet_stats_update(lp, false);
- mutex_unlock(&lp->stats_lock);
+ if (lp->axienet_config->stats_update) {
+ mutex_lock(&lp->stats_lock);
+ lp->axienet_config->stats_update(lp);
+ mutex_unlock(&lp->stats_lock);
+ }
- /* Just less than 2^32 bytes at 2.5 GBit/s */
+ /* Re-arm the poll before any counter can overflow between updates: the
+ * 1G byte counter reaches just under 2^32 in this interval at 2.5 Gbit/s,
+ * and the XXV internal accumulators must be latched (via TICK in
+ * axienet_xxv_stats_update()) before they saturate at line rate.
+ */
schedule_delayed_work(&lp->stats_work, 13 * HZ);
}
@@ -594,7 +606,16 @@ static int __axienet_device_reset(struct axienet_local *lp)
u32 value;
int ret;
- /* Save statistics counters in case they will be reset */
+ /* Save statistics counters in case they will be reset.
+ *
+ * The XAE_FEATURE_STATS blocks in this function read the TEMAC
+ * statistics registers at XAE_STATS_OFFSET, i.e. they assume the 1G
+ * counter layout. This is safe because __axienet_device_reset() is
+ * only reached on the legacy (non-dmaengine) DMA path, which the
+ * legacy_dma capability restricts to the 1G MAC. MACs that use their
+ * own statistics mechanism (e.g. XXV, which is dmaengine-only) never
+ * execute this path.
+ */
mutex_lock(&lp->stats_lock);
if (lp->features & XAE_FEATURE_STATS)
axienet_stats_update(lp, true);
@@ -694,6 +715,32 @@ static void axienet_dma_stop(struct axienet_local *lp)
axienet_unlock_mii(lp);
}
+/**
+ * axienet_1g_mac_init - 1G MAC-specific bring-up after the DMA reset
+ * @ndev: Pointer to the net_device structure
+ *
+ * Return: 0 on success or a negative error number otherwise.
+ */
+static int axienet_1g_mac_init(struct net_device *ndev)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+ u32 axienet_status;
+
+ axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
+ axienet_status &= ~XAE_RCW1_RX_MASK;
+ axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
+
+ axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
+ if (axienet_status & XAE_INT_RXRJECT_MASK)
+ axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+ axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
+ XAE_INT_RECV_ERROR_MASK : 0);
+
+ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+
+ return 0;
+}
+
/**
* axienet_device_reset - Reset and initialize the Axi Ethernet hardware.
* @ndev: Pointer to the net_device structure
@@ -709,19 +756,23 @@ static void axienet_dma_stop(struct axienet_local *lp)
*/
static int axienet_device_reset(struct net_device *ndev)
{
- u32 axienet_status;
struct axienet_local *lp = netdev_priv(ndev);
int ret;
+ if (lp->axienet_config->gt_reset)
+ lp->axienet_config->gt_reset(lp);
+
lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
- lp->options |= XAE_OPTION_VLAN;
+
+ if (lp->axienet_config->vlan)
+ lp->options |= XAE_OPTION_VLAN;
lp->options &= (~XAE_OPTION_JUMBO);
if (ndev->mtu > XAE_MTU && ndev->mtu <= XAE_JUMBO_MTU) {
lp->max_frm_size = ndev->mtu + VLAN_ETH_HLEN +
XAE_TRL_SIZE;
- if (lp->max_frm_size <= lp->rxmem)
+ if (lp->max_frm_size <= lp->rxmem && lp->axienet_config->jumbo)
lp->options |= XAE_OPTION_JUMBO;
}
@@ -738,26 +789,18 @@ static int axienet_device_reset(struct net_device *ndev)
}
}
- axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
- axienet_status &= ~XAE_RCW1_RX_MASK;
- axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
-
- axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
- if (axienet_status & XAE_INT_RXRJECT_MASK)
- axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
- axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
- XAE_INT_RECV_ERROR_MASK : 0);
-
- axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+ ret = lp->axienet_config->mac_init(ndev);
+ if (ret)
+ return ret;
/* Sync default options with HW but leave receiver and
* transmitter disabled.
*/
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_set_mac_address(ndev, NULL);
axienet_set_multicast_list(ndev);
- axienet_setoptions(ndev, lp->options);
+ lp->axienet_config->setoptions(ndev, lp->options);
netif_trans_update(ndev);
@@ -915,6 +958,13 @@ axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev)
int sg_len;
int ret;
+ if (lp->axienet_config->sw_padding && eth_skb_pad(skb)) {
+ /* Pad short frames; the MAC does not append Ethernet padding. */
+ ndev->stats.tx_dropped++;
+ ndev->stats.tx_errors++;
+ return NETDEV_TX_OK;
+ }
+
dma_dev = lp->tx_chan->device;
sg_len = skb_shinfo(skb)->nr_frags + 1;
if (CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX) <= 1) {
@@ -939,19 +989,21 @@ axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev)
goto xmit_error_drop_skb;
/* Fill up app fields for checksum */
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (lp->features & XAE_FEATURE_FULL_TX_CSUM) {
- /* Tx Full Checksum Offload Enabled */
- app_metadata[0] |= 2;
- } else if (lp->features & XAE_FEATURE_PARTIAL_TX_CSUM) {
- csum_start_off = skb_transport_offset(skb);
- csum_index_off = csum_start_off + skb->csum_offset;
- /* Tx Partial Checksum Offload Enabled */
- app_metadata[0] |= 1;
- app_metadata[1] = (csum_start_off << 16) | csum_index_off;
+ if (lp->axienet_config->dma_tx_csum) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (lp->features & XAE_FEATURE_FULL_TX_CSUM) {
+ /* Tx Full Checksum Offload Enabled */
+ app_metadata[0] |= 2;
+ } else if (lp->features & XAE_FEATURE_PARTIAL_TX_CSUM) {
+ csum_start_off = skb_transport_offset(skb);
+ csum_index_off = csum_start_off + skb->csum_offset;
+ /* Tx Partial Checksum Offload Enabled */
+ app_metadata[0] |= 1;
+ app_metadata[1] = (csum_start_off << 16) | csum_index_off;
+ }
+ } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ app_metadata[0] |= 2; /* Tx Full Checksum Offload Enabled */
}
- } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
- app_metadata[0] |= 2; /* Tx Full Checksum Offload Enabled */
}
dma_tx_desc = dma_dev->device_prep_slave_sg(lp->tx_chan, skbuf_dma->sgl,
@@ -1670,6 +1722,10 @@ static int axienet_open(struct net_device *ndev)
axienet_lock_mii(lp);
ret = axienet_device_reset(ndev);
axienet_unlock_mii(lp);
+ if (ret) {
+ dev_err(lp->dev, "axienet_device_reset() failed: %d\n", ret);
+ return ret;
+ }
ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0);
if (ret) {
@@ -1738,12 +1794,17 @@ static int axienet_stop(struct net_device *ndev)
cancel_work_sync(&lp->rx_dim.work);
cancel_delayed_work_sync(&lp->stats_work);
+ if (lp->axienet_config->stats_update) {
+ mutex_lock(&lp->stats_lock);
+ lp->axienet_config->stats_update(lp);
+ mutex_unlock(&lp->stats_lock);
+ }
phylink_stop(lp->phylink);
phylink_disconnect_phy(lp->phylink);
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
if (!lp->use_dmaengine) {
axienet_dma_stop(lp);
@@ -1769,7 +1830,8 @@ static int axienet_stop(struct net_device *ndev)
}
netdev_reset_queue(ndev);
- axienet_iow(lp, XAE_IE_OFFSET, 0);
+ if (lp->axienet_config->mac_irq)
+ axienet_iow(lp, XAE_IE_OFFSET, 0);
if (lp->eth_irq > 0)
free_irq(lp->eth_irq, ndev);
@@ -1834,29 +1896,11 @@ static int axienet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return phylink_mii_ioctl(lp->phylink, rq, cmd);
}
-static void
-axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+static void axienet_1g_get_stats64(struct axienet_local *lp,
+ struct rtnl_link_stats64 *stats)
{
- struct axienet_local *lp = netdev_priv(dev);
unsigned int start;
- netdev_stats_to_stats64(stats, &dev->stats);
-
- do {
- start = u64_stats_fetch_begin(&lp->rx_stat_sync);
- stats->rx_packets = u64_stats_read(&lp->rx_packets);
- stats->rx_bytes = u64_stats_read(&lp->rx_bytes);
- } while (u64_stats_fetch_retry(&lp->rx_stat_sync, start));
-
- do {
- start = u64_stats_fetch_begin(&lp->tx_stat_sync);
- stats->tx_packets = u64_stats_read(&lp->tx_packets);
- stats->tx_bytes = u64_stats_read(&lp->tx_bytes);
- } while (u64_stats_fetch_retry(&lp->tx_stat_sync, start));
-
- if (!(lp->features & XAE_FEATURE_STATS))
- return;
-
do {
start = read_seqcount_begin(&lp->hw_stats_seqcount);
stats->rx_length_errors =
@@ -1884,6 +1928,33 @@ axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
} while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
}
+static void
+axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+ struct axienet_local *lp = netdev_priv(dev);
+ unsigned int start;
+
+ netdev_stats_to_stats64(stats, &dev->stats);
+
+ do {
+ start = u64_stats_fetch_begin(&lp->rx_stat_sync);
+ stats->rx_packets = u64_stats_read(&lp->rx_packets);
+ stats->rx_bytes = u64_stats_read(&lp->rx_bytes);
+ } while (u64_stats_fetch_retry(&lp->rx_stat_sync, start));
+
+ do {
+ start = u64_stats_fetch_begin(&lp->tx_stat_sync);
+ stats->tx_packets = u64_stats_read(&lp->tx_packets);
+ stats->tx_bytes = u64_stats_read(&lp->tx_bytes);
+ } while (u64_stats_fetch_retry(&lp->tx_stat_sync, start));
+
+ if (!(lp->features & XAE_FEATURE_STATS))
+ return;
+
+ if (lp->axienet_config->get_stats64)
+ lp->axienet_config->get_stats64(lp, stats);
+}
+
static const struct net_device_ops axienet_netdev_ops = {
.ndo_open = axienet_open,
.ndo_stop = axienet_stop,
@@ -1938,30 +2009,18 @@ static void axienet_ethtools_get_drvinfo(struct net_device *ndev,
*/
static int axienet_ethtools_get_regs_len(struct net_device *ndev)
{
- return sizeof(u32) * AXIENET_REGS_N;
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ return sizeof(u32) * lp->axienet_config->regs_n;
}
/**
- * axienet_ethtools_get_regs - Dump the contents of all registers present
- * in AxiEthernet core.
- * @ndev: Pointer to net_device structure
- * @regs: Pointer to ethtool_regs structure
- * @ret: Void pointer used to return the contents of the registers.
- *
- * This implements ethtool command for getting the Axi Ethernet register dump.
- * Issue "ethtool -d ethX" to execute this function.
+ * axienet_1g_get_regs - Dump 1G MAC registers for ethtool
+ * @lp: Pointer to the axienet_local structure
+ * @data: Buffer for register values (zeroed and sized by the caller)
*/
-static void axienet_ethtools_get_regs(struct net_device *ndev,
- struct ethtool_regs *regs, void *ret)
+static void axienet_1g_get_regs(struct axienet_local *lp, u32 *data)
{
- u32 *data = (u32 *)ret;
- size_t len = sizeof(u32) * AXIENET_REGS_N;
- struct axienet_local *lp = netdev_priv(ndev);
-
- regs->version = 0;
- regs->len = len;
-
- memset(data, 0, len);
data[0] = axienet_ior(lp, XAE_RAF_OFFSET);
data[1] = axienet_ior(lp, XAE_TPF_OFFSET);
data[2] = axienet_ior(lp, XAE_IFGP_OFFSET);
@@ -2002,6 +2061,31 @@ static void axienet_ethtools_get_regs(struct net_device *ndev,
}
}
+/**
+ * axienet_ethtools_get_regs - Dump the contents of all registers present
+ * in AxiEthernet core.
+ * @ndev: Pointer to net_device structure
+ * @regs: Pointer to ethtool_regs structure
+ * @ret: Void pointer used to return the contents of the registers.
+ *
+ * This implements ethtool command for getting the Axi Ethernet register dump.
+ * Issue "ethtool -d ethX" to execute this function.
+ */
+static void axienet_ethtools_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *ret)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+ u32 *data = (u32 *)ret;
+ size_t len;
+
+ len = sizeof(u32) * lp->axienet_config->regs_n;
+ regs->version = 0;
+ regs->len = len;
+
+ memset(data, 0, len);
+ lp->axienet_config->get_regs(lp, data);
+}
+
static void
axienet_ethtools_get_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ering,
@@ -2303,11 +2387,8 @@ static int axienet_ethtools_nway_reset(struct net_device *dev)
return phylink_ethtool_nway_reset(lp->phylink);
}
-static void axienet_ethtools_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats,
- u64 *data)
+static void axienet_1g_get_ethtool_stats(struct axienet_local *lp, u64 *data)
{
- struct axienet_local *lp = netdev_priv(dev);
unsigned int start;
do {
@@ -2324,6 +2405,17 @@ static void axienet_ethtools_get_ethtool_stats(struct net_device *dev,
} while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
}
+static void axienet_ethtools_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct axienet_local *lp = netdev_priv(dev);
+
+ if (lp->features & XAE_FEATURE_STATS &&
+ lp->axienet_config->get_ethtool_stats)
+ lp->axienet_config->get_ethtool_stats(lp, data);
+}
+
static const char axienet_ethtool_stats_strings[][ETH_GSTRING_LEN] = {
"Received bytes",
"Transmitted bytes",
@@ -2336,12 +2428,26 @@ static const char axienet_ethtool_stats_strings[][ETH_GSTRING_LEN] = {
"User Defined Counter 2",
};
+static void axienet_1g_get_strings(u8 *data)
+{
+ memcpy(data, axienet_ethtool_stats_strings,
+ sizeof(axienet_ethtool_stats_strings));
+}
+
+static int axienet_1g_get_sset_count(void)
+{
+ return ARRAY_SIZE(axienet_ethtool_stats_strings);
+}
+
static void axienet_ethtools_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
+ struct axienet_local *lp = netdev_priv(dev);
+
switch (stringset) {
case ETH_SS_STATS:
- memcpy(data, axienet_ethtool_stats_strings,
- sizeof(axienet_ethtool_stats_strings));
+ if (lp->features & XAE_FEATURE_STATS &&
+ lp->axienet_config->get_strings)
+ lp->axienet_config->get_strings(data);
break;
}
}
@@ -2352,24 +2458,20 @@ static int axienet_ethtools_get_sset_count(struct net_device *dev, int sset)
switch (sset) {
case ETH_SS_STATS:
- if (lp->features & XAE_FEATURE_STATS)
- return ARRAY_SIZE(axienet_ethtool_stats_strings);
+ if (lp->features & XAE_FEATURE_STATS &&
+ lp->axienet_config->get_sset_count)
+ return lp->axienet_config->get_sset_count();
fallthrough;
default:
return -EOPNOTSUPP;
}
}
-static void
-axienet_ethtools_get_pause_stats(struct net_device *dev,
- struct ethtool_pause_stats *pause_stats)
+static void axienet_1g_get_pause_stats(struct axienet_local *lp,
+ struct ethtool_pause_stats *pause_stats)
{
- struct axienet_local *lp = netdev_priv(dev);
unsigned int start;
- if (!(lp->features & XAE_FEATURE_STATS))
- return;
-
do {
start = read_seqcount_begin(&lp->hw_stats_seqcount);
pause_stats->tx_pause_frames =
@@ -2380,15 +2482,23 @@ axienet_ethtools_get_pause_stats(struct net_device *dev,
}
static void
-axienet_ethtool_get_eth_mac_stats(struct net_device *dev,
- struct ethtool_eth_mac_stats *mac_stats)
+axienet_ethtools_get_pause_stats(struct net_device *dev,
+ struct ethtool_pause_stats *pause_stats)
{
struct axienet_local *lp = netdev_priv(dev);
- unsigned int start;
if (!(lp->features & XAE_FEATURE_STATS))
return;
+ if (lp->axienet_config->get_pause_stats)
+ lp->axienet_config->get_pause_stats(lp, pause_stats);
+}
+
+static void axienet_1g_get_eth_mac_stats(struct axienet_local *lp,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ unsigned int start;
+
do {
start = read_seqcount_begin(&lp->hw_stats_seqcount);
mac_stats->FramesTransmittedOK =
@@ -2425,15 +2535,24 @@ axienet_ethtool_get_eth_mac_stats(struct net_device *dev,
}
static void
-axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,
- struct ethtool_eth_ctrl_stats *ctrl_stats)
+axienet_ethtool_get_eth_mac_stats(struct net_device *dev,
+ struct ethtool_eth_mac_stats *mac_stats)
{
struct axienet_local *lp = netdev_priv(dev);
- unsigned int start;
if (!(lp->features & XAE_FEATURE_STATS))
return;
+ if (lp->axienet_config->get_eth_mac_stats)
+ lp->axienet_config->get_eth_mac_stats(lp, mac_stats);
+}
+
+static void
+axienet_1g_get_eth_ctrl_stats(struct axienet_local *lp,
+ struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+ unsigned int start;
+
do {
start = read_seqcount_begin(&lp->hw_stats_seqcount);
ctrl_stats->MACControlFramesTransmitted =
@@ -2445,7 +2564,20 @@ axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,
} while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
}
-static const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {
+static void
+axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,
+ struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+ struct axienet_local *lp = netdev_priv(dev);
+
+ if (!(lp->features & XAE_FEATURE_STATS))
+ return;
+
+ if (lp->axienet_config->get_eth_ctrl_stats)
+ lp->axienet_config->get_eth_ctrl_stats(lp, ctrl_stats);
+}
+
+const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {
{ 64, 64 },
{ 65, 127 },
{ 128, 255 },
@@ -2457,16 +2589,12 @@ static const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {
};
static void
-axienet_ethtool_get_rmon_stats(struct net_device *dev,
- struct ethtool_rmon_stats *rmon_stats,
- const struct ethtool_rmon_hist_range **ranges)
+axienet_1g_get_rmon_stats(struct axienet_local *lp,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
{
- struct axienet_local *lp = netdev_priv(dev);
unsigned int start;
- if (!(lp->features & XAE_FEATURE_STATS))
- return;
-
do {
start = read_seqcount_begin(&lp->hw_stats_seqcount);
rmon_stats->undersize_pkts =
@@ -2510,6 +2638,20 @@ axienet_ethtool_get_rmon_stats(struct net_device *dev,
*ranges = axienet_rmon_ranges;
}
+static void
+axienet_ethtool_get_rmon_stats(struct net_device *dev,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct axienet_local *lp = netdev_priv(dev);
+
+ if (!(lp->features & XAE_FEATURE_STATS))
+ return;
+
+ if (lp->axienet_config->get_rmon_stats)
+ lp->axienet_config->get_rmon_stats(lp, rmon_stats, ranges);
+}
+
static const struct ethtool_ops axienet_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |
ETHTOOL_COALESCE_USECS |
@@ -2555,11 +2697,6 @@ static const struct ethtool_ops axienet_ethtool_dmaengine_ops = {
.get_rmon_stats = axienet_ethtool_get_rmon_stats,
};
-static struct axienet_local *pcs_to_axienet_local(struct phylink_pcs *pcs)
-{
- return container_of(pcs, struct axienet_local, pcs);
-}
-
static void axienet_pcs_get_state(struct phylink_pcs *pcs,
unsigned int neg_mode,
struct phylink_link_state *state)
@@ -2619,7 +2756,9 @@ static struct phylink_pcs *axienet_mac_select_pcs(struct phylink_config *config,
struct axienet_local *lp = netdev_priv(ndev);
if (interface == PHY_INTERFACE_MODE_1000BASEX ||
- interface == PHY_INTERFACE_MODE_SGMII)
+ interface == PHY_INTERFACE_MODE_SGMII ||
+ interface == PHY_INTERFACE_MODE_10GBASER ||
+ interface == PHY_INTERFACE_MODE_25GBASER)
return &lp->pcs;
return NULL;
@@ -2638,13 +2777,9 @@ static void axienet_mac_link_down(struct phylink_config *config,
/* nothing meaningful to do */
}
-static void axienet_mac_link_up(struct phylink_config *config,
- struct phy_device *phy,
- unsigned int mode, phy_interface_t interface,
- int speed, int duplex,
- bool tx_pause, bool rx_pause)
+static void axienet_1g_mac_link_up(struct net_device *ndev, int speed,
+ bool tx_pause, bool rx_pause)
{
- struct net_device *ndev = to_net_dev(config->dev);
struct axienet_local *lp = netdev_priv(ndev);
u32 emmc_reg, fcc_reg;
@@ -2681,6 +2816,19 @@ static void axienet_mac_link_up(struct phylink_config *config,
axienet_iow(lp, XAE_FCC_OFFSET, fcc_reg);
}
+static void axienet_mac_link_up(struct phylink_config *config,
+ struct phy_device *phy,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct net_device *ndev = to_net_dev(config->dev);
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ if (lp->axienet_config->mac_link_up)
+ lp->axienet_config->mac_link_up(ndev, speed, tx_pause, rx_pause);
+}
+
static const struct phylink_mac_ops axienet_phylink_ops = {
.mac_select_pcs = axienet_mac_select_pcs,
.mac_config = axienet_mac_config,
@@ -2698,7 +2846,6 @@ static const struct phylink_mac_ops axienet_phylink_ops = {
static void axienet_dma_err_handler(struct work_struct *work)
{
u32 i;
- u32 axienet_status;
struct axidma_bd *cur_p;
struct axienet_local *lp = container_of(work, struct axienet_local,
dma_err_task);
@@ -2711,8 +2858,8 @@ static void axienet_dma_err_handler(struct work_struct *work)
napi_disable(&lp->napi_tx);
napi_disable(&lp->napi_rx);
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_dma_stop(lp);
netdev_reset_queue(ndev);
@@ -2757,29 +2904,126 @@ static void axienet_dma_err_handler(struct work_struct *work)
axienet_dma_start(lp);
- axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
- axienet_status &= ~XAE_RCW1_RX_MASK;
- axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
-
- axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
- if (axienet_status & XAE_INT_RXRJECT_MASK)
- axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
- axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
- XAE_INT_RECV_ERROR_MASK : 0);
- axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+ /* This error handler runs only for the legacy embedded-DMA (1G) path,
+ * whose mac_init() cannot fail, so its return value is not checked.
+ */
+ lp->axienet_config->mac_init(ndev);
/* Sync default options with HW but leave receiver and
* transmitter disabled.
*/
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_set_mac_address(ndev, NULL);
axienet_set_multicast_list(ndev);
napi_enable(&lp->napi_rx);
napi_enable(&lp->napi_tx);
- axienet_setoptions(ndev, lp->options);
+ lp->axienet_config->setoptions(ndev, lp->options);
+}
+
+/**
+ * axienet_1g_phylink_set_caps - Set 1G phylink capabilities and interfaces
+ * @lp: Pointer to the axienet_local structure
+ * @config: Pointer to the phylink_config structure
+ */
+static void axienet_1g_phylink_set_caps(struct axienet_local *lp,
+ struct phylink_config *config)
+{
+ config->mac_capabilities |= MAC_10FD | MAC_100FD | MAC_1000FD;
+ __set_bit(lp->phy_mode, config->supported_interfaces);
+ if (lp->switch_x_sgmii) {
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_SGMII,
+ config->supported_interfaces);
+ }
+}
+
+/**
+ * axienet_1g_clk_init - Get and enable the 1G MAC clocks
+ * @lp: Pointer to the axienet_local structure
+ *
+ * Return: 0 on success or a negative error number otherwise.
+ */
+static int axienet_1g_clk_init(struct axienet_local *lp)
+{
+ struct device *dev = lp->dev;
+ int ret;
+
+ lp->axi_clk = devm_clk_get_optional_enabled(dev, "s_axi_lite_clk");
+ if (!lp->axi_clk) {
+ /* For backward compatibility, if named AXI clock is not
+ * present, treat the first clock specified as the AXI clock.
+ */
+ lp->axi_clk = devm_clk_get_optional_enabled(dev, NULL);
+ }
+ if (IS_ERR(lp->axi_clk))
+ return dev_err_probe(dev, PTR_ERR(lp->axi_clk),
+ "could not get AXI clock\n");
+
+ lp->misc_clks[0].id = "axis_clk";
+ lp->misc_clks[1].id = "ref_clk";
+ lp->misc_clks[2].id = "mgt_clk";
+
+ ret = devm_clk_bulk_get_optional_enable(dev, XAE_NUM_MISC_CLOCKS,
+ lp->misc_clks);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "could not get/enable misc. clocks\n");
+
+ return 0;
+}
+
+/**
+ * axienet_1g_probe_init - 1G MAC-specific probe-time initialization
+ * @lp: Pointer to the axienet_local structure
+ */
+static void axienet_1g_probe_init(struct axienet_local *lp)
+{
+ if (axienet_ior(lp, XAE_ABILITY_OFFSET) & XAE_ABILITY_STATS)
+ lp->features |= XAE_FEATURE_STATS;
}
+static const struct axienet_config axienet_1g_config = {
+ .mdio = true,
+ .mac_irq = true,
+ .legacy_dma = true,
+ .uc_filter = true,
+ .mc_filter = true,
+ .vlan = true,
+ .jumbo = true,
+ .dma_tx_csum = true,
+ .regs_n = AXIENET_REGS_N,
+ .clk_init = axienet_1g_clk_init,
+ .setoptions = axienet_setoptions,
+ .probe_init = axienet_1g_probe_init,
+ .mac_init = axienet_1g_mac_init,
+ .mac_link_up = axienet_1g_mac_link_up,
+ .get_regs = axienet_1g_get_regs,
+ .phylink_set_caps = axienet_1g_phylink_set_caps,
+ .pcs_ops = &axienet_pcs_ops,
+ .stats_update = axienet_1g_stats_update,
+ .get_stats64 = axienet_1g_get_stats64,
+ .get_ethtool_stats = axienet_1g_get_ethtool_stats,
+ .get_strings = axienet_1g_get_strings,
+ .get_sset_count = axienet_1g_get_sset_count,
+ .get_pause_stats = axienet_1g_get_pause_stats,
+ .get_eth_mac_stats = axienet_1g_get_eth_mac_stats,
+ .get_eth_ctrl_stats = axienet_1g_get_eth_ctrl_stats,
+ .get_rmon_stats = axienet_1g_get_rmon_stats,
+};
+
+/* Match table for of_platform binding */
+static const struct of_device_id axienet_of_match[] = {
+ { .compatible = "xlnx,axi-ethernet-1.00.a", .data = &axienet_1g_config },
+ { .compatible = "xlnx,axi-ethernet-1.01.a", .data = &axienet_1g_config },
+ { .compatible = "xlnx,axi-ethernet-2.01.a", .data = &axienet_1g_config },
+ { .compatible = "xlnx,xxv-ethernet-1.0", .data = &axienet_10g25g_config },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, axienet_of_match);
+
/**
* axienet_probe - Axi Ethernet probe function.
* @pdev: Pointer to platform device structure.
@@ -2830,27 +3074,13 @@ static int axienet_probe(struct platform_device *pdev)
seqcount_mutex_init(&lp->hw_stats_seqcount, &lp->stats_lock);
INIT_DEFERRABLE_WORK(&lp->stats_work, axienet_refresh_stats);
- lp->axi_clk = devm_clk_get_optional_enabled(&pdev->dev,
- "s_axi_lite_clk");
- if (!lp->axi_clk) {
- /* For backward compatibility, if named AXI clock is not present,
- * treat the first clock specified as the AXI clock.
- */
- lp->axi_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
- }
- if (IS_ERR(lp->axi_clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(lp->axi_clk),
- "could not get AXI clock\n");
+ lp->axienet_config = device_get_match_data(&pdev->dev);
+ if (!lp->axienet_config)
+ return -ENODEV;
- lp->misc_clks[0].id = "axis_clk";
- lp->misc_clks[1].id = "ref_clk";
- lp->misc_clks[2].id = "mgt_clk";
-
- ret = devm_clk_bulk_get_optional_enable(&pdev->dev, XAE_NUM_MISC_CLOCKS,
- lp->misc_clks);
+ ret = lp->axienet_config->clk_init(lp);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "could not get/enable misc. clocks\n");
+ return ret;
/* Map device registers */
lp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ðres);
@@ -2861,9 +3091,6 @@ static int axienet_probe(struct platform_device *pdev)
/* Setup checksum offload, but default to off if not specified */
lp->features = 0;
- if (axienet_ior(lp, XAE_ABILITY_OFFSET) & XAE_ABILITY_STATS)
- lp->features |= XAE_FEATURE_STATS;
-
ret = of_property_read_u32(pdev->dev.of_node, "xlnx,txcsum", &value);
if (!ret) {
switch (value) {
@@ -2937,7 +3164,17 @@ static int axienet_probe(struct platform_device *pdev)
return -EINVAL;
}
+ if (lp->axienet_config->probe_init)
+ lp->axienet_config->probe_init(lp);
+
if (!of_property_present(pdev->dev.of_node, "dmas")) {
+ /* Non-dmaengine (legacy DMA) mode is only supported by some MACs */
+ if (!lp->axienet_config->legacy_dma) {
+ dev_err(&pdev->dev,
+ "Legacy DMA mode not supported by this MAC, use dmaengine\n");
+ return -EINVAL;
+ }
+
/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
@@ -3017,7 +3254,10 @@ static int axienet_probe(struct platform_device *pdev)
struct xilinx_vdma_config cfg;
struct dma_chan *tx_chan;
- lp->eth_irq = platform_get_irq_optional(pdev, 0);
+ if (lp->axienet_config->mac_irq)
+ lp->eth_irq = platform_get_irq_optional(pdev, 0);
+ else
+ lp->eth_irq = -ENXIO;
if (lp->eth_irq < 0 && lp->eth_irq != -ENXIO) {
return lp->eth_irq;
}
@@ -3070,10 +3310,12 @@ static int axienet_probe(struct platform_device *pdev)
lp->tx_dma_cr = axienet_calc_cr(lp, XAXIDMA_DFT_TX_THRESHOLD,
XAXIDMA_DFT_TX_USEC);
- ret = axienet_mdio_setup(lp);
- if (ret)
- dev_warn(&pdev->dev,
- "error registering MDIO bus: %d\n", ret);
+ if (lp->axienet_config->mdio) {
+ ret = axienet_mdio_setup(lp);
+ if (ret)
+ dev_warn(&pdev->dev,
+ "error registering MDIO bus: %d\n", ret);
+ }
if (lp->phy_mode == PHY_INTERFACE_MODE_SGMII ||
lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX) {
@@ -3097,23 +3339,21 @@ static int axienet_probe(struct platform_device *pdev)
goto cleanup_mdio;
}
of_node_put(np);
- lp->pcs.ops = &axienet_pcs_ops;
+ lp->pcs.ops = lp->axienet_config->pcs_ops;
+ lp->pcs.poll = true;
+ }
+
+ if (lp->axienet_config->internal_pcs) {
+ lp->pcs.ops = lp->axienet_config->pcs_ops;
lp->pcs.poll = true;
}
lp->phylink_config.dev = &ndev->dev;
lp->phylink_config.type = PHYLINK_NETDEV;
lp->phylink_config.mac_managed_pm = true;
- lp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
- MAC_10FD | MAC_100FD | MAC_1000FD;
+ lp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
- __set_bit(lp->phy_mode, lp->phylink_config.supported_interfaces);
- if (lp->switch_x_sgmii) {
- __set_bit(PHY_INTERFACE_MODE_1000BASEX,
- lp->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_SGMII,
- lp->phylink_config.supported_interfaces);
- }
+ lp->axienet_config->phylink_set_caps(lp, &lp->phylink_config);
lp->phylink = phylink_create(&lp->phylink_config, pdev->dev.fwnode,
lp->phy_mode,
@@ -3156,7 +3396,8 @@ static void axienet_remove(struct platform_device *pdev)
if (lp->pcs_phy)
put_device(&lp->pcs_phy->dev);
- axienet_mdio_teardown(lp);
+ if (lp->mii_bus)
+ axienet_mdio_teardown(lp);
}
static void axienet_shutdown(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
new file mode 100644
index 00000000000000..ea4bf99fddfa48
--- /dev/null
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * XXV (10G/25G) support
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/iopoll.h>
+#include <linux/netdevice.h>
+#include <linux/phylink.h>
+#include <linux/string.h>
+
+#include "xilinx_axienet.h"
+#include "xilinx_axienet_xxv.h"
+
+/* readl_poll_timeout() sleep interval (us) and 1 ms total timeout for GT
+ * reset-done and PCS block-lock polls. Values from ZynqMP/Versal bring-up;
+ * PG210 does not specify these bounds.
+ */
+#define XXV_LINK_POLL_INTERVAL_US 10
+
+/* Number of XXV (10G/25G) MAC registers exposed via ethtool -d.
+ * Covers configuration and status registers per Xilinx PG210.
+ */
+static const u32 axienet_xxv_reg_dump_offsets[XXV_REGS_N] = {
+ XXV_GT_RESET_OFFSET,
+ XXV_RESET_OFFSET,
+ XXV_MODE_OFFSET,
+ XXV_TC_OFFSET,
+ XXV_RCW1_OFFSET,
+ XXV_JUM_OFFSET,
+ XXV_VL_LENGTH_OFFSET,
+ XXV_TICKREG_OFFSET,
+ XXV_CONFIG_REVISION,
+ XXV_CONFIG_1588_OFFSET,
+ XXV_CONFIG_TX_FLOW_CTRL1_OFFSET,
+ XXV_CONFIG_RX_FLOW_CTRL1_OFFSET,
+ XXV_CONFIG_RX_FLOW_CTRL2_OFFSET,
+ XXV_CONFIG_RSFEC_OFFSET,
+ XXV_CONFIG_FEC_OFFSET,
+ XXV_AN_CTL1_OFFSET,
+ XXV_AN_CTL2_OFFSET,
+ XXV_AN_ABILITY_OFFSET,
+ XXV_LT_CTL1_OFFSET,
+ XXV_SWITCH_CORE_SPEED_OFFSET,
+ XXV_CONFIG_1588_32BIT_OFFSET,
+ XXV_TX_CONFIG_1588_OFFSET,
+ XXV_RX_CONFIG_1588_OFFSET,
+ XXV_GTWIZ_CTRL_OFFSET,
+ XXV_STATRX_STATUS0_OFFSET,
+ XXV_RX_STATUS_REG1,
+ XXV_STATRX_STATUS2_OFFSET,
+ XXV_STATRX_BLKLCK_OFFSET,
+ XXV_STAT_RX_RSFEC_STATUS_OFFSET,
+ XXV_STAT_RX_FEC_STATUS_OFFSET,
+ XXV_STAT_TX_RSFEC_STATUS_OFFSET,
+ XXV_STAT_TX_FLOW_CTRL1_OFFSET,
+ XXV_STAT_RX_FLOW_CTRL1_OFFSET,
+ XXV_STAT_AN_STS_OFFSET,
+ XXV_STAT_AN_LP_STATUS_OFFSET,
+ XXV_STAT_AN_LINK_CTL_OFFSET,
+ XXV_STAT_LT_STATUS1_OFFSET,
+ XXV_STAT_LT_STATUS2_OFFSET,
+ XXV_STAT_LT_STATUS3_OFFSET,
+ XXV_STAT_LT_STATUS4_OFFSET,
+ XXV_STAT_LT_COEFF0_OFFSET,
+ XXV_STAT_RX_VALID_CTRL_CODE_OFFSET,
+ XXV_STAT_CORE_SPEED_OFFSET,
+ XXV_STAT_TSN_OFFSET,
+ XXV_STAT_GTWIZ_OFFSET,
+ XXV_STAT_AN_LINK_CTL2_OFFSET,
+};
+
+/* Option table for setting up XXV Ethernet hardware options */
+static struct axienet_option xxvenet_options[] = {
+ { /* Turn on FCS stripping on receive packets */
+ .opt = XAE_OPTION_FCS_STRIP,
+ .reg = XXV_RCW1_OFFSET,
+ .m_or = XXV_RCW1_FCS_MASK,
+ }, { /* Turn on FCS insertion on transmit packets */
+ .opt = XAE_OPTION_FCS_INSERT,
+ .reg = XXV_TC_OFFSET,
+ .m_or = XXV_TC_FCS_MASK,
+ }, { /* Enable transmitter */
+ .opt = XAE_OPTION_TXEN,
+ .reg = XXV_TC_OFFSET,
+ .m_or = XXV_TC_TX_MASK,
+ }, { /* Enable receiver */
+ .opt = XAE_OPTION_RXEN,
+ .reg = XXV_RCW1_OFFSET,
+ .m_or = XXV_RCW1_RX_MASK,
+ },
+ {}
+};
+
+/* PG210 statistics-block offsets indexed by enum xxv_stat. Each entry is
+ * the 32-bit LSB register address; the corresponding MSB is at +4.
+ */
+static const u32 axienet_xxv_stat_offsets[XXV_STAT_COUNT] = {
+ [XXV_STAT_RX_TOTAL_PACKETS] = XXV_STAT_RX_TOTAL_PACKETS_OFFSET,
+ [XXV_STAT_RX_TOTAL_GOOD_PACKETS] = XXV_STAT_RX_TOTAL_GOOD_PACKETS_OFFSET,
+ [XXV_STAT_RX_TOTAL_BYTES] = XXV_STAT_RX_TOTAL_BYTES_OFFSET,
+ [XXV_STAT_RX_TOTAL_GOOD_BYTES] = XXV_STAT_RX_TOTAL_GOOD_BYTES_OFFSET,
+ [XXV_STAT_RX_BAD_FCS] = XXV_STAT_RX_BAD_FCS_OFFSET,
+ [XXV_STAT_RX_INRANGEERR] = XXV_STAT_RX_INRANGEERR_OFFSET,
+ [XXV_STAT_RX_MULTICAST] = XXV_STAT_RX_MULTICAST_OFFSET,
+ [XXV_STAT_RX_BROADCAST] = XXV_STAT_RX_BROADCAST_OFFSET,
+ [XXV_STAT_RX_UNDERSIZE] = XXV_STAT_RX_UNDERSIZE_OFFSET,
+ [XXV_STAT_RX_FRAGMENT] = XXV_STAT_RX_FRAGMENT_OFFSET,
+ [XXV_STAT_RX_JABBER] = XXV_STAT_RX_JABBER_OFFSET,
+ [XXV_STAT_RX_OVERSIZE] = XXV_STAT_RX_OVERSIZE_OFFSET,
+ [XXV_STAT_RX_PAUSE] = XXV_STAT_RX_PAUSE_OFFSET,
+ [XXV_STAT_TX_TOTAL_PACKETS] = XXV_STAT_TX_TOTAL_PACKETS_OFFSET,
+ [XXV_STAT_TX_TOTAL_GOOD_PACKETS] = XXV_STAT_TX_TOTAL_GOOD_PACKETS_OFFSET,
+ [XXV_STAT_TX_TOTAL_BYTES] = XXV_STAT_TX_TOTAL_BYTES_OFFSET,
+ [XXV_STAT_TX_TOTAL_GOOD_BYTES] = XXV_STAT_TX_TOTAL_GOOD_BYTES_OFFSET,
+ [XXV_STAT_TX_BAD_FCS] = XXV_STAT_TX_BAD_FCS_OFFSET,
+ [XXV_STAT_TX_FRAME_ERROR] = XXV_STAT_TX_FRAME_ERROR_OFFSET,
+ [XXV_STAT_TX_MULTICAST] = XXV_STAT_TX_MULTICAST_OFFSET,
+ [XXV_STAT_TX_BROADCAST] = XXV_STAT_TX_BROADCAST_OFFSET,
+ [XXV_STAT_TX_PAUSE] = XXV_STAT_TX_PAUSE_OFFSET,
+};
+
+/* XXV (PG210) counters exposed via ethtool -S. Only counters that have no
+ * standard uAPI are listed here; the totals include errored frames, so they
+ * are distinct from the good-frame counts in rtnl_link_stats64 and the
+ * IEEE MAC statistics. Every other XXV counter is reported through the
+ * dedicated stats64, pause, MAC and RMON callbacks instead.
+ */
+static const enum xxv_stat axienet_xxv_priv_stats[] = {
+ XXV_STAT_RX_TOTAL_PACKETS,
+ XXV_STAT_RX_TOTAL_BYTES,
+ XXV_STAT_TX_TOTAL_PACKETS,
+ XXV_STAT_TX_TOTAL_BYTES,
+ XXV_STAT_TX_BAD_FCS,
+ XXV_STAT_TX_FRAME_ERROR,
+};
+
+static const char axienet_xxv_ethtool_stats_strings[][ETH_GSTRING_LEN] = {
+ "RX Total Packets",
+ "RX Total Bytes",
+ "TX Total Packets",
+ "TX Total Bytes",
+ "TX Bad FCS",
+ "TX Frame Error",
+};
+
+static u64 axienet_xxv_read_counter(struct axienet_local *lp, enum xxv_stat stat)
+{
+ u32 off = axienet_xxv_stat_offsets[stat];
+ u32 lsb, msb;
+
+ lsb = axienet_ior(lp, off);
+ msb = axienet_ior(lp, off + XXV_STAT_MSB_OFFSET);
+
+ return ((u64)msb << 32) | lsb;
+}
+
+static bool axienet_xxv_ip_has_gtwiz_status(u32 ip_version)
+{
+ u8 minor = FIELD_GET(XXV_MIN_MASK, ip_version);
+ u8 maj = ip_version & XXV_MAJ_MASK;
+
+ if (maj == XXV_IP_VER_GTWIZ_MAJ_MIN)
+ return minor >= XXV_IP_VER_GTWIZ_MIN_MIN;
+ return maj > XXV_IP_VER_GTWIZ_MAJ_MIN;
+}
+
+/**
+ * axienet_xxv_setoptions - Set XXV MAC options from the option table
+ * @ndev: Pointer to the net_device structure
+ * @options: Option flags to apply
+ */
+static void axienet_xxv_setoptions(struct net_device *ndev, u32 options)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+ struct axienet_option *tp = xxvenet_options;
+ u32 reg;
+
+ while (tp->opt) {
+ reg = axienet_ior(lp, tp->reg) & ~tp->m_or;
+ if (options & tp->opt)
+ reg |= tp->m_or;
+ axienet_iow(lp, tp->reg, reg);
+ tp++;
+ }
+
+ lp->options |= options;
+}
+
+/**
+ * axienet_xxv_probe_init - Initialize XXV-specific state at probe time
+ * @lp: Pointer to the axienet_local structure
+ */
+static void axienet_xxv_probe_init(struct axienet_local *lp)
+{
+ lp->xxv_ip_version = axienet_ior(lp, XXV_CONFIG_REVISION);
+ lp->features |= XAE_FEATURE_STATS;
+}
+
+/**
+ * axienet_xxv_gt_reset - Pulse the XXV GT reset line
+ * @lp: Pointer to the axienet_local structure
+ */
+static void axienet_xxv_gt_reset(struct axienet_local *lp)
+{
+ u32 val;
+
+ /* Reset GT */
+ val = axienet_ior(lp, XXV_GT_RESET_OFFSET);
+ val |= XXV_GT_RESET_MASK;
+ axienet_iow(lp, XXV_GT_RESET_OFFSET, val);
+ /* Allow 1 ms for the GT reset to settle (see timeout note above) */
+ mdelay(1);
+ val = axienet_ior(lp, XXV_GT_RESET_OFFSET);
+ val &= ~XXV_GT_RESET_MASK;
+ axienet_iow(lp, XXV_GT_RESET_OFFSET, val);
+}
+
+/**
+ * axienet_xxv_poll_link_ready - Wait for XXV GT and PCS block lock
+ * @ndev: Pointer to the net_device structure
+ *
+ * Poll GT wizard reset-done on IP v3.2+, then RX PCS block lock. Block-lock
+ * failure is logged but not propagated: it depends on a live link partner and
+ * reference clock, so an unplugged cable must not fail device bring-up.
+ *
+ * Return: 0 on success, or a negative error if GT reset-done times out.
+ */
+static int axienet_xxv_poll_link_ready(struct net_device *ndev)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+ u32 val;
+ int ret;
+
+ /* Confirm XXV Ethernet is up: on IP v3.2+, wait for GT
+ * reset-done before further register access, then poll until
+ * RX PCS block lock is asserted.
+ */
+ if (axienet_xxv_ip_has_gtwiz_status(lp->xxv_ip_version)) {
+ ret = readl_poll_timeout(lp->regs + XXV_STAT_GTWIZ_OFFSET,
+ val, (val & XXV_GTWIZ_RESET_DONE),
+ XXV_LINK_POLL_INTERVAL_US,
+ DELAY_OF_ONE_MILLISEC);
+ if (ret) {
+ netdev_err(ndev, "XXV MAC GT reset not complete! Cross-check the MAC ref clock configuration\n");
+ return ret;
+ }
+ }
+
+ ret = readl_poll_timeout(lp->regs + XXV_STATRX_BLKLCK_OFFSET,
+ val, (val & XXV_RX_BLKLCK_MASK),
+ XXV_LINK_POLL_INTERVAL_US,
+ DELAY_OF_ONE_MILLISEC);
+ if (ret)
+ netdev_err(ndev, "XXV MAC block lock not complete! Cross-check the MAC ref clock configuration\n");
+
+ return 0;
+}
+
+/**
+ * axienet_xxv_mac_init - XXV MAC-specific bring-up after the DMA reset
+ * @ndev: Pointer to the net_device structure
+ *
+ * Return: 0 on success or a negative error number otherwise.
+ */
+static int axienet_xxv_mac_init(struct net_device *ndev)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+ int ret;
+
+ ret = axienet_xxv_poll_link_ready(ndev);
+ if (ret)
+ return ret;
+
+ lp->options |= XAE_OPTION_FCS_STRIP;
+ lp->options |= XAE_OPTION_FCS_INSERT;
+
+ return 0;
+}
+
+static void axienet_xxv_phylink_set_capabilities(struct axienet_local *lp,
+ struct phylink_config *cfg)
+{
+ u32 core_speed;
+ bool rtsw;
+
+ core_speed = axienet_ior(lp, XXV_STAT_CORE_SPEED_OFFSET);
+ /* Bit[1:0]: 00=25G, 01=10G, 10=runtime-switchable 25G,
+ * 11=runtime-switchable 10G. A runtime-switchable core can operate at
+ * either speed, so advertise both; a fixed core advertises only its
+ * configured speed.
+ */
+ rtsw = core_speed & XXV_STAT_CORE_SPEED_RTSW_MASK;
+
+ if (rtsw || (core_speed & XXV_STAT_CORE_SPEED_10G_MASK)) {
+ cfg->mac_capabilities |= MAC_10000FD;
+ __set_bit(PHY_INTERFACE_MODE_10GBASER,
+ cfg->supported_interfaces);
+ }
+
+ if (rtsw || !(core_speed & XXV_STAT_CORE_SPEED_10G_MASK)) {
+ cfg->mac_capabilities |= MAC_25000FD;
+ __set_bit(PHY_INTERFACE_MODE_25GBASER,
+ cfg->supported_interfaces);
+ }
+}
+
+static void axienet_xxv_pcs_get_state(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ struct axienet_local *lp = pcs_to_axienet_local(pcs);
+
+ state->duplex = DUPLEX_FULL;
+ state->an_complete = !!(axienet_ior(lp, XXV_STAT_AN_STS_OFFSET) &
+ XXV_AN_COMPLETE_MASK);
+ state->link = axienet_ior(lp, XXV_RX_STATUS_REG1) &
+ XXV_RX_STATUS_MASK;
+
+ if (axienet_ior(lp, XXV_STAT_CORE_SPEED_OFFSET) &
+ XXV_STAT_CORE_SPEED_10G_MASK)
+ state->speed = SPEED_10000;
+ else
+ state->speed = SPEED_25000;
+}
+
+static int axienet_xxv_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ return 0;
+}
+
+static const struct phylink_pcs_ops axienet_xxv_pcs_ops = {
+ .pcs_get_state = axienet_xxv_pcs_get_state,
+ .pcs_config = axienet_xxv_pcs_config,
+};
+
+/**
+ * axienet_xxv_get_regs - Dump XXV MAC registers for ethtool
+ * @lp: Pointer to the axienet_local structure
+ * @data: Buffer for register values (zeroed and sized by the caller)
+ */
+static void axienet_xxv_get_regs(struct axienet_local *lp, u32 *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(axienet_xxv_reg_dump_offsets); i++)
+ data[i] = axienet_ior(lp, axienet_xxv_reg_dump_offsets[i]);
+}
+
+static int axienet_10g25g_clk_init(struct axienet_local *lp)
+{
+ struct device *dev = lp->dev;
+ int ret;
+
+ /* The register, RX and GT DRP clocks are mandatory for MAC+PCS
+ * operation, so fetch them as required.
+ */
+ lp->axi_clk = devm_clk_get_enabled(dev, "s_axi_aclk");
+ if (IS_ERR(lp->axi_clk))
+ return dev_err_probe(dev, PTR_ERR(lp->axi_clk),
+ "could not get AXI clock\n");
+
+ lp->misc_clks[0].id = "rx_core_clk";
+ lp->misc_clks[1].id = "dclk";
+
+ ret = devm_clk_bulk_get_enable(dev, 2, lp->misc_clks);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "could not get/enable XXV clocks\n");
+
+ return 0;
+}
+
+/**
+ * axienet_xxv_stats_update - Latch and accumulate XXV hardware counters
+ * @lp: Pointer to the axienet_local structure
+ *
+ * The XXV statistics counters are clear-on-tick (PG210): writing TICK_REG
+ * latches the internal accumulators into the readable STAT_*_LSB/MSB registers
+ * and clears the internal accumulators. Each post-TICK read therefore returns
+ * the count for the interval since the previous TICK, so software accumulates
+ * those intervals into lp->xxv_stat_base. A last-counter delta (as used by the
+ * free-running 1G MAC path) is not needed.
+ */
+static void axienet_xxv_stats_update(struct axienet_local *lp)
+{
+ u64 counter[XXV_STAT_COUNT];
+ enum xxv_stat stat;
+
+ /* Latch the clear-on-tick snapshot and read the counters outside the
+ * seqcount write section, so only the accumulator updates run inside it
+ * and the reader retry window stays short.
+ */
+ axienet_iow(lp, XXV_TICKREG_OFFSET, XXV_TICKREG_STATEN_MASK);
+ for (stat = 0; stat < XXV_STAT_COUNT; stat++)
+ counter[stat] = axienet_xxv_read_counter(lp, stat);
+
+ write_seqcount_begin(&lp->hw_stats_seqcount);
+ for (stat = 0; stat < XXV_STAT_COUNT; stat++)
+ lp->xxv_stat_base[stat] += counter[stat];
+ write_seqcount_end(&lp->hw_stats_seqcount);
+}
+
+/**
+ * axienet_xxv_get_stats64 - Fill rtnl_link_stats64 from XXV counters
+ * @lp: Pointer to the axienet_local structure
+ * @stats: Output rtnl_link_stats64 structure to populate
+ */
+static void axienet_xxv_get_stats64(struct axienet_local *lp,
+ struct rtnl_link_stats64 *stats)
+{
+ unsigned int start;
+ u64 tx_hw_errors;
+
+ do {
+ start = read_seqcount_begin(&lp->hw_stats_seqcount);
+ stats->rx_crc_errors = lp->xxv_stat_base[XXV_STAT_RX_BAD_FCS];
+ /* Both in-range length errors and frame-too-long (oversize)
+ * frames are IEEE 802.3 length errors, so fold them together
+ * into rx_length_errors; rx_over_errors is reserved for receiver
+ * FIFO/ring overflow, which the XXV MAC does not expose.
+ */
+ stats->rx_length_errors =
+ lp->xxv_stat_base[XXV_STAT_RX_INRANGEERR] +
+ lp->xxv_stat_base[XXV_STAT_RX_OVERSIZE];
+ stats->rx_errors = lp->xxv_stat_base[XXV_STAT_RX_UNDERSIZE] +
+ lp->xxv_stat_base[XXV_STAT_RX_FRAGMENT] +
+ lp->xxv_stat_base[XXV_STAT_RX_JABBER] +
+ stats->rx_crc_errors +
+ stats->rx_length_errors;
+ stats->multicast = lp->xxv_stat_base[XXV_STAT_RX_MULTICAST];
+ tx_hw_errors = lp->xxv_stat_base[XXV_STAT_TX_BAD_FCS] +
+ lp->xxv_stat_base[XXV_STAT_TX_FRAME_ERROR];
+ } while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
+
+ /* Fold the HW TX error count into the software tx_errors seeded from
+ * dev->stats by the caller. The XXV xmit path bumps dev->stats.tx_errors
+ * for frames dropped on pad failure before they reach the MAC, while the
+ * HW counters only cover frames the MAC actually transmitted; the two are
+ * disjoint. This runs once, outside the seqcount retry loop, so a racing
+ * stats update cannot make the accumulation re-add on retry.
+ */
+ stats->tx_errors += tx_hw_errors;
+}
+
+/**
+ * axienet_xxv_get_ethtool_stats - Copy XXV counters for ethtool -S
+ * @lp: Pointer to the axienet_local structure
+ * @data: Output buffer sized for ARRAY_SIZE(axienet_xxv_priv_stats) u64 values
+ */
+static void axienet_xxv_get_ethtool_stats(struct axienet_local *lp, u64 *data)
+{
+ unsigned int i, start;
+
+ do {
+ start = read_seqcount_begin(&lp->hw_stats_seqcount);
+ for (i = 0; i < ARRAY_SIZE(axienet_xxv_priv_stats); i++)
+ data[i] = lp->xxv_stat_base[axienet_xxv_priv_stats[i]];
+ } while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
+}
+
+/**
+ * axienet_xxv_get_strings - Copy XXV ethtool statistics name strings
+ * @data: Output buffer for the statistics name strings
+ */
+static void axienet_xxv_get_strings(u8 *data)
+{
+ memcpy(data, axienet_xxv_ethtool_stats_strings,
+ sizeof(axienet_xxv_ethtool_stats_strings));
+}
+
+/**
+ * axienet_xxv_get_sset_count - Number of XXV ethtool statistics
+ *
+ * Return: Count of XXV hardware statistics reported via ethtool -S.
+ */
+static int axienet_xxv_get_sset_count(void)
+{
+ return ARRAY_SIZE(axienet_xxv_ethtool_stats_strings);
+}
+
+/**
+ * axienet_xxv_get_pause_stats - Fill ethtool pause frame statistics
+ * @lp: Pointer to the axienet_local structure
+ * @pause_stats: Output ethtool_pause_stats structure to populate
+ */
+static void axienet_xxv_get_pause_stats(struct axienet_local *lp,
+ struct ethtool_pause_stats *pause_stats)
+{
+ unsigned int start;
+
+ do {
+ start = read_seqcount_begin(&lp->hw_stats_seqcount);
+ pause_stats->tx_pause_frames =
+ lp->xxv_stat_base[XXV_STAT_TX_PAUSE];
+ pause_stats->rx_pause_frames =
+ lp->xxv_stat_base[XXV_STAT_RX_PAUSE];
+ } while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
+}
+
+/**
+ * axienet_xxv_get_eth_mac_stats - Fill IEEE 802.3 MAC statistics
+ * @lp: Pointer to the axienet_local structure
+ * @mac_stats: Output ethtool_eth_mac_stats structure to populate
+ */
+static void axienet_xxv_get_eth_mac_stats(struct axienet_local *lp,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ unsigned int start;
+
+ do {
+ start = read_seqcount_begin(&lp->hw_stats_seqcount);
+ mac_stats->FramesTransmittedOK =
+ lp->xxv_stat_base[XXV_STAT_TX_TOTAL_GOOD_PACKETS];
+ mac_stats->FramesReceivedOK =
+ lp->xxv_stat_base[XXV_STAT_RX_TOTAL_GOOD_PACKETS];
+ mac_stats->OctetsTransmittedOK =
+ lp->xxv_stat_base[XXV_STAT_TX_TOTAL_GOOD_BYTES];
+ mac_stats->OctetsReceivedOK =
+ lp->xxv_stat_base[XXV_STAT_RX_TOTAL_GOOD_BYTES];
+ mac_stats->FrameCheckSequenceErrors =
+ lp->xxv_stat_base[XXV_STAT_RX_BAD_FCS];
+ mac_stats->MulticastFramesXmittedOK =
+ lp->xxv_stat_base[XXV_STAT_TX_MULTICAST];
+ mac_stats->BroadcastFramesXmittedOK =
+ lp->xxv_stat_base[XXV_STAT_TX_BROADCAST];
+ mac_stats->MulticastFramesReceivedOK =
+ lp->xxv_stat_base[XXV_STAT_RX_MULTICAST];
+ mac_stats->BroadcastFramesReceivedOK =
+ lp->xxv_stat_base[XXV_STAT_RX_BROADCAST];
+ mac_stats->InRangeLengthErrors =
+ lp->xxv_stat_base[XXV_STAT_RX_INRANGEERR];
+ } while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
+}
+
+/**
+ * axienet_xxv_get_rmon_stats - Fill RMON statistics and histogram ranges
+ * @lp: Pointer to the axienet_local structure
+ * @rmon_stats: Output ethtool_rmon_stats structure to populate
+ * @ranges: Set to the RMON histogram range table
+ */
+static void axienet_xxv_get_rmon_stats(struct axienet_local *lp,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ unsigned int start;
+
+ do {
+ start = read_seqcount_begin(&lp->hw_stats_seqcount);
+ rmon_stats->undersize_pkts =
+ lp->xxv_stat_base[XXV_STAT_RX_UNDERSIZE];
+ rmon_stats->oversize_pkts =
+ lp->xxv_stat_base[XXV_STAT_RX_OVERSIZE];
+ rmon_stats->fragments =
+ lp->xxv_stat_base[XXV_STAT_RX_FRAGMENT];
+ rmon_stats->jabbers =
+ lp->xxv_stat_base[XXV_STAT_RX_JABBER];
+ } while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
+
+ /* XXV currently exposes only aggregate RMON counters, not per-bin
+ * histogram buckets. Keep ranges NULL until histogram bins are wired.
+ */
+ *ranges = NULL;
+}
+
+const struct axienet_config axienet_10g25g_config = {
+ .sw_padding = true,
+ .internal_pcs = true,
+ .regs_n = XXV_REGS_N,
+ .clk_init = axienet_10g25g_clk_init,
+ .setoptions = axienet_xxv_setoptions,
+ .probe_init = axienet_xxv_probe_init,
+ .gt_reset = axienet_xxv_gt_reset,
+ .mac_init = axienet_xxv_mac_init,
+ .get_regs = axienet_xxv_get_regs,
+ .phylink_set_caps = axienet_xxv_phylink_set_capabilities,
+ .pcs_ops = &axienet_xxv_pcs_ops,
+ .stats_update = axienet_xxv_stats_update,
+ .get_stats64 = axienet_xxv_get_stats64,
+ .get_ethtool_stats = axienet_xxv_get_ethtool_stats,
+ .get_strings = axienet_xxv_get_strings,
+ .get_sset_count = axienet_xxv_get_sset_count,
+ .get_pause_stats = axienet_xxv_get_pause_stats,
+ .get_eth_mac_stats = axienet_xxv_get_eth_mac_stats,
+ .get_rmon_stats = axienet_xxv_get_rmon_stats,
+};
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h
new file mode 100644
index 00000000000000..ebfa7d57a85915
--- /dev/null
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * XXV (10G/25G) support
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef XILINX_AXIENET_XXV_H
+#define XILINX_AXIENET_XXV_H
+
+#include <linux/bits.h>
+
+struct axienet_local;
+struct axienet_config;
+
+#define XXV_REGS_N 46
+
+/* XXV MAC Register Definitions */
+#define XXV_GT_RESET_OFFSET 0x00000000
+#define XXV_RESET_OFFSET 0x00000004
+#define XXV_MODE_OFFSET 0x00000008
+#define XXV_TC_OFFSET 0x0000000C
+#define XXV_RCW1_OFFSET 0x00000014
+#define XXV_JUM_OFFSET 0x00000018
+#define XXV_VL_LENGTH_OFFSET 0x0000001C
+#define XXV_TICKREG_OFFSET 0x00000020
+#define XXV_CONFIG_REVISION 0x00000024
+#define XXV_CONFIG_1588_OFFSET 0x00000038
+#define XXV_CONFIG_TX_FLOW_CTRL1_OFFSET 0x00000040
+#define XXV_CONFIG_RX_FLOW_CTRL1_OFFSET 0x00000094
+#define XXV_CONFIG_RX_FLOW_CTRL2_OFFSET 0x00000098
+#define XXV_CONFIG_RSFEC_OFFSET 0x000000D0
+#define XXV_CONFIG_FEC_OFFSET 0x000000D4
+#define XXV_AN_CTL1_OFFSET 0x000000E0
+#define XXV_AN_CTL2_OFFSET 0x000000E4
+#define XXV_AN_ABILITY_OFFSET 0x000000F8
+#define XXV_LT_CTL1_OFFSET 0x00000100
+#define XXV_SWITCH_CORE_SPEED_OFFSET 0x00000138
+#define XXV_CONFIG_1588_32BIT_OFFSET 0x0000013C
+#define XXV_TX_CONFIG_1588_OFFSET 0x00000140
+#define XXV_RX_CONFIG_1588_OFFSET 0x00000144
+#define XXV_GTWIZ_CTRL_OFFSET 0x00000154
+#define XXV_STATRX_STATUS0_OFFSET 0x00000400
+#define XXV_RX_STATUS_REG1 0x00000404
+#define XXV_STATRX_STATUS2_OFFSET 0x00000408
+#define XXV_STATRX_BLKLCK_OFFSET 0x0000040C
+#define XXV_STAT_RX_RSFEC_STATUS_OFFSET 0x0000043C
+#define XXV_STAT_RX_FEC_STATUS_OFFSET 0x00000448
+#define XXV_STAT_TX_RSFEC_STATUS_OFFSET 0x0000044C
+#define XXV_STAT_TX_FLOW_CTRL1_OFFSET 0x00000450
+#define XXV_STAT_RX_FLOW_CTRL1_OFFSET 0x00000454
+#define XXV_STAT_AN_STS_OFFSET 0x00000458
+#define XXV_STAT_AN_LP_STATUS_OFFSET 0x0000045C
+#define XXV_STAT_AN_LINK_CTL_OFFSET 0x00000460
+#define XXV_STAT_LT_STATUS1_OFFSET 0x00000464
+#define XXV_STAT_LT_STATUS2_OFFSET 0x00000468
+#define XXV_STAT_LT_STATUS3_OFFSET 0x0000046C
+#define XXV_STAT_LT_STATUS4_OFFSET 0x00000470
+#define XXV_STAT_LT_COEFF0_OFFSET 0x00000474
+#define XXV_STAT_RX_VALID_CTRL_CODE_OFFSET 0x00000494
+#define XXV_STAT_CORE_SPEED_OFFSET 0x00000498
+#define XXV_STAT_TSN_OFFSET 0x0000049C
+#define XXV_STAT_GTWIZ_OFFSET 0x000004A0
+#define XXV_STAT_AN_LINK_CTL2_OFFSET 0x000009F0
+
+/* XXV statistics counter registers (PG210). Each counter is a pair of 32-bit
+ * registers; the MSB register is XXV_STAT_MSB_OFFSET bytes above the LSB.
+ */
+#define XXV_STAT_MSB_OFFSET 4
+#define XXV_STAT_TX_FRAME_ERROR_OFFSET 0x000006A0
+#define XXV_STAT_TX_TOTAL_PACKETS_OFFSET 0x00000700
+#define XXV_STAT_TX_TOTAL_GOOD_PACKETS_OFFSET 0x00000708
+#define XXV_STAT_TX_TOTAL_BYTES_OFFSET 0x00000710
+#define XXV_STAT_TX_TOTAL_GOOD_BYTES_OFFSET 0x00000718
+#define XXV_STAT_TX_BAD_FCS_OFFSET 0x000007B8
+#define XXV_STAT_TX_MULTICAST_OFFSET 0x000007D8
+#define XXV_STAT_TX_BROADCAST_OFFSET 0x000007E0
+#define XXV_STAT_TX_PAUSE_OFFSET 0x000007F0
+#define XXV_STAT_RX_TOTAL_PACKETS_OFFSET 0x00000808
+#define XXV_STAT_RX_TOTAL_GOOD_PACKETS_OFFSET 0x00000810
+#define XXV_STAT_RX_TOTAL_BYTES_OFFSET 0x00000818
+#define XXV_STAT_RX_TOTAL_GOOD_BYTES_OFFSET 0x00000820
+#define XXV_STAT_RX_UNDERSIZE_OFFSET 0x00000898
+#define XXV_STAT_RX_FRAGMENT_OFFSET 0x000008A0
+#define XXV_STAT_RX_OVERSIZE_OFFSET 0x000008A8
+#define XXV_STAT_RX_JABBER_OFFSET 0x000008B8
+#define XXV_STAT_RX_BAD_FCS_OFFSET 0x000008C0
+#define XXV_STAT_RX_MULTICAST_OFFSET 0x000008E0
+#define XXV_STAT_RX_BROADCAST_OFFSET 0x000008E8
+#define XXV_STAT_RX_PAUSE_OFFSET 0x000008F8
+#define XXV_STAT_RX_INRANGEERR_OFFSET 0x00000908
+
+/* XXV MAC Register Mask Definitions */
+#define XXV_GT_RESET_MASK BIT(0)
+#define XXV_TC_TX_MASK BIT(0)
+#define XXV_RCW1_RX_MASK BIT(0)
+#define XXV_RCW1_FCS_MASK BIT(1)
+#define XXV_TC_FCS_MASK BIT(1)
+#define XXV_RX_BLKLCK_MASK BIT(0)
+#define XXV_TICKREG_STATEN_MASK BIT(0)
+#define XXV_GTWIZ_RESET_DONE (BIT(0) | BIT(1))
+#define XXV_MAJ_MASK GENMASK(7, 0)
+#define XXV_MIN_MASK GENMASK(15, 8)
+/* IP v3.2+ exposes GT wizard status before other register access (PG210). */
+#define XXV_IP_VER_GTWIZ_MAJ_MIN 3
+#define XXV_IP_VER_GTWIZ_MIN_MIN 2
+#define XXV_AN_COMPLETE_MASK BIT(2)
+#define XXV_STAT_CORE_SPEED_RTSW_MASK BIT(1)
+#define XXV_STAT_CORE_SPEED_10G_MASK BIT(0)
+#define XXV_RX_STATUS_MASK BIT(0)
+
+/* XXV (10G/25G) MAC statistics counters, used to index xxv_stat_base[]. */
+enum xxv_stat {
+ XXV_STAT_RX_TOTAL_PACKETS = 0,
+ XXV_STAT_RX_TOTAL_GOOD_PACKETS,
+ XXV_STAT_RX_TOTAL_BYTES,
+ XXV_STAT_RX_TOTAL_GOOD_BYTES,
+ XXV_STAT_RX_BAD_FCS,
+ XXV_STAT_RX_INRANGEERR,
+ XXV_STAT_RX_MULTICAST,
+ XXV_STAT_RX_BROADCAST,
+ XXV_STAT_RX_UNDERSIZE,
+ XXV_STAT_RX_FRAGMENT,
+ XXV_STAT_RX_JABBER,
+ XXV_STAT_RX_OVERSIZE,
+ XXV_STAT_RX_PAUSE,
+ XXV_STAT_TX_TOTAL_PACKETS,
+ XXV_STAT_TX_TOTAL_GOOD_PACKETS,
+ XXV_STAT_TX_TOTAL_BYTES,
+ XXV_STAT_TX_TOTAL_GOOD_BYTES,
+ XXV_STAT_TX_BAD_FCS,
+ XXV_STAT_TX_FRAME_ERROR,
+ XXV_STAT_TX_MULTICAST,
+ XXV_STAT_TX_BROADCAST,
+ XXV_STAT_TX_PAUSE,
+ XXV_STAT_COUNT,
+};
+
+extern const struct axienet_config axienet_10g25g_config;
+
+#endif /* XILINX_AXIENET_XXV_H */
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 998ba3f261dac7..0289ac4c6e48ef 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -502,6 +502,22 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
*/
int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
struct clk_bulk_data *clks);
+/**
+ * devm_clk_bulk_get_enable - Get and enable bulk clocks (managed)
+ * @dev: device for clock "consumer"
+ * @num_clks: the number of clk_bulk_data
+ * @clks: pointer to the clk_bulk_data table of consumer
+ *
+ * Behaves the same as devm_clk_bulk_get() but also prepares and enables the
+ * clocks in one operation with management. The clks will automatically be
+ * disabled, unprepared and freed when the device is unbound.
+ *
+ * Return: 0 if all clocks specified in clk_bulk_data table are obtained and
+ * enabled successfully. Otherwise returns valid IS_ERR() condition containing
+ * errno.
+ */
+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks);
/**
* devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed)
* @dev: device for clock "consumer"
@@ -1052,6 +1068,13 @@ static inline int __must_check devm_clk_bulk_get_optional(struct device *dev,
return 0;
}
+static inline int __must_check devm_clk_bulk_get_enable(struct device *dev,
+ int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return 0;
+}
+
static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev,
int num_clks,
struct clk_bulk_data *clks)
|
| 3/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 32713 output: 44 thoughts: 442 Thoughts: **Analyzing the Xilinx AXI Ethernet Driver Patch** Okay, so I'm looking at this patch series. It seems to be touching the Xilinx AXI Ethernet driver, specifically in `drivers/net/ethernet/xilinx/xilinx_axienet_main.c` and introducing support for the XXV (10G/25G) Ethernet Subsystem with `xilinx_axienet_xxv.c`. It also mentions `devm_clk_bulk_get_enable` for the clock API, which is something I'll want to review in more detail, but for now, my focus is the driver itself. First, I need to understand the implications for standard environments like QEMU. The AXI Ethernet driver is usually found in Xilinx FPGAs and SoCs – Zynq and MicroBlaze systems, right? So, is the existing AXI Ethernet IP core *actually* emulated within QEMU? I know QEMU has some Xilinx Zynq and MicroBlaze support. Let me check the QEMU source... ah, yes, `hw/net/xilinx_axienet.c`. So it *is* there, which is good. But, the patch also mentions `xlnx,xxv-ethernet-1.0`. I'm guessing XXV Ethernet emulation in QEMU isn't standard, and therefore not yet present. However, and this is important, the patch *also* refactors the existing AXI Ethernet driver for the *current* 1G MAC driver using a config struct (`axienet_config`) and function pointers for MAC-specific operations. This is a significant change, since it impacts the driver already emulated in QEMU! And now I need to determine if this refactor is problematic, or just adds a few quirks to get past. Now, I need to confirm if `xilinx_axienet` is enabled by default in standard kernel configurations or if it can be enabled. After quickly looking, I see the driver is, in fact, `CONFIG_XILINX_AXI_EMAC`. Time to check the Kconfig for `XILINX_AXI_EMAC` to see where it sits. |
| 4/2 | 2026/07/26 00:02 | tool | grepper |
0mArgs:{
"Expression": "config XILINX_AXI_EMAC",
"PathPrefix": "drivers/net/ethernet/xilinx/Kconfig"
}Results: {
"Output": "drivers/net/ethernet/xilinx/Kconfig=19=config XILINX_EMACLITE\n--\ndrivers/net/ethernet/xilinx/Kconfig-25-\ndrivers/net/ethernet/xilinx/Kconfig:26:config XILINX_AXI_EMAC\ndrivers/net/ethernet/xilinx/Kconfig-27-\ttristate \"Xilinx 10/100/1000 AXI Ethernet support\"\n"
} |
| 5/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 33818 output: 44 thoughts: 19 Thoughts: Here's my thought process, breaking down the dependencies of `XILINX_AXI_EMAC`: **Deconstructing `XILINX_AXI_EMAC` Dependencies** Okay, so I'm thinking about `XILINX_AXI_EMAC`. As an expert, I know this is a pretty crucial IP, likely representing the Xilinx AXI Ethernet MAC. My immediate focus is, naturally, the dependencies. What other blocks or configurations is this IP inherently reliant upon? First, I'm mentally parsing the obvious ones. A MAC, at its core, is going to need a physical interface – so I'm expecting something like an Ethernet PHY, either directly integrated or externally connected. I'm already mentally searching for associated PHY interfaces in the design, perhaps a GMII, RGMII, or SGMII. My experience suggests that the specifics of that PHY interface will drastically influence the configuration of the `XILINX_AXI_EMAC` itself. Next, the AXI interface is the giveaway of the IP. That tells me this is going to be a bridge between Ethernet (at layer 2) and some sort of AXI-based interconnect on the FPGA. This means I'm going to have to consider AXI-specific dependencies. Things like AXI clocking, AXI bus widths (data, address, etc.), and burst lengths – I'm essentially going to be concerned with optimal throughput on the AXI bus. The IP will be built to the AXI specification, so how this connects to the rest of the system is the crux. I'm also anticipating that clocking is going to be important. High-speed Ethernet requires very precise clocks. I'm going to have to think about clock sources, clock dividers, and any clock domain crossings between the PHY, the MAC, and the AXI bus. Jitter is the enemy here; I'll be keeping an eye out for potential clocking issues. Finally, I'm going to think about what the IP does, which I already know is Ethernet MAC, so this will likely require DMA (Direct Memory Access) capability for moving packets in and out of memory. So, I'll be looking for memory interface controllers. Memory access will also play a role in timing requirements. This has potential impacts on the design, considering these IPs are often the bottlenecks. |
| 6/2 | 2026/07/26 00:02 | tool | grepper |
0mArgs:{
"Expression": "config XILINX_AXI_EMAC",
"PathPrefix": "drivers/net/ethernet/xilinx/Kconfig"
}Results: {
"Output": "drivers/net/ethernet/xilinx/Kconfig=19=config XILINX_EMACLITE\n--\ndrivers/net/ethernet/xilinx/Kconfig-25-\ndrivers/net/ethernet/xilinx/Kconfig:26:config XILINX_AXI_EMAC\ndrivers/net/ethernet/xilinx/Kconfig-27-\ttristate \"Xilinx 10/100/1000 AXI Ethernet support\"\n"
} |
| 7/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34512 output: 40 thoughts: 11 Thoughts: Here's my attempt at summarizing the thought process in the first person, assuming the user is an expert: **Kconfig Inspection Time** Right, time to dive into the Kconfig file. I need to get a clear picture of how this new feature/module/change is configured, and that means understanding the dependency structure. I'll need to look for the relevant symbols, see what their default values are, and trace back any dependencies on other configurations or features. I'll be looking for any unusual constraints or relationships that might affect how users interact with this. Then, I'll identify the associated menu entries and the help text – that's crucial for understanding the rationale behind the configuration options. My goal is to quickly build a mental map of the configuration landscape and pinpoint any potential gotchas or edge cases that need attention. |
| 8/2 | 2026/07/26 00:02 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/xilinx/Kconfig",
"FirstLine": 26,
"LineCount": 20
}Results: {
"Contents": " 26:\tconfig XILINX_AXI_EMAC\n 27:\t\ttristate \"Xilinx 10/100/1000 AXI Ethernet support\"\n 28:\t\tdepends on HAS_IOMEM\n 29:\t\tdepends on XILINX_DMA\n 30:\t\tselect PHYLINK\n 31:\t\tselect DIMLIB\n 32:\t\thelp\n 33:\t\t This driver supports the 10/100/1000 Ethernet from Xilinx for the\n 34:\t\t AXI bus interface used in Xilinx Virtex FPGAs and Soc's.\n 35:\t\n 36:\tconfig XILINX_LL_TEMAC\n 37:\t\ttristate \"Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver\"\n 38:\t\tdepends on HAS_IOMEM\n 39:\t\tselect PHYLIB\n 40:\t\thelp\n 41:\t\t This driver supports the Xilinx 10/100/1000 LocalLink TEMAC\n 42:\t\t core used in Xilinx Spartan and Virtex FPGAs\n 43:\t\n 44:\tendif # NET_VENDOR_XILINX\n"
} |
| 9/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35054 output: 34 thoughts: 32 Thoughts: Okay, here's my interpretation of those thoughts, summarized from my perspective as an expert in the field: **Assessing the DMA Dependency** Right, so we're looking at a potential dependency here. My initial thought is that the behaviour of the system clearly hinges on the configuration of `HAS_IOMEM` and `XILINX_DMA`. The key question right now is how `XILINX_DMA` is set. Understanding its state is critical to determine the path the system will take. Let me prioritize that check for the state of `XILINX_DMA`. |
| 10/2 | 2026/07/26 00:02 | tool | grepper |
0mArgs:{
"Expression": "config XILINX_DMA",
"PathPrefix": "drivers/dma/Kconfig"
}Results: {
"Output": "drivers/dma/Kconfig=674=config XGENE_DMA\n--\ndrivers/dma/Kconfig-682-\ndrivers/dma/Kconfig:683:config XILINX_DMA\ndrivers/dma/Kconfig-684-\ttristate \"Xilinx AXI DMAS Engine\"\n"
} |
| 11/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35339 output: 35 thoughts: 22 Thoughts: Okay, let's dive into this. Here's my take on examining the `drivers/dma/Kconfig` file, specifically the section related to `XILINX_DMA`: **Analyzing the Xilinx DMA Kconfig** Alright, time to get a good look at how the Xilinx DMA driver is configured within the kernel build system. First, I need to open up `drivers/dma/Kconfig` – should be straightforward enough. I'm expecting to find the standard Kconfig format here, defining the options, dependencies, and default values for the Xilinx DMA driver. I'll be looking for things like: * **The main `XILINX_DMA` option itself**: This will be the master switch for enabling or disabling the entire driver. I'll need to understand if it's tristate (y/m/n) or binary (y/n). * **Any sub-options**: Are there separate options for different Xilinx DMA controllers, like AXI DMA or others? This is where the configurability starts to shine. I'll look for specific controller types or feature selections. * **Dependencies**: What other kernel features or hardware configurations need to be enabled before `XILINX_DMA` can be selected? This is crucial for understanding the driver's prerequisites and potential conflicts. Likely, it would depend on the system using a Xilinx SoC. * **Default settings**: What is the default state of `XILINX_DMA`? Is it enabled by default, or is it disabled? Knowing the default helps me anticipate whether I need to explicitly enable or disable it, especially when configuring a new kernel build. * **Help text**: The help text within the Kconfig file should give me a clear explanation of what this driver does, the hardware it supports, and any important caveats. This is key to properly understanding the function and the options. Once I've parsed those aspects of the file, I'll have a solid understanding of how the Xilinx DMA driver is integrated into the build process, its level of configurability, and its dependencies. This information will be vital when debugging kernel builds, enabling the Xilinx DMA controller in my own projects, or contributing any modifications to this part of the kernel source. I'm curious to see what complexities they've accounted for. |
| 12/2 | 2026/07/26 00:02 | tool | read-file |
0mArgs:{
"File": "drivers/dma/Kconfig",
"FirstLine": 683,
"LineCount": 10
}Results: {
"Contents": " 683:\tconfig XILINX_DMA\n 684:\t\ttristate \"Xilinx AXI DMAS Engine\"\n 685:\t\tdepends on HAS_IOMEM\n 686:\t\tselect DMA_ENGINE\n 687:\t\thelp\n 688:\t\t Enable support for Xilinx AXI VDMA Soft IP.\n 689:\t\n 690:\t\t AXI VDMA engine provides high-bandwidth direct memory access\n 691:\t\t between memory and AXI4-Stream video type target\n 692:\t\t peripherals including peripherals which support AXI4-\n"
} |
| 13/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36064 output: 40 thoughts: 390 Thoughts: **Analyzing the Impact of this Patch** Okay, so this patch introduces some changes. It looks like `XILINX_DMA` depends on `HAS_IOMEM`, which is something to keep in mind for build configuration. The real meat of it is that this patch modifies `drivers/net/ethernet/xilinx/xilinx_axienet_main.c`, right at the core of `XILINX_AXI_EMAC`. This means a significant refactoring of the driver's initialization, option setting, and statistical handling. The interesting part is that `xilinx_axienet` *is* emulated in QEMU, specifically in `hw/net/xilinx_axienet.c`. That makes it reachable and, more importantly, *fuzzable*. My thoughts now revolve around how Syzkaller can interact with this. QEMU's `xilinx_axienet` is a platform device. Can Syzkaller reach it directly? It can fuzz platform devices, but it needs to know about them. Either through device tree instantiation or if the board itself instantiates it. Syzkaller doesn't typically just instantiate random platform devices, unless it's part of the fuzzing board configuration. That is, unless it knows about devices such as the `vexpress` or `virt` platforms. We *could* use a `syz_devres` pseudo-syscall, or we can just consider it reachable if the driver is loaded and the device is probed. And of course, there's always the possibility of injecting platform devices using `syz_genetlink` or something similar, or probing it via device tree. But is it even *worth* the fuzzing effort? The patch refactors the driver, adding a new MAC type. The refactoring does touch the 1G MAC which is emulated, so it might be. Let's dig deeper. The patch also modifies `drivers/clk/clk-devres.c`, adding `devm_clk_bulk_get_enable`. *That's* a core kernel API change. This warrants a closer look at `devm_clk_bulk_get_enable` and how it is being used. |
| 14/2 | 2026/07/26 00:02 | tool | grepper |
0mArgs:{
"Expression": "devm_clk_bulk_get_enable",
"PathPrefix": "drivers/clk/clk-devres.c"
}Results: {
"Output": "drivers/clk/clk-devres.c=182=static void devm_clk_bulk_release_enable(struct device *dev, void *res)\n--\ndrivers/clk/clk-devres.c-189-\ndrivers/clk/clk-devres.c:190:static int __devm_clk_bulk_get_enable(struct device *dev, int num_clks,\ndrivers/clk/clk-devres.c-191-\t\t\t\t struct clk_bulk_data *clks, bool optional)\n--\ndrivers/clk/clk-devres.c-224-\ndrivers/clk/clk-devres.c:225:int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,\ndrivers/clk/clk-devres.c-226-\t\t\t\t\t struct clk_bulk_data *clks)\ndrivers/clk/clk-devres.c-227-{\ndrivers/clk/clk-devres.c:228:\treturn __devm_clk_bulk_get_enable(dev, num_clks, clks, false);\ndrivers/clk/clk-devres.c-229-}\ndrivers/clk/clk-devres.c:230:EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);\ndrivers/clk/clk-devres.c-231-\ndrivers/clk/clk-devres.c=232=int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,\n--\ndrivers/clk/clk-devres.c-234-{\ndrivers/clk/clk-devres.c:235:\treturn __devm_clk_bulk_get_enable(dev, num_clks, clks, true);\ndrivers/clk/clk-devres.c-236-}\n"
} |
| 15/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 37449 output: 41 thoughts: 596 Thoughts: **WorthFuzzing Decision for This Patch** Okay, let's break this down. This patch introduces `devm_clk_bulk_get_enable`, which is a new API call, and it modifies the Xilinx AXI Ethernet driver. My immediate question is: is this new API used anywhere *else*? Nope, it's exclusively within the changes here. The core of the change seems to be around the Xilinx AXI Ethernet driver, specifically. My next line of thought is whether or not this is even *reachable* by syzkaller in its typical virtualized environments. I know QEMU supports the `xilinx_axienet` device in certain machine types like `petalogic-s3adsp1800` and `xilinx-zynq-a9`. However, my understanding is that syzkaller generally leans on `x86_64` with `q35` or `pc` or `arm64` with `virt` machines. And, critically, the Xilinx AXI Ethernet isn't present *by default* on those configurations. Now, syzkaller *can* load modules, but the question is, can we instantiate the device using those means, maybe with device tree overlays or something? It's a platform device, not a PCI device. The code mentions that. So, can it be instantiated in a *standard* QEMU `virt` machine? Probably not, unless we use a specific machine type or a device tree overlay. And my gut feeling is that syzkaller *isn't* currently using overlays to instantiate arbitrary platform devices on those `x86_64` or `arm64` `virt` machines. The instructions say that if it's impossible to reach in virtualized environments, return `WorthFuzzing=false`. And the examples point to things like vendor-specific PCIe switch drivers, which require physical cards not emulated by QEMU. This seems to apply, unless my assumptions about syzkaller's machine configurations are incorrect. But wait! The patch *also* adds `devm_clk_bulk_get_enable` to `drivers/clk/clk-devres.c`. This *is* a core kernel API now, right? But again, it's only *used* by this new Xilinx driver in *this* patch. Hmm, does it make sense to fuzz the core API addition *itself*? Well, `devm_clk_bulk_get_enable` is just a wrapper around `__devm_clk_bulk_get_enable`, so I need to see if that underlying function was already there. I'm leaning towards `WorthFuzzing=false` at this point. |
| 16/2 | 2026/07/26 00:02 | tool | grepper |
0mArgs:{
"Expression": "__devm_clk_bulk_get_enable",
"PathPrefix": "drivers/clk/clk-devres.c"
}Results: {
"Output": "drivers/clk/clk-devres.c=182=static void devm_clk_bulk_release_enable(struct device *dev, void *res)\n--\ndrivers/clk/clk-devres.c-189-\ndrivers/clk/clk-devres.c:190:static int __devm_clk_bulk_get_enable(struct device *dev, int num_clks,\ndrivers/clk/clk-devres.c-191-\t\t\t\t struct clk_bulk_data *clks, bool optional)\n--\ndrivers/clk/clk-devres.c=225=int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,\n--\ndrivers/clk/clk-devres.c-227-{\ndrivers/clk/clk-devres.c:228:\treturn __devm_clk_bulk_get_enable(dev, num_clks, clks, false);\ndrivers/clk/clk-devres.c-229-}\n--\ndrivers/clk/clk-devres.c=232=int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,\n--\ndrivers/clk/clk-devres.c-234-{\ndrivers/clk/clk-devres.c:235:\treturn __devm_clk_bulk_get_enable(dev, num_clks, clks, true);\ndrivers/clk/clk-devres.c-236-}\n"
} |
| 17/2 | 2026/07/26 00:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 39066 output: 35 thoughts: 311 Thoughts: **Analyzing the `devm_clk_bulk_get_enable` Patch and Its Reach in Syzkaller** Okay, so this patch is adding `devm_clk_bulk_get_enable`, which, as I see it, is the non-optional version of `devm_clk_bulk_get_optional_enable`. So the core code change itself is actually quite small and likely straightforward. The real action seems to be in the Xilinx Ethernet driver code, specifically in `drivers/net/ethernet/xilinx/`. Now the question is, can syzkaller even *reach* `xilinx_axienet`? I know syzkaller primarily targets `x86_64`, `arm64`, and `riscv64` with virtual machines. It doesn't typically fuzz Xilinx Zynq boards out of the box. That means any platform devices not exposed via the device tree, ACPI, or discoverable buses like PCI or USB are generally inaccessible unless there's a specific injection mechanism. Wait, is there a way to inject platform devices into the fuzzing environment? I seem to recall a `syz_genetlink` call, but that's for netlink interactions. Does syzkaller offer something like `syz_platform_device_add`? No, that doesn't exist, which is a problem. Can `xilinx_axienet` even be instantiated through something like netlink? No, it's a platform driver, so that's not an option. Alright, let me quickly double-check: is `xilinx_axienet` a PCI driver? If it were, that would open up a whole new set of possibilities. But I don't think it is... |
| 18/2 | 2026/07/26 00:03 | tool | grepper |
0mError:no matches Args: {
"Expression": "pci_driver",
"PathPrefix": "drivers/net/ethernet/xilinx/"
}Results: {
"error": "no matches"
} |
| 19/2 | 2026/07/26 00:03 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 39808 output: 34 thoughts: 6 Thoughts: Okay, here's the summary, assuming I'm an expert in platform development: **Thinking Through Platform Driver Implementation** Right, so this is about a platform driver. Straight away, I'm already mentally running through the typical considerations: the platform bus, resource management, device registration and unregistration, probe and remove functions... all the usual suspects. I need to understand the specifics of the hardware abstraction layer being used, if any. Is it a standard platform driver framework, or something custom? What about interrupt handling? Power management callbacks? Error handling? And of course, I need to know the target platform – the specific SoC, the peripherals it uses, and how they’re configured. This initial thought just raises all the questions that I will want answered to start the process. |
| 20/2 | 2026/07/26 00:03 | tool | grepper |
0mArgs:{
"Expression": "platform_driver",
"PathPrefix": "drivers/net/ethernet/xilinx/"
}Results: {
"Output": "drivers/net/ethernet/xilinx/ll_temac_main.c=1648=MODULE_DEVICE_TABLE(of, temac_of_match);\ndrivers/net/ethernet/xilinx/ll_temac_main.c-1649-\ndrivers/net/ethernet/xilinx/ll_temac_main.c:1650:static struct platform_driver temac_driver = {\ndrivers/net/ethernet/xilinx/ll_temac_main.c-1651-\t.probe = temac_probe,\n--\ndrivers/net/ethernet/xilinx/ll_temac_main.c-1658-\ndrivers/net/ethernet/xilinx/ll_temac_main.c:1659:module_platform_driver(temac_driver);\ndrivers/net/ethernet/xilinx/ll_temac_main.c-1660-\n--\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c=3448=static DEFINE_SIMPLE_DEV_PM_OPS(axienet_pm_ops,\n--\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c-3450-\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c:3451:static struct platform_driver axienet_driver = {\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c-3452-\t.probe = axienet_probe,\n--\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c-3461-\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c:3462:module_platform_driver(axienet_driver);\ndrivers/net/ethernet/xilinx/xilinx_axienet_main.c-3463-\n--\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c=1253=MODULE_DEVICE_TABLE(of, xemaclite_of_match);\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c-1254-\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c:1255:static struct platform_driver xemaclite_of_driver = {\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c-1256-\t.driver = {\n--\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c-1263-\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c:1264:module_platform_driver(xemaclite_of_driver);\ndrivers/net/ethernet/xilinx/xilinx_emaclite.c-1265-\n"
} |
| 21/2 | 2026/07/26 00:03 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 40758 output: 170 thoughts: 699 Thoughts: **Unreachable Driver in Standard Fuzzing Environments** Okay, so I'm looking at this patch and immediately, my expert eye tells me this is about XXV support for the Xilinx AXI Ethernet driver. Since it's a platform driver, specifically designed for Xilinx SoCs, and not a bus-discoverable device like PCI or USB, the standard QEMU environments used by syzkaller—`q35` for x86_64, `virt` for arm64—aren't going to touch this thing unless there's a specific device tree entry. And syzkaller *doesn't* use those Xilinx-specific QEMU machines for fuzzing; it sticks to the more generic ones. So, that `axienet_probe` function? Never called in the fuzzing context. Unreachable code. The instructions are pretty clear on this: if the patch contains "code paths that are impossible to reach in virtualized environments like GCE or QEMU... even when utilizing software-emulated hardware", it's a `WorthFuzzing=false`. Sure, QEMU *could* emulate `xilinx_axienet` if we spun up a `petalogic-s3adsp1800` or `xilinx-zynq-a9` machine, but syzkaller doesn't use those. No, syzkaller is all about those standard, ubiquitous environments. Is there *any* other way this driver could be instantiated? Nope. This driver is dead in the water in this fuzzing setup. Okay, let's see if there are any other areas of reachability. The patch adds `devm_clk_bulk_get_enable` to `drivers/clk/clk-devres.c`. But it's just a 5-line wrapper function, essentially. Do I fuzz for this? No, it's trivial and not the point. The patch's thrust is clearly about the Xilinx AXI Ethernet driver. Let's review the instructions again: "Return WorthFuzzing=false if the patch only contains... Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware". That's my answer. Therefore, I'm returning `WorthFuzzing=false`. My reasoning is that the patch modifies a platform-specific Ethernet driver (Xilinx AXI Ethernet). It's unreachable in syzkaller's standard virtualized environments (x86_64 `q35`, arm64 `virt`) because it requires a specific device tree that isn't present. And the addition of `devm_clk_bulk_get_enable` is just a trivial wrapper. |
| 22/2 | 2026/07/26 00:03 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch primarily modifies the Xilinx AXI Ethernet driver (a platform driver for Xilinx FPGAs/SoCs) to add support for the XXV (10G/25G) MAC. Platform devices require specific device tree nodes to be probed and are not discoverable like PCI/USB devices. Since standard fuzzing environments (e.g., x86_64 q35, arm64 virt) do not instantiate these Xilinx-specific platform devices, the modified driver code is unreachable. The only core change is the addition of `devm_clk_bulk_get_enable`, which is a trivial 5-line wrapper.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch primarily modifies the Xilinx AXI Ethernet driver (a platform driver for Xilinx FPGAs/SoCs) to add support for the XXV (10G/25G) MAC. Platform devices require specific device tree nodes to be probed and are not discoverable like PCI/USB devices. Since standard fuzzing environments (e.g., x86_64 q35, arm64 virt) do not instantiate these Xilinx-specific platform devices, the modified driver code is unreachable. The only core change is the addition of `devm_clk_bulk_get_enable`, which is a trivial 5-line wrapper.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|