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 strcpy(info
->version
, XGENE_DRV_VERSION
);
107 snprintf(info
->fw_version
, ETHTOOL_FWVERS_LEN
, "N/A");
108 sprintf(info
->bus_info
, "%s", pdev
->name
);
111 static int xgene_get_link_ksettings(struct net_device
*ndev
,
112 struct ethtool_link_ksettings
*cmd
)
114 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
115 struct phy_device
*phydev
= ndev
->phydev
;
118 if (phy_interface_mode_is_rgmii(pdata
->phy_mode
)) {
122 phy_ethtool_ksettings_get(phydev
, cmd
);
125 } else if (pdata
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
126 if (pdata
->mdio_driver
) {
130 phy_ethtool_ksettings_get(phydev
, cmd
);
135 supported
= SUPPORTED_1000baseT_Full
| SUPPORTED_Autoneg
|
137 ethtool_convert_legacy_u32_to_link_mode(
138 cmd
->link_modes
.supported
,
140 ethtool_convert_legacy_u32_to_link_mode(
141 cmd
->link_modes
.advertising
,
144 cmd
->base
.speed
= SPEED_1000
;
145 cmd
->base
.duplex
= DUPLEX_FULL
;
146 cmd
->base
.port
= PORT_MII
;
147 cmd
->base
.autoneg
= AUTONEG_ENABLE
;
149 supported
= SUPPORTED_10000baseT_Full
| SUPPORTED_FIBRE
;
150 ethtool_convert_legacy_u32_to_link_mode(
151 cmd
->link_modes
.supported
,
153 ethtool_convert_legacy_u32_to_link_mode(
154 cmd
->link_modes
.advertising
,
157 cmd
->base
.speed
= SPEED_10000
;
158 cmd
->base
.duplex
= DUPLEX_FULL
;
159 cmd
->base
.port
= PORT_FIBRE
;
160 cmd
->base
.autoneg
= AUTONEG_DISABLE
;
166 static int xgene_set_link_ksettings(struct net_device
*ndev
,
167 const struct ethtool_link_ksettings
*cmd
)
169 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
170 struct phy_device
*phydev
= ndev
->phydev
;
172 if (phy_interface_mode_is_rgmii(pdata
->phy_mode
)) {
176 return phy_ethtool_ksettings_set(phydev
, cmd
);
179 if (pdata
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
180 if (pdata
->mdio_driver
) {
184 return phy_ethtool_ksettings_set(phydev
, cmd
);
191 static void xgene_get_strings(struct net_device
*ndev
, u32 stringset
, u8
*data
)
196 if (stringset
!= ETH_SS_STATS
)
199 for (i
= 0; i
< XGENE_STATS_LEN
; i
++) {
200 memcpy(p
, gstrings_stats
[i
].name
, ETH_GSTRING_LEN
);
201 p
+= ETH_GSTRING_LEN
;
204 for (i
= 0; i
< XGENE_EXTD_STATS_LEN
; i
++) {
205 memcpy(p
, gstrings_extd_stats
[i
].name
, ETH_GSTRING_LEN
);
206 p
+= ETH_GSTRING_LEN
;
210 static int xgene_get_sset_count(struct net_device
*ndev
, int sset
)
212 if (sset
!= ETH_SS_STATS
)
215 return XGENE_STATS_LEN
+ XGENE_EXTD_STATS_LEN
;
218 static void xgene_get_extd_stats(struct xgene_enet_pdata
*pdata
)
220 u32 rx_drop
, tx_drop
;
224 for (i
= 0; i
< XGENE_EXTD_STATS_LEN
; i
++) {
225 tmp
= xgene_enet_rd_stat(pdata
, gstrings_extd_stats
[i
].addr
);
226 if (gstrings_extd_stats
[i
].mask
) {
227 mask
= GENMASK(gstrings_extd_stats
[i
].mask
- 1, 0);
228 pdata
->extd_stats
[i
] += (tmp
& mask
);
232 if (pdata
->phy_mode
== PHY_INTERFACE_MODE_XGMII
) {
233 /* Errata 10GE_10 - SW should intepret RALN as 0 */
234 pdata
->extd_stats
[RALN_IDX
] = 0;
236 /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
237 pdata
->extd_stats
[RFCS_IDX
] -= pdata
->extd_stats
[RALN_IDX
];
238 pdata
->extd_stats
[RFLR_IDX
] -= pdata
->extd_stats
[RUND_IDX
];
239 pdata
->extd_stats
[TFCS_IDX
] -= pdata
->extd_stats
[TFRG_IDX
];
242 pdata
->mac_ops
->get_drop_cnt(pdata
, &rx_drop
, &tx_drop
);
243 pdata
->extd_stats
[RX_OVERRUN_IDX
] += rx_drop
;
244 pdata
->extd_stats
[TX_UNDERRUN_IDX
] += tx_drop
;
246 /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */
247 pdata
->extd_stats
[FALSE_RFLR_IDX
] = pdata
->false_rflr
;
248 /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
249 pdata
->extd_stats
[FALSE_RJBR_IDX
] = pdata
->vlan_rjbr
;
252 int xgene_extd_stats_init(struct xgene_enet_pdata
*pdata
)
254 pdata
->extd_stats
= devm_kmalloc_array(&pdata
->pdev
->dev
,
255 XGENE_EXTD_STATS_LEN
, sizeof(u64
), GFP_KERNEL
);
256 if (!pdata
->extd_stats
)
259 xgene_get_extd_stats(pdata
);
260 memset(pdata
->extd_stats
, 0, XGENE_EXTD_STATS_LEN
* sizeof(u64
));
265 static void xgene_get_ethtool_stats(struct net_device
*ndev
,
266 struct ethtool_stats
*dummy
,
269 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
270 struct rtnl_link_stats64 stats
;
273 dev_get_stats(ndev
, &stats
);
274 for (i
= 0; i
< XGENE_STATS_LEN
; i
++)
275 data
[i
] = *(u64
*)((char *)&stats
+ gstrings_stats
[i
].offset
);
277 xgene_get_extd_stats(pdata
);
278 for (i
= 0; i
< XGENE_EXTD_STATS_LEN
; i
++)
279 data
[i
+ XGENE_STATS_LEN
] = pdata
->extd_stats
[i
];
282 static void xgene_get_pauseparam(struct net_device
*ndev
,
283 struct ethtool_pauseparam
*pp
)
285 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
287 pp
->autoneg
= pdata
->pause_autoneg
;
288 pp
->tx_pause
= pdata
->tx_pause
;
289 pp
->rx_pause
= pdata
->rx_pause
;
292 static int xgene_set_pauseparam(struct net_device
*ndev
,
293 struct ethtool_pauseparam
*pp
)
295 struct xgene_enet_pdata
*pdata
= netdev_priv(ndev
);
296 struct phy_device
*phydev
= ndev
->phydev
;
298 if (phy_interface_mode_is_rgmii(pdata
->phy_mode
) ||
299 pdata
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
303 if (!phy_validate_pause(phydev
, pp
))
306 pdata
->pause_autoneg
= pp
->autoneg
;
307 pdata
->tx_pause
= pp
->tx_pause
;
308 pdata
->rx_pause
= pp
->rx_pause
;
310 phy_set_asym_pause(phydev
, pp
->rx_pause
, pp
->tx_pause
);
313 pdata
->mac_ops
->flowctl_tx(pdata
, pdata
->tx_pause
);
314 pdata
->mac_ops
->flowctl_rx(pdata
, pdata
->rx_pause
);
320 pdata
->tx_pause
= pp
->tx_pause
;
321 pdata
->rx_pause
= pp
->rx_pause
;
323 pdata
->mac_ops
->flowctl_tx(pdata
, pdata
->tx_pause
);
324 pdata
->mac_ops
->flowctl_rx(pdata
, pdata
->rx_pause
);
330 static const struct ethtool_ops xgene_ethtool_ops
= {
331 .get_drvinfo
= xgene_get_drvinfo
,
332 .get_link
= ethtool_op_get_link
,
333 .get_strings
= xgene_get_strings
,
334 .get_sset_count
= xgene_get_sset_count
,
335 .get_ethtool_stats
= xgene_get_ethtool_stats
,
336 .get_link_ksettings
= xgene_get_link_ksettings
,
337 .set_link_ksettings
= xgene_set_link_ksettings
,
338 .get_pauseparam
= xgene_get_pauseparam
,
339 .set_pauseparam
= xgene_set_pauseparam
342 void xgene_enet_set_ethtool_ops(struct net_device
*ndev
)
344 ndev
->ethtool_ops
= &xgene_ethtool_ops
;