Message ID | 20190413012822.30931-18-olteanv@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | David Miller |
Headers | show |
Series | NXP SJA1105 DSA driver | expand |
Sat, Apr 13, 2019 at 03:28:15AM CEST, olteanv@gmail.com wrote: >Signed-off-by: Vladimir Oltean <olteanv@gmail.com> >Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> >--- >Changes in v3: >None. > >Changes in v2: >None functional. Moved the IS_ET() and IS_PQRS() device identification >macros here since they are not used in earlier patches. > > drivers/net/dsa/sja1105/Makefile | 1 + > drivers/net/dsa/sja1105/sja1105.h | 7 +- > drivers/net/dsa/sja1105/sja1105_ethtool.c | 414 ++++++++++++++++++ > drivers/net/dsa/sja1105/sja1105_main.c | 3 + > .../net/dsa/sja1105/sja1105_static_config.h | 21 + > 5 files changed, 445 insertions(+), 1 deletion(-) > create mode 100644 drivers/net/dsa/sja1105/sja1105_ethtool.c > >diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile >index ed00840802f4..bb4404c79eb2 100644 >--- a/drivers/net/dsa/sja1105/Makefile >+++ b/drivers/net/dsa/sja1105/Makefile >@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o > sja1105-objs := \ > sja1105_spi.o \ > sja1105_main.o \ >+ sja1105_ethtool.o \ > sja1105_clocking.o \ > sja1105_static_config.o \ > sja1105_dynamic_config.o \ >diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h >index 4c9df44a4478..80b20bdd8f9c 100644 >--- a/drivers/net/dsa/sja1105/sja1105.h >+++ b/drivers/net/dsa/sja1105/sja1105.h >@@ -120,8 +120,13 @@ typedef enum { > int sja1105_clocking_setup_port(struct sja1105_private *priv, int port); > int sja1105_clocking_setup(struct sja1105_private *priv); > >-/* From sja1105_dynamic_config.c */ >+/* From sja1105_ethtool.c */ >+void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data); >+void sja1105_get_strings(struct dsa_switch *ds, int port, >+ u32 stringset, u8 *data); >+int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset); > >+/* From sja1105_dynamic_config.c */ > int sja1105_dynamic_config_read(struct sja1105_private *priv, > enum sja1105_blk_idx blk_idx, > int index, void *entry); >diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c >new file mode 100644 >index 000000000000..c082599702bd >--- /dev/null >+++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c >@@ -0,0 +1,414 @@ >+// SPDX-License-Identifier: GPL-2.0 >+/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> >+ */ >+#include "sja1105.h" >+ >+#define SIZE_MAC_AREA (0x02 * 4) >+#define SIZE_HL1_AREA (0x10 * 4) >+#define SIZE_HL2_AREA (0x4 * 4) >+#define SIZE_QLEVEL_AREA (0x8 * 4) /* 0x4 to 0xB */ Please use prefixes for defines like this. For example "SIZE_MAC_AREA" sounds way too generic. [...] >+static void >+sja1105_port_status_hl1_unpack(void *buf, >+ struct sja1105_port_status_hl1 *status) >+{ >+ /* Make pointer arithmetic work on 4 bytes */ >+ u32 *p = (u32 *)buf; You don't need to cast void *. Please avoid it in the whole patchset. [...] >+ if (!IS_PQRS(priv->info->device_id)) >+ return; >+ >+ memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) * >+ sizeof(u64)); >+ for (i = 0; i < 8; i++) { Array size instead of "8"? >+ data[k++] = status.hl2.qlevel_hwm[i]; >+ data[k++] = status.hl2.qlevel[i]; >+ } [...] > >+#define IS_PQRS(device_id) \ >+ (((device_id) == SJA1105PR_DEVICE_ID) || \ >+ ((device_id) == SJA1105QS_DEVICE_ID)) >+#define IS_ET(device_id) \ >+ (((device_id) == SJA1105E_DEVICE_ID) || \ >+ ((device_id) == SJA1105T_DEVICE_ID)) >+/* P and R have same Device ID, and differ by Part Number */ >+#define IS_P(device_id, part_nr) \ >+ (((device_id) == SJA1105PR_DEVICE_ID) && \ >+ ((part_nr) == SJA1105P_PART_NR)) >+#define IS_R(device_id, part_nr) \ >+ (((device_id) == SJA1105PR_DEVICE_ID) && \ >+ ((part_nr) == SJA1105R_PART_NR)) >+/* Same do Q and S */ >+#define IS_Q(device_id, part_nr) \ >+ (((device_id) == SJA1105QS_DEVICE_ID) && \ >+ ((part_nr) == SJA1105Q_PART_NR)) >+#define IS_S(device_id, part_nr) \ Please have a prefix for macros like this. "IS_S" sounds way too generic... >+ (((device_id) == SJA1105QS_DEVICE_ID) && \ >+ ((part_nr) == SJA1105S_PART_NR)) >+ > struct sja1105_general_params_entry { > u64 vllupformat; > u64 mirr_ptacu; >-- >2.17.1 >
On Sat, 13 Apr 2019 at 23:53, Jiri Pirko <jiri@resnulli.us> wrote: > > Sat, Apr 13, 2019 at 03:28:15AM CEST, olteanv@gmail.com wrote: > >Signed-off-by: Vladimir Oltean <olteanv@gmail.com> > >Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> > >--- > >Changes in v3: > >None. > > > >Changes in v2: > >None functional. Moved the IS_ET() and IS_PQRS() device identification > >macros here since they are not used in earlier patches. > > > > drivers/net/dsa/sja1105/Makefile | 1 + > > drivers/net/dsa/sja1105/sja1105.h | 7 +- > > drivers/net/dsa/sja1105/sja1105_ethtool.c | 414 ++++++++++++++++++ > > drivers/net/dsa/sja1105/sja1105_main.c | 3 + > > .../net/dsa/sja1105/sja1105_static_config.h | 21 + > > 5 files changed, 445 insertions(+), 1 deletion(-) > > create mode 100644 drivers/net/dsa/sja1105/sja1105_ethtool.c > > > >diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile > >index ed00840802f4..bb4404c79eb2 100644 > >--- a/drivers/net/dsa/sja1105/Makefile > >+++ b/drivers/net/dsa/sja1105/Makefile > >@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o > > sja1105-objs := \ > > sja1105_spi.o \ > > sja1105_main.o \ > >+ sja1105_ethtool.o \ > > sja1105_clocking.o \ > > sja1105_static_config.o \ > > sja1105_dynamic_config.o \ > >diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h > >index 4c9df44a4478..80b20bdd8f9c 100644 > >--- a/drivers/net/dsa/sja1105/sja1105.h > >+++ b/drivers/net/dsa/sja1105/sja1105.h > >@@ -120,8 +120,13 @@ typedef enum { > > int sja1105_clocking_setup_port(struct sja1105_private *priv, int port); > > int sja1105_clocking_setup(struct sja1105_private *priv); > > > >-/* From sja1105_dynamic_config.c */ > >+/* From sja1105_ethtool.c */ > >+void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data); > >+void sja1105_get_strings(struct dsa_switch *ds, int port, > >+ u32 stringset, u8 *data); > >+int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset); > > > >+/* From sja1105_dynamic_config.c */ > > int sja1105_dynamic_config_read(struct sja1105_private *priv, > > enum sja1105_blk_idx blk_idx, > > int index, void *entry); > >diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c > >new file mode 100644 > >index 000000000000..c082599702bd > >--- /dev/null > >+++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c > >@@ -0,0 +1,414 @@ > >+// SPDX-License-Identifier: GPL-2.0 > >+/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> > >+ */ > >+#include "sja1105.h" > >+ > >+#define SIZE_MAC_AREA (0x02 * 4) > >+#define SIZE_HL1_AREA (0x10 * 4) > >+#define SIZE_HL2_AREA (0x4 * 4) > >+#define SIZE_QLEVEL_AREA (0x8 * 4) /* 0x4 to 0xB */ > > Please use prefixes for defines like this. For example "SIZE_MAC_AREA" > sounds way too generic. > What you propose sounds nice but then consistency would be a concern, so I'd have to redo the entire driver. And then there are tables named like "L2 Address Lookup Parameters Table", and as if SIZE_L2_LOOKUP_PARAMS_DYN_CMD_ET wasn't long enough, a prefix would top it off. I don't think it's as much of an issue for the reader (for the compiler it clearly isn't, as it's restricted to this C file only) as it is for tools like ctags? > [...] > > > >+static void > >+sja1105_port_status_hl1_unpack(void *buf, > >+ struct sja1105_port_status_hl1 *status) > >+{ > >+ /* Make pointer arithmetic work on 4 bytes */ > >+ u32 *p = (u32 *)buf; > > You don't need to cast void *. Please avoid it in the whole patchset. > Ok. > [...] > > > >+ if (!IS_PQRS(priv->info->device_id)) > >+ return; > >+ > >+ memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) * > >+ sizeof(u64)); > >+ for (i = 0; i < 8; i++) { > > Array size instead of "8"? > Perhaps SJA1105_NUM_TC, since the egress queue occupancy levels are per traffic class. The size of the array is 16. > > >+ data[k++] = status.hl2.qlevel_hwm[i]; > >+ data[k++] = status.hl2.qlevel[i]; > >+ } > > [...] > > > > > >+#define IS_PQRS(device_id) \ > >+ (((device_id) == SJA1105PR_DEVICE_ID) || \ > >+ ((device_id) == SJA1105QS_DEVICE_ID)) > >+#define IS_ET(device_id) \ > >+ (((device_id) == SJA1105E_DEVICE_ID) || \ > >+ ((device_id) == SJA1105T_DEVICE_ID)) > >+/* P and R have same Device ID, and differ by Part Number */ > >+#define IS_P(device_id, part_nr) \ > >+ (((device_id) == SJA1105PR_DEVICE_ID) && \ > >+ ((part_nr) == SJA1105P_PART_NR)) > >+#define IS_R(device_id, part_nr) \ > >+ (((device_id) == SJA1105PR_DEVICE_ID) && \ > >+ ((part_nr) == SJA1105R_PART_NR)) > >+/* Same do Q and S */ > >+#define IS_Q(device_id, part_nr) \ > >+ (((device_id) == SJA1105QS_DEVICE_ID) && \ > >+ ((part_nr) == SJA1105Q_PART_NR)) > >+#define IS_S(device_id, part_nr) \ > > Please have a prefix for macros like this. "IS_S" sounds way too > generic... > Ok, I can think of a more descriptive name, since there are under 5 occurrences of these macros after the reorg, now that I have the sja1105_info structure which also holds per-revision function pointers. > > >+ (((device_id) == SJA1105QS_DEVICE_ID) && \ > >+ ((part_nr) == SJA1105S_PART_NR)) > >+ > > struct sja1105_general_params_entry { > > u64 vllupformat; > > u64 mirr_ptacu; > >-- > >2.17.1 > > Thanks! -Vladimir
Sat, Apr 13, 2019 at 11:55:52PM CEST, olteanv@gmail.com wrote: >On Sat, 13 Apr 2019 at 23:53, Jiri Pirko <jiri@resnulli.us> wrote: >> >> Sat, Apr 13, 2019 at 03:28:15AM CEST, olteanv@gmail.com wrote: >> >Signed-off-by: Vladimir Oltean <olteanv@gmail.com> >> >Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> >> >--- >> >Changes in v3: >> >None. >> > >> >Changes in v2: >> >None functional. Moved the IS_ET() and IS_PQRS() device identification >> >macros here since they are not used in earlier patches. >> > >> > drivers/net/dsa/sja1105/Makefile | 1 + >> > drivers/net/dsa/sja1105/sja1105.h | 7 +- >> > drivers/net/dsa/sja1105/sja1105_ethtool.c | 414 ++++++++++++++++++ >> > drivers/net/dsa/sja1105/sja1105_main.c | 3 + >> > .../net/dsa/sja1105/sja1105_static_config.h | 21 + >> > 5 files changed, 445 insertions(+), 1 deletion(-) >> > create mode 100644 drivers/net/dsa/sja1105/sja1105_ethtool.c >> > >> >diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile >> >index ed00840802f4..bb4404c79eb2 100644 >> >--- a/drivers/net/dsa/sja1105/Makefile >> >+++ b/drivers/net/dsa/sja1105/Makefile >> >@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o >> > sja1105-objs := \ >> > sja1105_spi.o \ >> > sja1105_main.o \ >> >+ sja1105_ethtool.o \ >> > sja1105_clocking.o \ >> > sja1105_static_config.o \ >> > sja1105_dynamic_config.o \ >> >diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h >> >index 4c9df44a4478..80b20bdd8f9c 100644 >> >--- a/drivers/net/dsa/sja1105/sja1105.h >> >+++ b/drivers/net/dsa/sja1105/sja1105.h >> >@@ -120,8 +120,13 @@ typedef enum { >> > int sja1105_clocking_setup_port(struct sja1105_private *priv, int port); >> > int sja1105_clocking_setup(struct sja1105_private *priv); >> > >> >-/* From sja1105_dynamic_config.c */ >> >+/* From sja1105_ethtool.c */ >> >+void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data); >> >+void sja1105_get_strings(struct dsa_switch *ds, int port, >> >+ u32 stringset, u8 *data); >> >+int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset); >> > >> >+/* From sja1105_dynamic_config.c */ >> > int sja1105_dynamic_config_read(struct sja1105_private *priv, >> > enum sja1105_blk_idx blk_idx, >> > int index, void *entry); >> >diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c >> >new file mode 100644 >> >index 000000000000..c082599702bd >> >--- /dev/null >> >+++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c >> >@@ -0,0 +1,414 @@ >> >+// SPDX-License-Identifier: GPL-2.0 >> >+/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> >> >+ */ >> >+#include "sja1105.h" >> >+ >> >+#define SIZE_MAC_AREA (0x02 * 4) >> >+#define SIZE_HL1_AREA (0x10 * 4) >> >+#define SIZE_HL2_AREA (0x4 * 4) >> >+#define SIZE_QLEVEL_AREA (0x8 * 4) /* 0x4 to 0xB */ >> >> Please use prefixes for defines like this. For example "SIZE_MAC_AREA" >> sounds way too generic. >> > >What you propose sounds nice but then consistency would be a concern, >so I'd have to redo the entire driver. And then there are tables named Yep >like "L2 Address Lookup Parameters Table", and as if >SIZE_L2_LOOKUP_PARAMS_DYN_CMD_ET wasn't long enough, a prefix would >top it off. It's a tradeoff. But most of the time, it is doable. Then the code is easier to read. >I don't think it's as much of an issue for the reader (for the >compiler it clearly isn't, as it's restricted to this C file only) as >it is for tools like ctags? > >> [...] >> >> >> >+static void >> >+sja1105_port_status_hl1_unpack(void *buf, >> >+ struct sja1105_port_status_hl1 *status) >> >+{ >> >+ /* Make pointer arithmetic work on 4 bytes */ >> >+ u32 *p = (u32 *)buf; >> >> You don't need to cast void *. Please avoid it in the whole patchset. >> > >Ok. > >> [...] >> >> >> >+ if (!IS_PQRS(priv->info->device_id)) >> >+ return; >> >+ >> >+ memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) * >> >+ sizeof(u64)); >> >+ for (i = 0; i < 8; i++) { >> >> Array size instead of "8"? >> > >Perhaps SJA1105_NUM_TC, since the egress queue occupancy levels are >per traffic class. The size of the array is 16. > >> >> >+ data[k++] = status.hl2.qlevel_hwm[i]; >> >+ data[k++] = status.hl2.qlevel[i]; >> >+ } >> >> [...] >> >> >> > >> >+#define IS_PQRS(device_id) \ >> >+ (((device_id) == SJA1105PR_DEVICE_ID) || \ >> >+ ((device_id) == SJA1105QS_DEVICE_ID)) >> >+#define IS_ET(device_id) \ >> >+ (((device_id) == SJA1105E_DEVICE_ID) || \ >> >+ ((device_id) == SJA1105T_DEVICE_ID)) >> >+/* P and R have same Device ID, and differ by Part Number */ >> >+#define IS_P(device_id, part_nr) \ >> >+ (((device_id) == SJA1105PR_DEVICE_ID) && \ >> >+ ((part_nr) == SJA1105P_PART_NR)) >> >+#define IS_R(device_id, part_nr) \ >> >+ (((device_id) == SJA1105PR_DEVICE_ID) && \ >> >+ ((part_nr) == SJA1105R_PART_NR)) >> >+/* Same do Q and S */ >> >+#define IS_Q(device_id, part_nr) \ >> >+ (((device_id) == SJA1105QS_DEVICE_ID) && \ >> >+ ((part_nr) == SJA1105Q_PART_NR)) >> >+#define IS_S(device_id, part_nr) \ >> >> Please have a prefix for macros like this. "IS_S" sounds way too >> generic... >> > >Ok, I can think of a more descriptive name, since there are under 5 >occurrences of these macros after the reorg, now that I have the >sja1105_info structure which also holds per-revision function >pointers. > >> >> >+ (((device_id) == SJA1105QS_DEVICE_ID) && \ >> >+ ((part_nr) == SJA1105S_PART_NR)) >> >+ >> > struct sja1105_general_params_entry { >> > u64 vllupformat; >> > u64 mirr_ptacu; >> >-- >> >2.17.1 >> > > > >Thanks! >-Vladimir
diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile index ed00840802f4..bb4404c79eb2 100644 --- a/drivers/net/dsa/sja1105/Makefile +++ b/drivers/net/dsa/sja1105/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o sja1105-objs := \ sja1105_spi.o \ sja1105_main.o \ + sja1105_ethtool.o \ sja1105_clocking.o \ sja1105_static_config.o \ sja1105_dynamic_config.o \ diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 4c9df44a4478..80b20bdd8f9c 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -120,8 +120,13 @@ typedef enum { int sja1105_clocking_setup_port(struct sja1105_private *priv, int port); int sja1105_clocking_setup(struct sja1105_private *priv); -/* From sja1105_dynamic_config.c */ +/* From sja1105_ethtool.c */ +void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data); +void sja1105_get_strings(struct dsa_switch *ds, int port, + u32 stringset, u8 *data); +int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset); +/* From sja1105_dynamic_config.c */ int sja1105_dynamic_config_read(struct sja1105_private *priv, enum sja1105_blk_idx blk_idx, int index, void *entry); diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c new file mode 100644 index 000000000000..c082599702bd --- /dev/null +++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> + */ +#include "sja1105.h" + +#define SIZE_MAC_AREA (0x02 * 4) +#define SIZE_HL1_AREA (0x10 * 4) +#define SIZE_HL2_AREA (0x4 * 4) +#define SIZE_QLEVEL_AREA (0x8 * 4) /* 0x4 to 0xB */ + +struct sja1105_port_status_mac { + u64 n_runt; + u64 n_soferr; + u64 n_alignerr; + u64 n_miierr; + u64 typeerr; + u64 sizeerr; + u64 tctimeout; + u64 priorerr; + u64 nomaster; + u64 memov; + u64 memerr; + u64 invtyp; + u64 intcyov; + u64 domerr; + u64 pcfbagdrop; + u64 spcprior; + u64 ageprior; + u64 portdrop; + u64 lendrop; + u64 bagdrop; + u64 policeerr; + u64 drpnona664err; + u64 spcerr; + u64 agedrp; +}; + +struct sja1105_port_status_hl1 { + u64 n_n664err; + u64 n_vlanerr; + u64 n_unreleased; + u64 n_sizeerr; + u64 n_crcerr; + u64 n_vlnotfound; + u64 n_ctpolerr; + u64 n_polerr; + u64 n_rxfrmsh; + u64 n_rxfrm; + u64 n_rxbytesh; + u64 n_rxbyte; + u64 n_txfrmsh; + u64 n_txfrm; + u64 n_txbytesh; + u64 n_txbyte; +}; + +struct sja1105_port_status_hl2 { + u64 n_qfull; + u64 n_part_drop; + u64 n_egr_disabled; + u64 n_not_reach; + u64 qlevel_hwm[8]; /* Only for P/Q/R/S */ + u64 qlevel[8]; /* Only for P/Q/R/S */ +}; + +struct sja1105_port_status { + struct sja1105_port_status_mac mac; + struct sja1105_port_status_hl1 hl1; + struct sja1105_port_status_hl2 hl2; +}; + +static void +sja1105_port_status_mac_unpack(void *buf, + struct sja1105_port_status_mac *status) +{ + /* Make pointer arithmetic work on 4 bytes */ + u32 *p = (u32 *)buf; + + sja1105_unpack(p + 0x0, &status->n_runt, 31, 24, 4); + sja1105_unpack(p + 0x0, &status->n_soferr, 23, 16, 4); + sja1105_unpack(p + 0x0, &status->n_alignerr, 15, 8, 4); + sja1105_unpack(p + 0x0, &status->n_miierr, 7, 0, 4); + sja1105_unpack(p + 0x1, &status->typeerr, 27, 27, 4); + sja1105_unpack(p + 0x1, &status->sizeerr, 26, 26, 4); + sja1105_unpack(p + 0x1, &status->tctimeout, 25, 25, 4); + sja1105_unpack(p + 0x1, &status->priorerr, 24, 24, 4); + sja1105_unpack(p + 0x1, &status->nomaster, 23, 23, 4); + sja1105_unpack(p + 0x1, &status->memov, 22, 22, 4); + sja1105_unpack(p + 0x1, &status->memerr, 21, 21, 4); + sja1105_unpack(p + 0x1, &status->invtyp, 19, 19, 4); + sja1105_unpack(p + 0x1, &status->intcyov, 18, 18, 4); + sja1105_unpack(p + 0x1, &status->domerr, 17, 17, 4); + sja1105_unpack(p + 0x1, &status->pcfbagdrop, 16, 16, 4); + sja1105_unpack(p + 0x1, &status->spcprior, 15, 12, 4); + sja1105_unpack(p + 0x1, &status->ageprior, 11, 8, 4); + sja1105_unpack(p + 0x1, &status->portdrop, 6, 6, 4); + sja1105_unpack(p + 0x1, &status->lendrop, 5, 5, 4); + sja1105_unpack(p + 0x1, &status->bagdrop, 4, 4, 4); + sja1105_unpack(p + 0x1, &status->policeerr, 3, 3, 4); + sja1105_unpack(p + 0x1, &status->drpnona664err, 2, 2, 4); + sja1105_unpack(p + 0x1, &status->spcerr, 1, 1, 4); + sja1105_unpack(p + 0x1, &status->agedrp, 0, 0, 4); +} + +static void +sja1105_port_status_hl1_unpack(void *buf, + struct sja1105_port_status_hl1 *status) +{ + /* Make pointer arithmetic work on 4 bytes */ + u32 *p = (u32 *)buf; + + sja1105_unpack(p + 0xF, &status->n_n664err, 31, 0, 4); + sja1105_unpack(p + 0xE, &status->n_vlanerr, 31, 0, 4); + sja1105_unpack(p + 0xD, &status->n_unreleased, 31, 0, 4); + sja1105_unpack(p + 0xC, &status->n_sizeerr, 31, 0, 4); + sja1105_unpack(p + 0xB, &status->n_crcerr, 31, 0, 4); + sja1105_unpack(p + 0xA, &status->n_vlnotfound, 31, 0, 4); + sja1105_unpack(p + 0x9, &status->n_ctpolerr, 31, 0, 4); + sja1105_unpack(p + 0x8, &status->n_polerr, 31, 0, 4); + sja1105_unpack(p + 0x7, &status->n_rxfrmsh, 31, 0, 4); + sja1105_unpack(p + 0x6, &status->n_rxfrm, 31, 0, 4); + sja1105_unpack(p + 0x5, &status->n_rxbytesh, 31, 0, 4); + sja1105_unpack(p + 0x4, &status->n_rxbyte, 31, 0, 4); + sja1105_unpack(p + 0x3, &status->n_txfrmsh, 31, 0, 4); + sja1105_unpack(p + 0x2, &status->n_txfrm, 31, 0, 4); + sja1105_unpack(p + 0x1, &status->n_txbytesh, 31, 0, 4); + sja1105_unpack(p + 0x0, &status->n_txbyte, 31, 0, 4); + status->n_rxfrm += status->n_rxfrmsh << 32; + status->n_rxbyte += status->n_rxbytesh << 32; + status->n_txfrm += status->n_txfrmsh << 32; + status->n_txbyte += status->n_txbytesh << 32; +} + +static void +sja1105_port_status_hl2_unpack(void *buf, + struct sja1105_port_status_hl2 *status) +{ + /* Make pointer arithmetic work on 4 bytes */ + u32 *p = (u32 *)buf; + + sja1105_unpack(p + 0x3, &status->n_qfull, 31, 0, 4); + sja1105_unpack(p + 0x2, &status->n_part_drop, 31, 0, 4); + sja1105_unpack(p + 0x1, &status->n_egr_disabled, 31, 0, 4); + sja1105_unpack(p + 0x0, &status->n_not_reach, 31, 0, 4); +} + +static void +sja1105pqrs_port_status_qlevel_unpack(void *buf, + struct sja1105_port_status_hl2 *status) +{ + /* Make pointer arithmetic work on 4 bytes */ + u32 *p = (u32 *)buf; + int i; + + for (i = 0; i < 8; i++) { + sja1105_unpack(p + i, &status->qlevel_hwm[i], 24, 16, 4); + sja1105_unpack(p + i, &status->qlevel[i], 8, 0, 4); + } +} + +static int sja1105_port_status_get_mac(struct sja1105_private *priv, + struct sja1105_port_status_mac *status, + int port) +{ + const struct sja1105_regs *regs = priv->info->regs; + u8 packed_buf[SIZE_MAC_AREA] = {0}; + int rc; + + /* MAC area */ + rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac[port], + packed_buf, SIZE_MAC_AREA); + if (rc < 0) + return rc; + + sja1105_port_status_mac_unpack(packed_buf, status); + + return 0; +} + +static int sja1105_port_status_get_hl1(struct sja1105_private *priv, + struct sja1105_port_status_hl1 *status, + int port) +{ + const struct sja1105_regs *regs = priv->info->regs; + u8 packed_buf[SIZE_HL1_AREA] = {0}; + int rc; + + rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl1[port], + packed_buf, SIZE_HL1_AREA); + if (rc < 0) + return rc; + + sja1105_port_status_hl1_unpack(packed_buf, status); + + return 0; +} + +static int sja1105_port_status_get_hl2(struct sja1105_private *priv, + struct sja1105_port_status_hl2 *status, + int port) +{ + const struct sja1105_regs *regs = priv->info->regs; + u8 packed_buf[SIZE_QLEVEL_AREA] = {0}; + int rc; + + rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl2[port], + packed_buf, SIZE_HL2_AREA); + if (rc < 0) + return rc; + + sja1105_port_status_hl2_unpack(packed_buf, status); + + if (IS_ET(priv->info->device_id)) + /* Code below is strictly P/Q/R/S specific. */ + return 0; + + rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->qlevel[port], + packed_buf, SIZE_QLEVEL_AREA); + if (rc < 0) + return rc; + + sja1105pqrs_port_status_qlevel_unpack(packed_buf, status); + + return 0; +} + +static int sja1105_port_status_get(struct sja1105_private *priv, + struct sja1105_port_status *status, + int port) +{ + int rc; + + rc = sja1105_port_status_get_mac(priv, &status->mac, port); + if (rc < 0) + return rc; + rc = sja1105_port_status_get_hl1(priv, &status->hl1, port); + if (rc < 0) + return rc; + rc = sja1105_port_status_get_hl2(priv, &status->hl2, port); + if (rc < 0) + return rc; + + return 0; +} + +static char sja1105_port_stats[][ETH_GSTRING_LEN] = { + /* MAC-Level Diagnostic Counters */ + "n_runt", + "n_soferr", + "n_alignerr", + "n_miierr", + /* MAC-Level Diagnostic Flags */ + "typeerr", + "sizeerr", + "tctimeout", + "priorerr", + "nomaster", + "memov", + "memerr", + "invtyp", + "intcyov", + "domerr", + "pcfbagdrop", + "spcprior", + "ageprior", + "portdrop", + "lendrop", + "bagdrop", + "policeerr", + "drpnona664err", + "spcerr", + "agedrp", + /* High-Level Diagnostic Counters */ + "n_n664err", + "n_vlanerr", + "n_unreleased", + "n_sizeerr", + "n_crcerr", + "n_vlnotfound", + "n_ctpolerr", + "n_polerr", + "n_rxfrm", + "n_rxbyte", + "n_txfrm", + "n_txbyte", + "n_qfull", + "n_part_drop", + "n_egr_disabled", + "n_not_reach", +}; + +static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = { + /* Queue Levels */ + "qlevel_hwm_0", + "qlevel_hwm_1", + "qlevel_hwm_2", + "qlevel_hwm_3", + "qlevel_hwm_4", + "qlevel_hwm_5", + "qlevel_hwm_6", + "qlevel_hwm_7", + "qlevel_0", + "qlevel_1", + "qlevel_2", + "qlevel_3", + "qlevel_4", + "qlevel_5", + "qlevel_6", + "qlevel_7", +}; + +void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_port_status status = {0}; + int rc, i, k = 0; + + rc = sja1105_port_status_get(priv, &status, port); + if (rc < 0) { + dev_err(ds->dev, "Failed to read port %d counters: %d\n", + port, rc); + return; + } + memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64)); + data[k++] = status.mac.n_runt; + data[k++] = status.mac.n_soferr; + data[k++] = status.mac.n_alignerr; + data[k++] = status.mac.n_miierr; + data[k++] = status.mac.typeerr; + data[k++] = status.mac.sizeerr; + data[k++] = status.mac.tctimeout; + data[k++] = status.mac.priorerr; + data[k++] = status.mac.nomaster; + data[k++] = status.mac.memov; + data[k++] = status.mac.memerr; + data[k++] = status.mac.invtyp; + data[k++] = status.mac.intcyov; + data[k++] = status.mac.domerr; + data[k++] = status.mac.pcfbagdrop; + data[k++] = status.mac.spcprior; + data[k++] = status.mac.ageprior; + data[k++] = status.mac.portdrop; + data[k++] = status.mac.lendrop; + data[k++] = status.mac.bagdrop; + data[k++] = status.mac.policeerr; + data[k++] = status.mac.drpnona664err; + data[k++] = status.mac.spcerr; + data[k++] = status.mac.agedrp; + data[k++] = status.hl1.n_n664err; + data[k++] = status.hl1.n_vlanerr; + data[k++] = status.hl1.n_unreleased; + data[k++] = status.hl1.n_sizeerr; + data[k++] = status.hl1.n_crcerr; + data[k++] = status.hl1.n_vlnotfound; + data[k++] = status.hl1.n_ctpolerr; + data[k++] = status.hl1.n_polerr; + data[k++] = status.hl1.n_rxfrm; + data[k++] = status.hl1.n_rxbyte; + data[k++] = status.hl1.n_txfrm; + data[k++] = status.hl1.n_txbyte; + data[k++] = status.hl2.n_qfull; + data[k++] = status.hl2.n_part_drop; + data[k++] = status.hl2.n_egr_disabled; + data[k++] = status.hl2.n_not_reach; + + if (!IS_PQRS(priv->info->device_id)) + return; + + memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) * + sizeof(u64)); + for (i = 0; i < 8; i++) { + data[k++] = status.hl2.qlevel_hwm[i]; + data[k++] = status.hl2.qlevel[i]; + } +} + +void sja1105_get_strings(struct dsa_switch *ds, int port, + u32 stringset, u8 *data) +{ + struct sja1105_private *priv = ds->priv; + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(sja1105_port_stats); i++) { + strlcpy(p, sja1105_port_stats[i], ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + if (!IS_PQRS(priv->info->device_id)) + return; + for (i = 0; i < ARRAY_SIZE(sja1105pqrs_extra_port_stats); i++) { + strlcpy(p, sja1105pqrs_extra_port_stats[i], + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset) +{ + int count = ARRAY_SIZE(sja1105_port_stats); + struct sja1105_private *priv = ds->priv; + + if (sset != ETH_SS_STATS) + return -EOPNOTSUPP; + + if (IS_PQRS(priv->info->device_id)) + count += ARRAY_SIZE(sja1105pqrs_extra_port_stats); + + return count; +} + diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index a0851d1c9d89..9d28436fe466 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1240,6 +1240,9 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .get_tag_protocol = sja1105_get_tag_protocol, .setup = sja1105_setup, .adjust_link = sja1105_adjust_link, + .get_strings = sja1105_get_strings, + .get_ethtool_stats = sja1105_get_ethtool_stats, + .get_sset_count = sja1105_get_sset_count, .port_fdb_dump = sja1105_fdb_dump, .port_fdb_add = sja1105_fdb_add, .port_fdb_del = sja1105_fdb_del, diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h index c71ef9d366db..395d817e5fed 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.h +++ b/drivers/net/dsa/sja1105/sja1105_static_config.h @@ -78,6 +78,27 @@ enum sja1105_blk_idx { #define SJA1105R_PART_NO 0x9A86 #define SJA1105S_PART_NO 0x9A87 +#define IS_PQRS(device_id) \ + (((device_id) == SJA1105PR_DEVICE_ID) || \ + ((device_id) == SJA1105QS_DEVICE_ID)) +#define IS_ET(device_id) \ + (((device_id) == SJA1105E_DEVICE_ID) || \ + ((device_id) == SJA1105T_DEVICE_ID)) +/* P and R have same Device ID, and differ by Part Number */ +#define IS_P(device_id, part_nr) \ + (((device_id) == SJA1105PR_DEVICE_ID) && \ + ((part_nr) == SJA1105P_PART_NR)) +#define IS_R(device_id, part_nr) \ + (((device_id) == SJA1105PR_DEVICE_ID) && \ + ((part_nr) == SJA1105R_PART_NR)) +/* Same do Q and S */ +#define IS_Q(device_id, part_nr) \ + (((device_id) == SJA1105QS_DEVICE_ID) && \ + ((part_nr) == SJA1105Q_PART_NR)) +#define IS_S(device_id, part_nr) \ + (((device_id) == SJA1105QS_DEVICE_ID) && \ + ((part_nr) == SJA1105S_PART_NR)) + struct sja1105_general_params_entry { u64 vllupformat; u64 mirr_ptacu;