| From 7af037c39b600bac2c716dd1228e8ddbe149573f Mon Sep 17 00:00:00 2001 |
| From: Camel Guo <camelg@axis.com> |
| Date: Mon, 31 Jan 2022 09:38:40 +0100 |
| Subject: net: stmmac: dump gmac4 DMA registers correctly |
| |
| From: Camel Guo <camelg@axis.com> |
| |
| commit 7af037c39b600bac2c716dd1228e8ddbe149573f upstream. |
| |
| Unlike gmac100, gmac1000, gmac4 has 27 DMA registers and they are |
| located at DMA_CHAN_BASE_ADDR (0x1100). In order for ethtool to dump |
| gmac4 DMA registers correctly, this commit checks if a net_device has |
| gmac4 and uses different logic to dump its DMA registers. |
| |
| This fixes the following KASAN warning, which can normally be triggered |
| by a command similar like "ethtool -d eth0": |
| |
| BUG: KASAN: vmalloc-out-of-bounds in dwmac4_dump_dma_regs+0x6d4/0xb30 |
| Write of size 4 at addr ffffffc010177100 by task ethtool/1839 |
| kasan_report+0x200/0x21c |
| __asan_report_store4_noabort+0x34/0x60 |
| dwmac4_dump_dma_regs+0x6d4/0xb30 |
| stmmac_ethtool_gregs+0x110/0x204 |
| ethtool_get_regs+0x200/0x4b0 |
| dev_ethtool+0x1dac/0x3800 |
| dev_ioctl+0x7c0/0xb50 |
| sock_ioctl+0x298/0x6c4 |
| ... |
| |
| Fixes: fbf68229ffe7 ("net: stmmac: unify registers dumps methods") |
| Signed-off-by: Camel Guo <camelg@axis.com> |
| Link: https://lore.kernel.org/r/20220131083841.3346801-1-camel.guo@axis.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h | 1 + |
| drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 19 +++++++++++++++++-- |
| 2 files changed, 18 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h |
| +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h |
| @@ -130,6 +130,7 @@ |
| |
| #define NUM_DWMAC100_DMA_REGS 9 |
| #define NUM_DWMAC1000_DMA_REGS 23 |
| +#define NUM_DWMAC4_DMA_REGS 27 |
| |
| void dwmac_enable_dma_transmission(void __iomem *ioaddr); |
| void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); |
| --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c |
| +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c |
| @@ -21,10 +21,18 @@ |
| #include "dwxgmac2.h" |
| |
| #define REG_SPACE_SIZE 0x1060 |
| +#define GMAC4_REG_SPACE_SIZE 0x116C |
| #define MAC100_ETHTOOL_NAME "st_mac100" |
| #define GMAC_ETHTOOL_NAME "st_gmac" |
| #define XGMAC_ETHTOOL_NAME "st_xgmac" |
| |
| +/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h |
| + * |
| + * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the |
| + * same time due to the conflicting macro names. |
| + */ |
| +#define GMAC4_DMA_CHAN_BASE_ADDR 0x00001100 |
| + |
| #define ETHTOOL_DMA_OFFSET 55 |
| |
| struct stmmac_stats { |
| @@ -413,6 +421,8 @@ static int stmmac_ethtool_get_regs_len(s |
| |
| if (priv->plat->has_xgmac) |
| return XGMAC_REGSIZE * 4; |
| + else if (priv->plat->has_gmac4) |
| + return GMAC4_REG_SPACE_SIZE; |
| return REG_SPACE_SIZE; |
| } |
| |
| @@ -425,8 +435,13 @@ static void stmmac_ethtool_gregs(struct |
| stmmac_dump_mac_regs(priv, priv->hw, reg_space); |
| stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space); |
| |
| - if (!priv->plat->has_xgmac) { |
| - /* Copy DMA registers to where ethtool expects them */ |
| + /* Copy DMA registers to where ethtool expects them */ |
| + if (priv->plat->has_gmac4) { |
| + /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */ |
| + memcpy(®_space[ETHTOOL_DMA_OFFSET], |
| + ®_space[GMAC4_DMA_CHAN_BASE_ADDR / 4], |
| + NUM_DWMAC4_DMA_REGS * 4); |
| + } else if (!priv->plat->has_xgmac) { |
| memcpy(®_space[ETHTOOL_DMA_OFFSET], |
| ®_space[DMA_BUS_MODE / 4], |
| NUM_DWMAC1000_DMA_REGS * 4); |