1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Applied Micro X-Gene SoC Ethernet Driver
4 * Copyright (c) 2014, Applied Micro Circuits Corporation
5 * Authors: Iyappan Subramanian <isubramanian@apm.com>
8 #include <linux/ethtool.h>
9 #include "xgene_enet_main.h"
11 struct xgene_gstrings_stats
{
12 char name
[ETH_GSTRING_LEN
];
18 #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
19 #define XGENE_EXTD_STAT(s, a, m) \
26 static const struct xgene_gstrings_stats gstrings_stats
[] = {
27 XGENE_STAT(rx_packets
),
28 XGENE_STAT(tx_packets
),
31 XGENE_STAT(rx_errors
),
32 XGENE_STAT(tx_errors
),
33 XGENE_STAT(rx_length_errors
),
34 XGENE_STAT(rx_crc_errors
),
35 XGENE_STAT(rx_frame_errors
),
36 XGENE_STAT(rx_fifo_errors
)
39 static const struct xgene_gstrings_stats gstrings_extd_stats
[] = {
40 XGENE_EXTD_STAT(tx_rx_64b_frame_cntr
, TR64
, 31),
41 XGENE_EXTD_STAT(tx_rx_127b_frame_cntr
, TR127
, 31),
42 XGENE_EXTD_STAT(tx_rx_255b_frame_cntr
, TR255
, 31),
43 XGENE_EXTD_STAT(tx_rx_511b_frame_cntr
, TR511
, 31),
44 XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr
, TR1K
, 31),
45 XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr
, TRMAX
, 31),
46 XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr
, TRMGV
, 31),
47 XGENE_EXTD_STAT(rx_fcs_error_cntr
, RFCS
, 16),
48 XGENE_EXTD_STAT(rx_multicast_pkt_cntr
, RMCA
, 31),
49 XGENE_EXTD_STAT(rx_broadcast_pkt_cntr
, RBCA
, 31),
50 XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr
, RXCF
, 16),
51 XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr
, RXPF
, 16),
52 XGENE_EXTD_STAT(rx_unk_opcode_cntr
, RXUO
, 16),
53 XGENE_EXTD_STAT(rx_align_err_cntr
, RALN
, 16),
54 XGENE_EXTD_STAT(rx_frame_len_err_cntr
, RFLR
, 16),
55 XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr
, DUMP
, 0),
56 XGENE_EXTD_STAT(rx_code_err_cntr
, RCDE
, 16),
57 XGENE_EXTD_STAT(rx_carrier_sense_err_cntr
, RCSE
, 16),
58 XGENE_EXTD_STAT(rx_undersize_pkt_cntr
, RUND
, 16),
59 XGENE_EXTD_STAT(rx_oversize_pkt_cntr
, ROVR
, 16),
60 XGENE_EXTD_STAT(rx_fragments_cntr
, RFRG
, 16),
61 XGENE_EXTD_STAT(rx_jabber_cntr
, RJBR
, 16),
62 XGENE_EXTD_STAT(rx_jabber_recov_cntr
, DUMP
, 0),
63 XGENE_EXTD_STAT(rx_dropped_pkt_cntr
, RDRP
, 16),
64 XGENE_EXTD_STAT(rx_overrun_cntr
, DUMP
, 0),
65 XGENE_EXTD_STAT(tx_multicast_pkt_cntr
, TMCA
, 31),
66 XGENE_EXTD_STAT(tx_broadcast_pkt_cntr
, TBCA
, 31),
67 XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr
, TXPF
, 16),
68 XGENE_EXTD_STAT(tx_defer_pkt_cntr
, TDFR
, 31),
69 XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr
, TEDF
, 31),
70 XGENE_EXTD_STAT(tx_single_col_pkt_cntr
, TSCL
, 31),
71 XGENE_EXTD_STAT(tx_multi_col_pkt_cntr
, TMCL
, 31),
72 XGENE_EXTD_STAT(tx_late_col_pkt_cntr
, TLCL
, 31),
73 XGENE_EXTD_STAT(tx_excv_col_pkt_cntr
, TXCL
, 31),
74 XGENE_EXTD_STAT(tx_total_col_cntr
, TNCL
, 31),
75 XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr
, TPFH
, 16),
76 XGENE_EXTD_STAT(tx_drop_frame_cntr
, TDRP
, 16),
77 XGENE_EXTD_STAT(tx_jabber_frame_cntr
, TJBR
, 12),
78 XGENE_EXTD_STAT(tx_fcs_error_cntr
, TFCS
, 12),
79 XGENE_EXTD_STAT(tx_ctrl_frame_cntr
, TXCF
, 12),
80 XGENE_EXTD_STAT(tx_oversize_frame_cntr
, TOVR
, 12),
81 XGENE_EXTD_STAT(tx_undersize_frame_cntr
, TUND
, 12),
82 XGENE_EXTD_STAT(tx_fragments_cntr
, TFRG
, 12),
83 XGENE_EXTD_STAT(tx_underrun_cntr
, DUMP
, 0)
86 #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats)
87 #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats)
91 #define FALSE_RFLR_IDX 15
93 #define FALSE_RJBR_IDX 22
94 #define RX_OVERRUN_IDX 24
97 #define TX_UNDERRUN_IDX 43
99 static void xgene_get_drvinfo(struct net_device
*ndev
,
100 struct ethtool_drvinfo
*info
)
102 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
103 struct platform_device
*pdev
= pdata
->pdev
;
105 strcpy(info
->driver
, "xgene_enet");
106 sprintf(info
->bus_info
, "%s", pdev
->name
);
109 static int xgene_get_link_ksettings(struct net_device
*ndev
,
110 struct ethtool_link_ksettings
*cmd
)
112 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
113 struct phy_device
*phydev
= ndev
->phydev
;
116 if (phy_interface_mode_is_rgmii(pdata
->phy_mode
)) {
120 phy_ethtool_ksettings_get(phydev
, cmd
);
123 } else if (pdata
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
124 if (pdata
->mdio_driver
) {
128 phy_ethtool_ksettings_get(phydev
, cmd
);
133 supported
= SUPPORTED_1000baseT_Full
| SUPPORTED_Autoneg
|
135 ethtool_convert_legacy_u32_to_link_mode(
136 cmd
->link_modes
.supported
,
138 ethtool_convert_legacy_u32_to_link_mode(
139 cmd
->link_modes
.advertising
,
142 cmd
->base
.speed
= SPEED_1000
;
143 cmd
->base
.duplex
= DUPLEX_FULL
;
144 cmd
->base
.port
= PORT_MII
;
145 cmd
->base
.autoneg
= AUTONEG_ENABLE
;
147 supported
= SUPPORTED_10000baseT_Full
| SUPPORTED_FIBRE
;
148 ethtool_convert_legacy_u32_to_link_mode(
149 cmd
->link_modes
.supported
,
151 ethtool_convert_legacy_u32_to_link_mode(
152 cmd
->link_modes
.advertising
,
155 cmd
->base
.speed
= SPEED_10000
;
156 cmd
->base
.duplex
= DUPLEX_FULL
;
157 cmd
->base
.port
= PORT_FIBRE
;
158 cmd
->base
.autoneg
= AUTONEG_DISABLE
;
164 static int xgene_set_link_ksettings(struct net_device
*ndev
,
165 const struct ethtool_link_ksettings
*cmd
)
167 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
168 struct phy_device
*phydev
= ndev
->phydev
;
170 if (phy_interface_mode_is_rgmii(pdata
->phy_mode
)) {
174 return phy_ethtool_ksettings_set(phydev
, cmd
);
177 if (pdata
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
178 if (pdata
->mdio_driver
) {
182 return phy_ethtool_ksettings_set(phydev
, cmd
);
189 static void xgene_get_strings(struct net_device
*ndev
, u32 stringset
, u8
*data
)
194 if (stringset
!= ETH_SS_STATS
)
197 for (i
= 0; i
< XGENE_STATS_LEN
; i
++) {
198 memcpy(p
, gstrings_stats
[i
].name
, ETH_GSTRING_LEN
);
199 p
+= ETH_GSTRING_LEN
;
202 for (i
= 0; i
< XGENE_EXTD_STATS_LEN
; i
++) {
203 memcpy(p
, gstrings_extd_stats
[i
].name
, ETH_GSTRING_LEN
);
204 p
+= ETH_GSTRING_LEN
;
208 static int xgene_get_sset_count(struct net_device
*ndev
, int sset
)
210 if (sset
!= ETH_SS_STATS
)
213 return XGENE_STATS_LEN
+ XGENE_EXTD_STATS_LEN
;
216 static void xgene_get_extd_stats(struct xgene_enet_pdata
*pdata
)
218 u32 rx_drop
, tx_drop
;
222 for (i
= 0; i
< XGENE_EXTD_STATS_LEN
; i
++) {
223 tmp
= xgene_enet_rd_stat(pdata
, gstrings_extd_stats
[i
].addr
);
224 if (gstrings_extd_stats
[i
].mask
) {
225 mask
= GENMASK(gstrings_extd_stats
[i
].mask
- 1, 0);
226 pdata
->extd_stats
[i
] += (tmp
& mask
);
230 if (pdata
->phy_mode
== PHY_INTERFACE_MODE_XGMII
) {
231 /* Errata 10GE_10 - SW should intepret RALN as 0 */
232 pdata
->extd_stats
[RALN_IDX
] = 0;
234 /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
235 pdata
->extd_stats
[RFCS_IDX
] -= pdata
->extd_stats
[RALN_IDX
];
236 pdata
->extd_stats
[RFLR_IDX
] -= pdata
->extd_stats
[RUND_IDX
];
237 pdata
->extd_stats
[TFCS_IDX
] -= pdata
->extd_stats
[TFRG_IDX
];
240 pdata
->mac_ops
->get_drop_cnt(pdata
, &rx_drop
, &tx_drop
);
241 pdata
->extd_stats
[RX_OVERRUN_IDX
] += rx_drop
;
242 pdata
->extd_stats
[TX_UNDERRUN_IDX
] += tx_drop
;
244 /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */
245 pdata
->extd_stats
[FALSE_RFLR_IDX
] = pdata
->false_rflr
;
246 /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
247 pdata
->extd_stats
[FALSE_RJBR_IDX
] = pdata
->vlan_rjbr
;
250 int xgene_extd_stats_init(struct xgene_enet_pdata
*pdata
)
252 pdata
->extd_stats
= devm_kmalloc_array(&pdata
->pdev
->dev
,
253 XGENE_EXTD_STATS_LEN
, sizeof(u64
), GFP_KERNEL
);
254 if (!pdata
->extd_stats
)
257 xgene_get_extd_stats(pdata
);
258 memset(pdata
->extd_stats
, 0, XGENE_EXTD_STATS_LEN
* sizeof(u64
));
263 static void xgene_get_ethtool_stats(struct net_device
*ndev
,
264 struct ethtool_stats
*dummy
,
267 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
268 struct rtnl_link_stats64 stats
;
271 dev_get_stats(ndev
, &stats
);
272 for (i
= 0; i
< XGENE_STATS_LEN
; i
++)
273 data
[i
] = *(u64
*)((char *)&stats
+ gstrings_stats
[i
].offset
);
275 xgene_get_extd_stats(pdata
);
276 for (i
= 0; i
< XGENE_EXTD_STATS_LEN
; i
++)
277 data
[i
+ XGENE_STATS_LEN
] = pdata
->extd_stats
[i
];
280 static void xgene_get_pauseparam(struct net_device
*ndev
,
281 struct ethtool_pauseparam
*pp
)
283 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
285 pp
->autoneg
= pdata
->pause_autoneg
;
286 pp
->tx_pause
= pdata
->tx_pause
;
287 pp
->rx_pause
= pdata
->rx_pause
;
290 static int xgene_set_pauseparam(struct net_device
*ndev
,
291 struct ethtool_pauseparam
*pp
)
293 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
294 struct phy_device
*phydev
= ndev
->phydev
;
296 if (phy_interface_mode_is_rgmii(pdata
->phy_mode
) ||
297 pdata
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
301 if (!phy_validate_pause(phydev
, pp
))
304 pdata
->pause_autoneg
= pp
->autoneg
;
305 pdata
->tx_pause
= pp
->tx_pause
;
306 pdata
->rx_pause
= pp
->rx_pause
;
308 phy_set_asym_pause(phydev
, pp
->rx_pause
, pp
->tx_pause
);
311 pdata
->mac_ops
->flowctl_tx(pdata
, pdata
->tx_pause
);
312 pdata
->mac_ops
->flowctl_rx(pdata
, pdata
->rx_pause
);
318 pdata
->tx_pause
= pp
->tx_pause
;
319 pdata
->rx_pause
= pp
->rx_pause
;
321 pdata
->mac_ops
->flowctl_tx(pdata
, pdata
->tx_pause
);
322 pdata
->mac_ops
->flowctl_rx(pdata
, pdata
->rx_pause
);
328 static const struct ethtool_ops xgene_ethtool_ops
= {
329 .get_drvinfo
= xgene_get_drvinfo
,
330 .get_link
= ethtool_op_get_link
,
331 .get_strings
= xgene_get_strings
,
332 .get_sset_count
= xgene_get_sset_count
,
333 .get_ethtool_stats
= xgene_get_ethtool_stats
,
334 .get_link_ksettings
= xgene_get_link_ksettings
,
335 .set_link_ksettings
= xgene_set_link_ksettings
,
336 .get_pauseparam
= xgene_get_pauseparam
,
337 .set_pauseparam
= xgene_set_pauseparam
340 void xgene_enet_set_ethtool_ops(struct net_device
*ndev
)
342 ndev
->ethtool_ops
= &xgene_ethtool_ops
;