qualcommax: qca_edma: add an ethtool register dump

The state of the rings, of the interrupts that serve them and of the
global configuration is only readable by patching the driver. ethtool -d
pairs every value with the offset it came from, so it is read without a
table on the other side.

The misc status is left out, so that a dump cannot take an error away
from the handler.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Link: https://github.com/openwrt/openwrt/pull/25117
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
Julius Bairaktaris authored and Robert Marko committed 2026-09-11 12:09:51 +02:00
1 parent 99a1ce6551
commit afd07bdbdd
2 files changed
+76

No files matched your search

@@ -1169,10 +1169,83 @@ static void edma_get_ringparam(struct net_device *netdev,
ring->rx_pending = EDMA_RX_RING_SIZE;
}
/* The registers the driver drives, in the order it configures them: the
* global block, then each ring it owns and the interrupt that serves it. The
* dump pairs every value with the offset it came from, so it reads without a
* table on the other side. The misc status is left out, so that a dump cannot
* take an error away from the handler.
*/
static int edma_get_regs_len(struct net_device *netdev)
{
return EDMA_REGS_COUNT * 2 * sizeof(u32);
}
static void edma_get_regs(struct net_device *netdev,
struct ethtool_regs *regs, void *p)
{
struct edma_priv *priv = netdev_priv(netdev);
const struct edma_soc_data *soc = priv->soc;
const u32 off[EDMA_REGS_COUNT] = {
EDMA_REG_PORT_CTRL,
EDMA_REG_DMAR_CTRL,
EDMA_REG_AXIW_CTRL,
EDMA_REG_MISC_INT_MASK,
EDMA_REG_TXDESC_BA(soc->txdesc_ring),
EDMA_REG_TXDESC_PROD_IDX(soc->txdesc_ring),
EDMA_REG_TXDESC_CONS_IDX(soc->txdesc_ring),
EDMA_REG_TXDESC_RING_SIZE(soc->txdesc_ring),
EDMA_REG_TXDESC_CTRL(soc->txdesc_ring),
EDMA_REG_TXCMPL_BA(soc->txcmpl_base, soc->txcmpl_ring),
EDMA_REG_TXCMPL_PROD_IDX(soc->txcmpl_base, soc->txcmpl_ring),
EDMA_REG_TXCMPL_CONS_IDX(soc->txcmpl_base, soc->txcmpl_ring),
EDMA_REG_TXCMPL_RING_SIZE(soc->txcmpl_base, soc->txcmpl_ring),
EDMA_REG_TXCMPL_CTRL(soc->txcmpl_base, soc->txcmpl_ring),
EDMA_REG_TX_INT_STAT(soc->tx_int_base, soc->txcmpl_ring),
EDMA_REG_TX_INT_MASK(soc->tx_int_base, soc->txcmpl_ring),
EDMA_REG_TX_MOD_TIMER(soc->tx_int_base, soc->txcmpl_ring),
EDMA_REG_TX_INT_CTRL(soc->tx_int_base, soc->txcmpl_ring),
EDMA_REG_RXFILL_BA(soc->rxfill_ring),
EDMA_REG_RXFILL_PROD_IDX(soc->rxfill_ring),
EDMA_REG_RXFILL_CONS_IDX(soc->rxfill_ring),
EDMA_REG_RXFILL_RING_SIZE(soc->rxfill_ring),
EDMA_REG_RXFILL_RING_EN(soc->rxfill_ring),
EDMA_REG_RXFILL_INT_STAT(soc->rxfill_ring),
EDMA_REG_RXFILL_INT_MASK(soc->rxfill_ring),
EDMA_REG_RXDESC_BA(soc->rxdesc_ring),
EDMA_REG_RXDESC_PROD_IDX(soc->rxdesc_ring),
EDMA_REG_RXDESC_CONS_IDX(soc->rxdesc_ring),
EDMA_REG_RXDESC_RING_SIZE(soc->rxdesc_ring),
EDMA_REG_RXDESC_CTRL(soc->rxdesc_ring),
EDMA_REG_RXDESC_INT_STAT(soc->rxdesc_ring),
EDMA_REG_RXDESC_INT_MASK(soc->rxdesc_ring),
EDMA_REG_RX_MOD_TIMER(soc->rxdesc_ring),
EDMA_REG_RX_INT_CTRL(soc->rxdesc_ring),
};
u32 *out = p;
int i;
regs->version = 1;
for (i = 0; i < EDMA_REGS_COUNT; i++) {
u32 val;
regmap_read(priv->regmap, off[i], &val);
*out++ = off[i];
*out++ = val;
}
}
static const struct ethtool_ops edma_ethtool_ops = {
.get_drvinfo = edma_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = edma_get_ringparam,
.get_regs_len = edma_get_regs_len,
.get_regs = edma_get_regs,
};
static int edma_ndo_open(struct net_device *netdev)
@@ -151,6 +151,9 @@
/* TXDESC to TXCMPL ring mapping */
#define EDMA_REG_TXDESC2CMPL_MAP(n) (0x0c + 0x4 * (n))
/* Registers the ethtool dump reports, as offset and value pairs. */
#define EDMA_REGS_COUNT 34
/* Sizes and ring configuration */
#define EDMA_MAX_FRAME_SIZE 12288
#define EDMA_RX_PREHDR_SIZE (sizeof(struct edma_rx_preheader))