* [PATCH net-next 1/7] clk: Add devm_clk_bulk_get_enable()
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
2026-07-23 15:04 ` Brian Masney
2026-07-23 12:38 ` [PATCH net-next 2/7] net: xilinx: axienet: Introduce axienet_config for MAC-specific ops Suraj Gupta
` (5 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
devm_clk_bulk_get_optional_enable() gets, prepares and enables a set of
clocks with device-managed cleanup, but treats every clock as optional:
a missing clock is silently returned as NULL instead of failing.
Consumers that need a fixed set of mandatory clocks enabled for the
lifetime of the device currently have to open-code devm_clk_bulk_get()
followed by clk_bulk_prepare_enable(), which loses the managed disable on
unbind, or fall back to per-clock devm_clk_get_enabled() calls.
Add devm_clk_bulk_get_enable() as the non-optional counterpart. The
underlying __devm_clk_bulk_get_enable() helper already supports the
required (optional = false) path, so only export a thin wrapper for it.
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
.../driver-api/driver-model/devres.rst | 1 +
drivers/clk/clk-devres.c | 7 ++++++
include/linux/clk.h | 23 +++++++++++++++++++
3 files changed, 31 insertions(+)
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index 017fb155a5bc..5067500ded5c 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 994d5bc5168b..49d4782991eb 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/include/linux/clk.h b/include/linux/clk.h
index 998ba3f261da..0289ac4c6e48 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)
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH net-next 1/7] clk: Add devm_clk_bulk_get_enable()
2026-07-23 12:38 ` [PATCH net-next 1/7] clk: Add devm_clk_bulk_get_enable() Suraj Gupta
@ 2026-07-23 15:04 ` Brian Masney
0 siblings, 0 replies; 9+ messages in thread
From: Brian Masney @ 2026-07-23 15:04 UTC (permalink / raw)
To: Suraj Gupta
Cc: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Russell King, Shyam Pandey,
netdev, devicetree, linux-arm-kernel, linux-clk, linux-doc,
driver-core, linux-kernel, harini.katakam
On Thu, Jul 23, 2026 at 06:08:32PM +0530, Suraj Gupta wrote:
> devm_clk_bulk_get_optional_enable() gets, prepares and enables a set of
> clocks with device-managed cleanup, but treats every clock as optional:
> a missing clock is silently returned as NULL instead of failing.
>
> Consumers that need a fixed set of mandatory clocks enabled for the
> lifetime of the device currently have to open-code devm_clk_bulk_get()
> followed by clk_bulk_prepare_enable(), which loses the managed disable on
> unbind, or fall back to per-clock devm_clk_get_enabled() calls.
>
> Add devm_clk_bulk_get_enable() as the non-optional counterpart. The
> underlying __devm_clk_bulk_get_enable() helper already supports the
> required (optional = false) path, so only export a thin wrapper for it.
>
> Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-next 2/7] net: xilinx: axienet: Introduce axienet_config for MAC-specific ops
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 1/7] clk: Add devm_clk_bulk_get_enable() Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 3/7] dt-bindings: net: xlnx,axi-ethernet: Add 10G/25G (XXV) ethernet Suraj Gupta
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
Introduce an axienet_config structure to abstract MAC-type-specific
operations, preparing the driver for supporting additional MAC types
beyond the existing 1G Ethernet.
Add axienet_config with capability flags (mdio, mac_irq, legacy_dma,
uc_filter, mc_filter, vlan, jumbo, dma_tx_csum, sw_padding, internal_pcs),
the register-dump count and callbacks (clk_init, setoptions, probe_init,
gt_reset, mac_init, mac_link_up, get_regs, phylink_set_caps, pcs_ops,
stats_update), and populate it from the OF match table. Convert the
common code to consult these capabilities and callbacks instead of
open-coding 1G behavior, so a new MAC type can be added without adding
MAC-specific conditionals to the shared paths.
No functional change intended for the existing 1G path.
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet.h | 52 +++
.../net/ethernet/xilinx/xilinx_axienet_main.c | 391 ++++++++++++------
2 files changed, 319 insertions(+), 124 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index fcd3aaef27fc..40f03c9eb382 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -545,6 +545,7 @@ 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.
+ * @axienet_config: MAC-type specific configuration and operations.
*/
struct axienet_local {
struct net_device *ndev;
@@ -626,6 +627,57 @@ struct axienet_local {
int tx_ring_tail;
int rx_ring_head;
int rx_ring_tail;
+ 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
+ */
+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);
};
/**
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 67d1b8e91d68..5c59423bd778 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>
@@ -64,16 +65,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 */
@@ -418,6 +409,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]) |
@@ -467,6 +461,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)
@@ -575,14 +572,25 @@ 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 */
schedule_delayed_work(&lp->stats_work, 13 * HZ);
@@ -693,6 +701,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
@@ -708,19 +742,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;
}
@@ -737,26 +775,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);
@@ -914,6 +944,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) {
@@ -938,19 +975,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,
@@ -1738,8 +1777,8 @@ static int axienet_stop(struct net_device *ndev)
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);
@@ -1765,7 +1804,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);
@@ -1934,30 +1974,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);
@@ -1998,6 +2026,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,
@@ -2634,13 +2687,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;
@@ -2677,6 +2726,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,
@@ -2694,7 +2756,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);
@@ -2707,8 +2768,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);
@@ -2753,29 +2814,114 @@ 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);
+ 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,
+};
+
+/* 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 },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, axienet_of_match);
+
/**
* axienet_probe - Axi Ethernet probe function.
* @pdev: Pointer to platform device structure.
@@ -2826,27 +2972,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);
@@ -2857,9 +2989,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) {
@@ -2933,7 +3062,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);
@@ -3013,7 +3152,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;
}
@@ -3066,10 +3208,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) {
@@ -3093,23 +3237,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,
@@ -3152,7 +3294,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)
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next 3/7] dt-bindings: net: xlnx,axi-ethernet: Add 10G/25G (XXV) ethernet
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 1/7] clk: Add devm_clk_bulk_get_enable() Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 2/7] net: xilinx: axienet: Introduce axienet_config for MAC-specific ops Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 4/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
The XXV Ethernet IP integrates a 10G/25G Ethernet MAC with an in-core
PCS/PMA driving a high-speed serial transceiver. Extend the existing
xlnx,axi-ethernet binding to describe it.
Add the "xlnx,xxv-ethernet-1.0" compatible and make the resource
requirements conditional based on the XXV compatible string:
- "dmas", "dma-names", and "phy-mode" are required.
- Interrupt properties are not required as it does not have a dedicated
Ethernet core interrupt.
- "phy-handle" is not required as it has internal PCS and PMA.
- Add the 10gbase-r and 25gbase-r phy-mode values used by XXV.
Annotate the existing compatibles, generalise the title to cover both
variants, and add an example node for XXV.
Define properties at top level per binding style and use if/then to
constrain requirements and phy-mode per compatible. Forbid 1G-only and
unused ethernet-controller properties on XXV nodes.
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
.../bindings/net/xlnx,axi-ethernet.yaml | 144 ++++++++++++++----
1 file changed, 117 insertions(+), 27 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
index fb02e579463c..23b1a27c04e5 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>;
+ };
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next 4/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
` (2 preceding siblings ...)
2026-07-23 12:38 ` [PATCH net-next 3/7] dt-bindings: net: xlnx,axi-ethernet: Add 10G/25G (XXV) ethernet Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 5/7] net: xilinx: axienet: Make axienet_rmon_ranges non-static for reuse Suraj Gupta
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
The AXI Ethernet driver currently supports only the AXI 1G Ethernet IP.
Add support for the Xilinx XXV Ethernet IP[1], which implements a 10G/25G
Ethernet MAC with PCS/PMA driving a high-speed serial transceiver, as
specified by the 25G Ethernet Consortium.
Add the XXV-specific logic in new xilinx_axienet_xxv.c/.h files and
describe the MAC through an axienet_10g25g_config that provides the
capability flags and callbacks (GT reset, link-ready polling, options
programming, phylink caps, PCS ops, register dump and probe-time init).
No MAC-specific conditionals are added to the shared paths.
Also propagate the axienet_device_reset() failure in axienet_open(),
which was previously overwritten by phylink_of_phy_connect() before being
checked. This matters for XXV, whose mac_init() can fail on a GT
reset-done timeout.
[1]: https://docs.amd.com/r/en-US/pg210-25g-ethernet
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/Makefile | 3 +-
drivers/net/ethernet/xilinx/xilinx_axienet.h | 9 +
.../net/ethernet/xilinx/xilinx_axienet_main.c | 17 +-
.../net/ethernet/xilinx/xilinx_axienet_xxv.c | 328 ++++++++++++++++++
.../net/ethernet/xilinx/xilinx_axienet_xxv.h | 86 +++++
5 files changed, 436 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
create mode 100644 drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h
diff --git a/drivers/net/ethernet/xilinx/Makefile b/drivers/net/ethernet/xilinx/Makefile
index 7d7dc1771423..db90e691fec5 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 40f03c9eb382..295a1b835165 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -17,6 +17,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 +547,7 @@ 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.
* @axienet_config: MAC-type specific configuration and operations.
*/
struct axienet_local {
@@ -627,6 +630,7 @@ 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;
};
@@ -680,6 +684,11 @@ struct axienet_config {
void (*stats_update)(struct axienet_local *lp);
};
+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.
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 5c59423bd778..5bffa5b9d0b4 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1705,6 +1705,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) {
@@ -2604,11 +2608,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)
@@ -2668,7 +2667,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;
@@ -2814,6 +2815,9 @@ static void axienet_dma_err_handler(struct work_struct *work)
axienet_dma_start(lp);
+ /* 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
@@ -2917,6 +2921,7 @@ 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 },
{},
};
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 000000000000..da3f6566a0c4
--- /dev/null
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
@@ -0,0 +1,328 @@
+// 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/iopoll.h>
+#include <linux/netdevice.h>
+#include <linux/phylink.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,
+ },
+ {}
+};
+
+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);
+}
+
+/**
+ * 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;
+}
+
+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,
+};
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 000000000000..15a323ee05b2
--- /dev/null
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h
@@ -0,0 +1,86 @@
+/* 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 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_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)
+
+extern const struct axienet_config axienet_10g25g_config;
+
+#endif /* XILINX_AXIENET_XXV_H */
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next 5/7] net: xilinx: axienet: Make axienet_rmon_ranges non-static for reuse
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
` (3 preceding siblings ...)
2026-07-23 12:38 ` [PATCH net-next 4/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 6/7] net: xilinx: axienet: Dispatch statistics through axienet_config ops Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 7/7] net: xilinx: axienet: Add statistics support for XXV ethernet Suraj Gupta
6 siblings, 0 replies; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
The RMON histogram range table axienet_rmon_ranges[] is MAC-agnostic.
Make it non-static and declare it in the shared xilinx_axienet.h so the
upcoming XXV RMON callback can reuse the same table instead of
duplicating it. Include <linux/ethtool.h> for the range element type.
No functional change intended.
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++++
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 295a1b835165..a1d15b4797ce 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>
@@ -802,4 +803,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 5bffa5b9d0b4..19fe2fd81f3a 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -2498,7 +2498,7 @@ 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[] = {
+const struct ethtool_rmon_hist_range axienet_rmon_ranges[] = {
{ 64, 64 },
{ 65, 127 },
{ 128, 255 },
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next 6/7] net: xilinx: axienet: Dispatch statistics through axienet_config ops
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
` (4 preceding siblings ...)
2026-07-23 12:38 ` [PATCH net-next 5/7] net: xilinx: axienet: Make axienet_rmon_ranges non-static for reuse Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
2026-07-23 12:38 ` [PATCH net-next 7/7] net: xilinx: axienet: Add statistics support for XXV ethernet Suraj Gupta
6 siblings, 0 replies; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
The ndo_get_stats64() and ethtool statistics callbacks read the 1G MAC
hardware counters directly. Supporting a second MAC type this way would
require an "if (mactype == ...)" dispatch branch in each of the eight
statistics callbacks.
Add statistics operation function pointers to struct axienet_config and
route get_stats64, get_ethtool_stats, get_strings, get_sset_count,
get_pause_stats, get_eth_mac_stats, get_eth_ctrl_stats and
get_rmon_stats through them. Factor the existing 1G counter reads into
axienet_1g_*() helpers and populate axienet_1g_config with them.
A NULL op means the MAC does not expose that statistics group, so a MAC
without control-frame counters simply leaves get_eth_ctrl_stats unset
instead of open-coding the special case in the callback.
No functional change intended.
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet.h | 23 +++
.../net/ethernet/xilinx/xilinx_axienet_main.c | 171 +++++++++++++-----
2 files changed, 146 insertions(+), 48 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index a1d15b4797ce..f286c428343f 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -658,6 +658,15 @@ struct axienet_local {
* @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;
@@ -683,6 +692,20 @@ struct axienet_config {
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)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 19fe2fd81f3a..198de353372a 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1874,29 +1874,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 =
@@ -1924,6 +1906,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,
@@ -2356,11 +2365,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 {
@@ -2377,6 +2383,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",
@@ -2389,12 +2406,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;
}
}
@@ -2405,24 +2436,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 =
@@ -2433,15 +2460,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 =
@@ -2478,15 +2513,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 =
@@ -2498,6 +2542,19 @@ axienet_ethtool_get_eth_ctrl_stats(struct net_device *dev,
} while (read_seqcount_retry(&lp->hw_stats_seqcount, start));
}
+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 },
@@ -2510,16 +2567,12 @@ 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 =
@@ -2563,6 +2616,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 |
@@ -2914,6 +2981,14 @@ static const struct axienet_config axienet_1g_config = {
.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 */
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next 7/7] net: xilinx: axienet: Add statistics support for XXV ethernet
2026-07-23 12:38 [PATCH net-next 0/7] net: xilinx: axienet: Add 10G/25G (XXV) ethernet support Suraj Gupta
` (5 preceding siblings ...)
2026-07-23 12:38 ` [PATCH net-next 6/7] net: xilinx: axienet: Dispatch statistics through axienet_config ops Suraj Gupta
@ 2026-07-23 12:38 ` Suraj Gupta
6 siblings, 0 replies; 9+ messages in thread
From: Suraj Gupta @ 2026-07-23 12:38 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
Rafael J . Wysocki, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
Michael Turquette, Stephen Boyd, Brian Masney, Russell King
Cc: Shyam Pandey, netdev, devicetree, linux-arm-kernel, linux-clk,
linux-doc, driver-core, linux-kernel, harini.katakam
The XXV ethernet exposes a dedicated statistics block whose counters are
clear-on-tick (PG210): writing TICK_REG latches the internal accumulators
into the readable registers and clears them, so each post-TICK read yields
the count for the interval since the previous TICK. Software accumulates
those intervals, so no last-counter delta (as used by the 1G MAC) is
needed.
Feed both ndo_get_stats64() and the ethtool statistics (-S, pause, MAC and
RMON) from this accumulator path through the axienet_config statistics ops.
MAC control statistics stay unsupported as the hardware exposes no matching
counters.
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet.h | 2 +
.../net/ethernet/xilinx/xilinx_axienet_main.c | 22 +-
.../net/ethernet/xilinx/xilinx_axienet_xxv.c | 266 ++++++++++++++++++
.../net/ethernet/xilinx/xilinx_axienet_xxv.h | 55 ++++
4 files changed, 343 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index f286c428343f..2ea086fc4dc3 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -549,6 +549,7 @@ struct skbuf_dma_descriptor {
* @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 {
@@ -603,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;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 198de353372a..e693f4a49f20 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -592,7 +592,11 @@ static void axienet_refresh_stats(struct work_struct *work)
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);
}
@@ -601,7 +605,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);
@@ -1777,6 +1790,11 @@ 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);
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
index da3f6566a0c4..ea4bf99fddfa 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.c
@@ -8,9 +8,11 @@
#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"
@@ -95,6 +97,69 @@ static struct axienet_option xxvenet_options[] = {
{}
};
+/* 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);
@@ -134,6 +199,7 @@ static void axienet_xxv_setoptions(struct net_device *ndev, u32 options)
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;
}
/**
@@ -313,6 +379,198 @@ static int axienet_10g25g_clk_init(struct axienet_local *lp)
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,
@@ -325,4 +583,12 @@ const struct axienet_config axienet_10g25g_config = {
.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
index 15a323ee05b2..ebfa7d57a859 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_xxv.h
@@ -63,6 +63,33 @@ struct axienet_config;
#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)
@@ -70,6 +97,7 @@ struct axienet_config;
#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)
@@ -81,6 +109,33 @@ struct axienet_config;
#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 */
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread