diff --git a/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.c b/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.c index 17e3715e69c..9378a07065d 100644 --- a/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.c +++ b/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.c @@ -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) diff --git a/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.h b/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.h index fc9f95f2162..96068a56002 100644 --- a/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.h +++ b/target/linux/qualcommax/files/drivers/net/ethernet/qualcomm/qca_edma.h @@ -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))