aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2022-11-16 21:27:05 +0200
committerMichal Kubecek <mkubecek@suse.cz>2022-11-21 09:31:56 +0100
commit7c856b4e1d87a548ac386e9d68244ec2646ff4fd (patch)
tree94b4e03a7d6bacf06fd4a1cc06b98feb6055c6b6
parentcbd784424577a6df7a7592e9904a22b5c5d599b7 (diff)
downloadethtool-7c856b4e1d87a548ac386e9d68244ec2646ff4fd.tar.gz
fsl_enetc: add support for NXP ENETC driver
Add pretty printer for the registers which the enetc PF and VF drivers support since their introduction in kernel v5.1. The selection of registers parsed is the selection exported by the kernel as of v6.1-rc2. Unparsed registers are printed as raw. One register is printed field by field (MAC COMMAND_CONFIG), I didn't have time/interest in printing more than 1. The rest are printed in hex. Sample output: $ ethtool -d eno0 SI mode register: 0x80000000 SI primary MAC address register 0: 0x59f0400 SI primary MAC address register 1: 0x27f6 SI control BDR mode register: 0x40000000 SI control BDR status register: 0x0 SI control BDR base address register 0: 0x8262f000 SI control BDR base address register 1: 0x20 SI control BDR producer index register: 0x3a SI control BDR consumer index register: 0x3a SI control BDR length register: 0x40 SI capability register 0: 0x10080008 SI capability register 1: 0x20002 SI uncorrectable error frame drop count register: 0x0 TX BDR 0 mode register: 0x80000200 TX BDR 0 status register: 0x0 TX BDR 0 base address register 0: 0xebfa0000 TX BDR 0 base address register 1: 0x0 TX BDR 0 producer index register: 0x12 TX BDR 0 consumer index register: 0x12 TX BDR 0 length register: 0x800 TX BDR 0 interrupt enable register: 0x1 TX BDR 0 interrupt coalescing register 0: 0x80000008 TX BDR 0 interrupt coalescing register 1: 0x3a980 (repeats for other TX rings) RX BDR 0 mode register: 0x80000034 RX BDR 0 status register: 0x0 RX BDR 0 buffer size register: 0x680 RX BDR 0 consumer index register: 0x7ff RX BDR 0 base address register 0: 0xec430000 RX BDR 0 base address register 1: 0x0 RX BDR 0 producer index register: 0x0 RX BDR 0 length register: 0x800 RX BDR 0 interrupt enable register: 0x1 RX BDR 0 interrupt coalescing register 0: 0x80000100 RX BDR 0 interrupt coalescing register 1: 0x1 (repeats for other RX rings) Port mode register: 0x70200 Port status register: 0x0 Port SI promiscuous mode register: 0x0 Port SI0 primary MAC address register 0: 0x59f0400 Port SI0 primary MAC address register 1: 0x27f6 Port HTA transmit memory buffer allocation register: 0xc390 Port capability register 0: 0x10101b3c Port capability register 1: 0x2070 Port SI0 configuration register 0: 0x3080008 Port RFS capability register: 0x2 Port traffic class 0 maximum SDU register: 0x2580 Port eMAC Command and Configuration Register: 0x8813 MG 0 RXSTP 0 REG_LOWP_RXETY 0 TX_LOWP_ENA 0 SFD 0 NO_LEN_CHK 0 SEND_IDLE 0 CNT_FRM_EN 0 SWR 0 TXP 1 XGLP 0 TX_ADDR_INS 0 PAUSE_IGN 0 PAUSE_FWD 0 CRC 0 PAD 0 PROMIS 1 WAN 0 RX_EN 1 TX_EN 1 Port eMAC Maximum Frame Length Register: 0x2580 Port eMAC Interface Mode Control Register: 0x1002 Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
-rw-r--r--Makefile.am4
-rw-r--r--ethtool.c2
-rw-r--r--fsl_enetc.c259
-rw-r--r--internal.h3
4 files changed, 266 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 66e322a..fcc912e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,8 +13,8 @@ ethtool_SOURCES = ethtool.c uapi/linux/ethtool.h internal.h \
if ETHTOOL_ENABLE_PRETTY_DUMP
ethtool_SOURCES += \
amd8111e.c de2104x.c dsa.c e100.c e1000.c et131x.c igb.c \
- fec.c fec_8xx.c ibm_emac.c ixgb.c ixgbe.c natsemi.c \
- pcnet32.c realtek.c tg3.c marvell.c vioc.c \
+ fec.c fec_8xx.c fsl_enetc.c ibm_emac.c ixgb.c ixgbe.c \
+ natsemi.c pcnet32.c realtek.c tg3.c marvell.c vioc.c \
smsc911x.c at76c50x-usb.c sfc.c stmmac.c \
sff-common.c sff-common.h sfpid.c sfpdiag.c \
ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \
diff --git a/ethtool.c b/ethtool.c
index 5d49302..3207e49 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1134,6 +1134,8 @@ static const struct {
{ "bnxt_en", bnxt_dump_regs },
{ "cpsw-switch", cpsw_dump_regs },
{ "lan743x", lan743x_dump_regs },
+ { "fsl_enetc", fsl_enetc_dump_regs },
+ { "fsl_enetc_vf", fsl_enetc_dump_regs },
};
#endif
diff --git a/fsl_enetc.c b/fsl_enetc.c
new file mode 100644
index 0000000..1180a66
--- /dev/null
+++ b/fsl_enetc.c
@@ -0,0 +1,259 @@
+/* Code to dump registers for the Freescale/NXP ENETC controller.
+ *
+ * Copyright 2022 NXP
+ */
+#include <stdio.h>
+#include "internal.h"
+
+#define BIT(x) (1U << (x))
+
+enum enetc_bdr_type {TX, RX};
+#define ENETC_SIMR 0
+#define ENETC_SIPMAR0 0x80
+#define ENETC_SIPMAR1 0x84
+#define ENETC_SICBDRMR 0x800
+#define ENETC_SICBDRSR 0x804
+#define ENETC_SICBDRBAR0 0x810
+#define ENETC_SICBDRBAR1 0x814
+#define ENETC_SICBDRPIR 0x818
+#define ENETC_SICBDRCIR 0x81c
+#define ENETC_SICBDRLENR 0x820
+#define ENETC_SICAPR0 0x900
+#define ENETC_SICAPR1 0x904
+#define ENETC_SIUEFDCR 0xe28
+
+#define ENETC_BDR_OFF(i) ((i) * 0x200)
+#define ENETC_BDR(t, i, r) (0x8000 + (t) * 0x100 + ENETC_BDR_OFF(i) + (r))
+
+/* RX BDR reg offsets */
+#define ENETC_RBMR 0
+#define ENETC_RBSR 0x4
+#define ENETC_RBBSR 0x8
+#define ENETC_RBCIR 0xc
+#define ENETC_RBBAR0 0x10
+#define ENETC_RBBAR1 0x14
+#define ENETC_RBPIR 0x18
+#define ENETC_RBLENR 0x20
+#define ENETC_RBIER 0xa0
+#define ENETC_RBICR0 0xa8
+#define ENETC_RBICR1 0xac
+
+/* TX BDR reg offsets */
+#define ENETC_TBMR 0
+#define ENETC_TBSR 0x4
+#define ENETC_TBBAR0 0x10
+#define ENETC_TBBAR1 0x14
+#define ENETC_TBPIR 0x18
+#define ENETC_TBCIR 0x1c
+#define ENETC_TBLENR 0x20
+#define ENETC_TBIER 0xa0
+#define ENETC_TBIDR 0xa4
+#define ENETC_TBICR0 0xa8
+#define ENETC_TBICR1 0xac
+
+/* Port registers */
+#define ENETC_PORT_BASE 0x10000
+#define ENETC_PMR ENETC_PORT_BASE + 0x0000
+#define ENETC_PSR ENETC_PORT_BASE + 0x0004
+#define ENETC_PSIPMR ENETC_PORT_BASE + 0x0018
+#define ENETC_PSIPMAR0(n) ENETC_PORT_BASE + (0x0100 + (n) * 0x8) /* n = SI index */
+#define ENETC_PSIPMAR1(n) ENETC_PORT_BASE + (0x0104 + (n) * 0x8)
+#define ENETC_PTXMBAR ENETC_PORT_BASE + 0x0608
+#define ENETC_PCAPR0 ENETC_PORT_BASE + 0x0900
+#define ENETC_PCAPR1 ENETC_PORT_BASE + 0x0904
+#define ENETC_PSICFGR0(n) ENETC_PORT_BASE + (0x0940 + (n) * 0xc) /* n = SI index */
+
+#define ENETC_PRFSCAPR ENETC_PORT_BASE + 0x1804
+#define ENETC_PTCMSDUR(n) ENETC_PORT_BASE + (0x2020 + (n) * 4) /* n = TC index [0..7] */
+
+#define ENETC_PM0_CMD_CFG ENETC_PORT_BASE + 0x8008
+#define ENETC_PM0_CMD_TX_EN BIT(0)
+#define ENETC_PM0_CMD_RX_EN BIT(1)
+#define ENETC_PM0_CMD_WAN BIT(3)
+#define ENETC_PM0_CMD_PROMISC BIT(4)
+#define ENETC_PM0_CMD_PAD BIT(5)
+#define ENETC_PM0_CMD_CRC BIT(6)
+#define ENETC_PM0_CMD_PAUSE_FWD BIT(7)
+#define ENETC_PM0_CMD_PAUSE_IGN BIT(8)
+#define ENETC_PM0_CMD_TX_ADDR_INS BIT(9)
+#define ENETC_PM0_CMD_XGLP BIT(10)
+#define ENETC_PM0_CMD_TXP BIT(11)
+#define ENETC_PM0_CMD_SWR BIT(12)
+#define ENETC_PM0_CMD_CNT_FRM_EN BIT(13)
+#define ENETC_PM0_CMD_SEND_IDLE BIT(16)
+#define ENETC_PM0_CMD_NO_LEN_CHK BIT(17)
+#define ENETC_PM0_CMD_SFD BIT(21)
+#define ENETC_PM0_CMD_TX_LOWP_ENA BIT(23)
+#define ENETC_PM0_CMD_REG_LOWP_RXETY BIT(24)
+#define ENETC_PM0_CMD_RXSTP BIT(29)
+#define ENETC_PM0_CMD_MG BIT(31)
+
+#define ENETC_PM0_MAXFRM ENETC_PORT_BASE + 0x8014
+#define ENETC_PM0_IF_MODE ENETC_PORT_BASE + 0x8300
+
+struct enetc_register {
+ u32 addr;
+ const char *name;
+ void (*decode)(u32 val, char *buf);
+};
+
+#define REG(_reg, _name) { .addr = (_reg), .name = (_name) }
+
+#define REG_DEC(_reg, _name, _decode) \
+ { .addr = (_reg), .name = (_name), .decode = (_decode) }
+
+static void decode_cmd_cfg(u32 val, char *buf)
+{
+ sprintf(buf, "\tMG %d\n\tRXSTP %d\n\tREG_LOWP_RXETY %d\n"
+ "\tTX_LOWP_ENA %d\n\tSFD %d\n\tNO_LEN_CHK %d\n\tSEND_IDLE %d\n"
+ "\tCNT_FRM_EN %d\n\tSWR %d\n\tTXP %d\n\tXGLP %d\n"
+ "\tTX_ADDR_INS %d\n\tPAUSE_IGN %d\n\tPAUSE_FWD %d\n\tCRC %d\n"
+ "\tPAD %d\n\tPROMIS %d\n\tWAN %d\n\tRX_EN %d\n\tTX_EN %d\n",
+ !!(val & ENETC_PM0_CMD_MG),
+ !!(val & ENETC_PM0_CMD_RXSTP),
+ !!(val & ENETC_PM0_CMD_REG_LOWP_RXETY),
+ !!(val & ENETC_PM0_CMD_TX_LOWP_ENA),
+ !!(val & ENETC_PM0_CMD_SFD),
+ !!(val & ENETC_PM0_CMD_NO_LEN_CHK),
+ !!(val & ENETC_PM0_CMD_SEND_IDLE),
+ !!(val & ENETC_PM0_CMD_CNT_FRM_EN),
+ !!(val & ENETC_PM0_CMD_SWR),
+ !!(val & ENETC_PM0_CMD_TXP),
+ !!(val & ENETC_PM0_CMD_XGLP),
+ !!(val & ENETC_PM0_CMD_TX_ADDR_INS),
+ !!(val & ENETC_PM0_CMD_PAUSE_IGN),
+ !!(val & ENETC_PM0_CMD_PAUSE_FWD),
+ !!(val & ENETC_PM0_CMD_CRC),
+ !!(val & ENETC_PM0_CMD_PAD),
+ !!(val & ENETC_PM0_CMD_PROMISC),
+ !!(val & ENETC_PM0_CMD_WAN),
+ !!(val & ENETC_PM0_CMD_RX_EN),
+ !!(val & ENETC_PM0_CMD_TX_EN));
+}
+
+#define RXBDR_REGS(_i) \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBMR), "RX BDR " #_i " mode register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBSR), "RX BDR " #_i " status register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBBSR), "RX BDR " #_i " buffer size register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBPIR), "RX BDR " #_i " producer index register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBCIR), "RX BDR " #_i " consumer index register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBBAR0), "RX BDR " #_i " base address register 0"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBBAR1), "RX BDR " #_i " base address register 1"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBLENR), "RX BDR " #_i " length register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBIER), "RX BDR " #_i " interrupt enable register"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBICR0), "RX BDR " #_i " interrupt coalescing register 0"), \
+ REG(ENETC_BDR(RX, (_i), ENETC_RBICR1), "RX BDR " #_i " interrupt coalescing register 1")
+
+#define TXBDR_REGS(_i) \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBMR), "TX BDR " #_i " mode register"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBSR), "TX BDR " #_i " status register"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBBAR0), "TX BDR " #_i " base address register 0"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBBAR1), "TX BDR " #_i " base address register 1"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBPIR), "TX BDR " #_i " producer index register"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBCIR), "TX BDR " #_i " consumer index register"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBLENR), "TX BDR " #_i " length register"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBIER), "TX BDR " #_i " interrupt enable register"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBICR0), "TX BDR " #_i " interrupt coalescing register 0"), \
+ REG(ENETC_BDR(TX, (_i), ENETC_TBICR1), "TX BDR " #_i " interrupt coalescing register 1")
+
+static const struct enetc_register known_enetc_regs[] = {
+ REG(ENETC_SIMR, "SI mode register"),
+ REG(ENETC_SIPMAR0, "SI primary MAC address register 0"),
+ REG(ENETC_SIPMAR1, "SI primary MAC address register 1"),
+ REG(ENETC_SICBDRMR, "SI control BDR mode register"),
+ REG(ENETC_SICBDRSR, "SI control BDR status register"),
+ REG(ENETC_SICBDRBAR0, "SI control BDR base address register 0"),
+ REG(ENETC_SICBDRBAR1, "SI control BDR base address register 1"),
+ REG(ENETC_SICBDRPIR, "SI control BDR producer index register"),
+ REG(ENETC_SICBDRCIR, "SI control BDR consumer index register"),
+ REG(ENETC_SICBDRLENR, "SI control BDR length register"),
+ REG(ENETC_SICAPR0, "SI capability register 0"),
+ REG(ENETC_SICAPR1, "SI capability register 1"),
+ REG(ENETC_SIUEFDCR, "SI uncorrectable error frame drop count register"),
+
+ TXBDR_REGS(0), TXBDR_REGS(1), TXBDR_REGS(2), TXBDR_REGS(3),
+ TXBDR_REGS(4), TXBDR_REGS(5), TXBDR_REGS(6), TXBDR_REGS(7),
+ TXBDR_REGS(8), TXBDR_REGS(9), TXBDR_REGS(10), TXBDR_REGS(11),
+ TXBDR_REGS(12), TXBDR_REGS(13), TXBDR_REGS(14), TXBDR_REGS(15),
+
+ RXBDR_REGS(0), RXBDR_REGS(1), RXBDR_REGS(2), RXBDR_REGS(3),
+ RXBDR_REGS(4), RXBDR_REGS(5), RXBDR_REGS(6), RXBDR_REGS(7),
+ RXBDR_REGS(8), RXBDR_REGS(9), RXBDR_REGS(10), RXBDR_REGS(11),
+ RXBDR_REGS(12), RXBDR_REGS(13), RXBDR_REGS(14), RXBDR_REGS(15),
+
+ REG(ENETC_PMR, "Port mode register"),
+ REG(ENETC_PSR, "Port status register"),
+ REG(ENETC_PSIPMR, "Port SI promiscuous mode register"),
+ REG(ENETC_PSIPMAR0(0), "Port SI0 primary MAC address register 0"),
+ REG(ENETC_PSIPMAR1(0), "Port SI0 primary MAC address register 1"),
+ REG(ENETC_PTXMBAR, "Port HTA transmit memory buffer allocation register"),
+ REG(ENETC_PCAPR0, "Port capability register 0"),
+ REG(ENETC_PCAPR1, "Port capability register 1"),
+ REG(ENETC_PSICFGR0(0), "Port SI0 configuration register 0"),
+ REG(ENETC_PRFSCAPR, "Port RFS capability register"),
+ REG(ENETC_PTCMSDUR(0), "Port traffic class 0 maximum SDU register"),
+ REG_DEC(ENETC_PM0_CMD_CFG, "Port eMAC Command and Configuration Register",
+ decode_cmd_cfg),
+ REG(ENETC_PM0_MAXFRM, "Port eMAC Maximum Frame Length Register"),
+ REG(ENETC_PM0_IF_MODE, "Port eMAC Interface Mode Control Register"),
+};
+
+static void decode_known_reg(const struct enetc_register *reg, u32 val)
+{
+ char buf[512];
+
+ reg->decode(val, buf);
+ fprintf(stdout, "%s: 0x%x\n%s", reg->name, val, buf);
+}
+
+static void dump_known_reg(const struct enetc_register *reg, u32 val)
+{
+ fprintf(stdout, "%s: 0x%x\n", reg->name, val);
+}
+
+static void dump_unknown_reg(u32 addr, u32 val)
+{
+ fprintf(stdout, "Reg 0x%x: 0x%x\n", addr, val);
+}
+
+static void dump_reg(u32 addr, u32 val)
+{
+ const struct enetc_register *reg;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(known_enetc_regs); i++) {
+ reg = &known_enetc_regs[i];
+ if (reg->addr == addr) {
+ if (reg->decode)
+ decode_known_reg(reg, val);
+ else
+ dump_known_reg(reg, val);
+ return;
+ }
+ }
+
+ dump_unknown_reg(addr, val);
+}
+
+/* Registers are structured in an array of key/value u32 pairs.
+ * Compare each key to our list of known registers, or print it
+ * as a raw address otherwise.
+ */
+int fsl_enetc_dump_regs(struct ethtool_drvinfo *info __maybe_unused,
+ struct ethtool_regs *regs)
+{
+ u32 *data = (u32 *)regs->data;
+ u32 len = regs->len;
+
+ if (len % 8) {
+ fprintf(stdout, "Expected length to be multiple of 8 bytes\n");
+ return -1;
+ }
+
+ while (len) {
+ dump_reg(data[0], data[1]);
+ data += 2; len -= 8;
+ }
+
+ return 0;
+}
diff --git a/internal.h b/internal.h
index 9fa6d80..dd7d6ac 100644
--- a/internal.h
+++ b/internal.h
@@ -406,6 +406,9 @@ int dsa_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
/* i.MX Fast Ethernet Controller */
int fec_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+/* Freescale/NXP ENETC Ethernet Controller */
+int fsl_enetc_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
/* Intel(R) Ethernet Controller I225-LM/I225-V adapter family */
int igc_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);