@@ -66,6 +66,8 @@ static const unsigned int otx2_n_dev_stats = ARRAY_SIZE(otx2_dev_stats);
66
66
static const unsigned int otx2_n_drv_stats = ARRAY_SIZE (otx2_drv_stats );
67
67
static const unsigned int otx2_n_queue_stats = ARRAY_SIZE (otx2_queue_stats );
68
68
69
+ static struct cgx_fw_data * otx2_get_fwdata (struct otx2_nic * pfvf );
70
+
69
71
static void otx2_get_drvinfo (struct net_device * netdev ,
70
72
struct ethtool_drvinfo * info )
71
73
{
@@ -128,6 +130,10 @@ static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
128
130
129
131
strcpy (data , "reset_count" );
130
132
data += ETH_GSTRING_LEN ;
133
+ sprintf (data , "Fec Corrected Errors: " );
134
+ data += ETH_GSTRING_LEN ;
135
+ sprintf (data , "Fec Uncorrected Errors: " );
136
+ data += ETH_GSTRING_LEN ;
131
137
}
132
138
133
139
static void otx2_get_qset_stats (struct otx2_nic * pfvf ,
@@ -160,11 +166,30 @@ static void otx2_get_qset_stats(struct otx2_nic *pfvf,
160
166
}
161
167
}
162
168
169
+ static int otx2_get_phy_fec_stats (struct otx2_nic * pfvf )
170
+ {
171
+ struct msg_req * req ;
172
+ int rc = - ENOMEM ;
173
+
174
+ mutex_lock (& pfvf -> mbox .lock );
175
+ req = otx2_mbox_alloc_msg_cgx_get_phy_fec_stats (& pfvf -> mbox );
176
+ if (!req )
177
+ goto end ;
178
+
179
+ if (!otx2_sync_mbox_msg (& pfvf -> mbox ))
180
+ rc = 0 ;
181
+ end :
182
+ mutex_unlock (& pfvf -> mbox .lock );
183
+ return rc ;
184
+ }
185
+
163
186
/* Get device and per queue statistics */
164
187
static void otx2_get_ethtool_stats (struct net_device * netdev ,
165
188
struct ethtool_stats * stats , u64 * data )
166
189
{
167
190
struct otx2_nic * pfvf = netdev_priv (netdev );
191
+ u64 fec_corr_blks , fec_uncorr_blks ;
192
+ struct cgx_fw_data * rsp ;
168
193
int stat ;
169
194
170
195
otx2_get_dev_stats (pfvf );
@@ -183,6 +208,32 @@ static void otx2_get_ethtool_stats(struct net_device *netdev,
183
208
for (stat = 0 ; stat < CGX_TX_STATS_COUNT ; stat ++ )
184
209
* (data ++ ) = pfvf -> hw .cgx_tx_stats [stat ];
185
210
* (data ++ ) = pfvf -> reset_count ;
211
+
212
+ fec_corr_blks = pfvf -> hw .cgx_fec_corr_blks ;
213
+ fec_uncorr_blks = pfvf -> hw .cgx_fec_uncorr_blks ;
214
+
215
+ rsp = otx2_get_fwdata (pfvf );
216
+ if (!IS_ERR (rsp ) && rsp -> fwdata .phy .misc .has_fec_stats &&
217
+ !otx2_get_phy_fec_stats (pfvf )) {
218
+ /* Fetch fwdata again because it's been recently populated with
219
+ * latest PHY FEC stats.
220
+ */
221
+ rsp = otx2_get_fwdata (pfvf );
222
+ if (!IS_ERR (rsp )) {
223
+ struct fec_stats_s * p = & rsp -> fwdata .phy .fec_stats ;
224
+
225
+ if (pfvf -> linfo .fec == OTX2_FEC_BASER ) {
226
+ fec_corr_blks = p -> brfec_corr_blks ;
227
+ fec_uncorr_blks = p -> brfec_uncorr_blks ;
228
+ } else {
229
+ fec_corr_blks = p -> rsfec_corr_cws ;
230
+ fec_uncorr_blks = p -> rsfec_uncorr_cws ;
231
+ }
232
+ }
233
+ }
234
+
235
+ * (data ++ ) = fec_corr_blks ;
236
+ * (data ++ ) = fec_uncorr_blks ;
186
237
}
187
238
188
239
static int otx2_get_sset_count (struct net_device * netdev , int sset )
@@ -195,9 +246,11 @@ static int otx2_get_sset_count(struct net_device *netdev, int sset)
195
246
196
247
qstats_count = otx2_n_queue_stats *
197
248
(pfvf -> hw .rx_queues + pfvf -> hw .tx_queues );
249
+ otx2_update_lmac_fec_stats (pfvf );
198
250
199
251
return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count +
200
- CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT + 1 ;
252
+ CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT + OTX2_FEC_STATS_CNT
253
+ + 1 ;
201
254
}
202
255
203
256
/* Get no of queues device supports and current queue count */
@@ -859,6 +912,109 @@ static int otx2_get_ts_info(struct net_device *netdev,
859
912
return 0 ;
860
913
}
861
914
915
+ static struct cgx_fw_data * otx2_get_fwdata (struct otx2_nic * pfvf )
916
+ {
917
+ struct cgx_fw_data * rsp = NULL ;
918
+ struct msg_req * req ;
919
+ int err = 0 ;
920
+
921
+ mutex_lock (& pfvf -> mbox .lock );
922
+ req = otx2_mbox_alloc_msg_cgx_get_aux_link_info (& pfvf -> mbox );
923
+ if (!req ) {
924
+ mutex_unlock (& pfvf -> mbox .lock );
925
+ return ERR_PTR (- ENOMEM );
926
+ }
927
+
928
+ err = otx2_sync_mbox_msg (& pfvf -> mbox );
929
+ if (!err ) {
930
+ rsp = (struct cgx_fw_data * )
931
+ otx2_mbox_get_rsp (& pfvf -> mbox .mbox , 0 , & req -> hdr );
932
+ } else {
933
+ rsp = ERR_PTR (err );
934
+ }
935
+
936
+ mutex_unlock (& pfvf -> mbox .lock );
937
+ return rsp ;
938
+ }
939
+
940
+ static int otx2_get_fecparam (struct net_device * netdev ,
941
+ struct ethtool_fecparam * fecparam )
942
+ {
943
+ struct otx2_nic * pfvf = netdev_priv (netdev );
944
+ struct cgx_fw_data * rsp ;
945
+ const int fec [] = {
946
+ ETHTOOL_FEC_OFF ,
947
+ ETHTOOL_FEC_BASER ,
948
+ ETHTOOL_FEC_RS ,
949
+ ETHTOOL_FEC_BASER | ETHTOOL_FEC_RS };
950
+ #define FEC_MAX_INDEX 4
951
+ if (pfvf -> linfo .fec < FEC_MAX_INDEX )
952
+ fecparam -> active_fec = fec [pfvf -> linfo .fec ];
953
+
954
+ rsp = otx2_get_fwdata (pfvf );
955
+ if (IS_ERR (rsp ))
956
+ return PTR_ERR (rsp );
957
+
958
+ if (rsp -> fwdata .supported_fec <= FEC_MAX_INDEX ) {
959
+ if (!rsp -> fwdata .supported_fec )
960
+ fecparam -> fec = ETHTOOL_FEC_NONE ;
961
+ else
962
+ fecparam -> fec = fec [rsp -> fwdata .supported_fec ];
963
+ }
964
+ return 0 ;
965
+ }
966
+
967
+ static int otx2_set_fecparam (struct net_device * netdev ,
968
+ struct ethtool_fecparam * fecparam )
969
+ {
970
+ struct otx2_nic * pfvf = netdev_priv (netdev );
971
+ struct mbox * mbox = & pfvf -> mbox ;
972
+ struct fec_mode * req , * rsp ;
973
+ int err = 0 , fec = 0 ;
974
+
975
+ switch (fecparam -> fec ) {
976
+ /* Firmware does not support AUTO mode consider it as FEC_OFF */
977
+ case ETHTOOL_FEC_OFF :
978
+ case ETHTOOL_FEC_AUTO :
979
+ fec = OTX2_FEC_OFF ;
980
+ break ;
981
+ case ETHTOOL_FEC_RS :
982
+ fec = OTX2_FEC_RS ;
983
+ break ;
984
+ case ETHTOOL_FEC_BASER :
985
+ fec = OTX2_FEC_BASER ;
986
+ break ;
987
+ default :
988
+ netdev_warn (pfvf -> netdev , "Unsupported FEC mode: %d" ,
989
+ fecparam -> fec );
990
+ return - EINVAL ;
991
+ }
992
+
993
+ if (fec == pfvf -> linfo .fec )
994
+ return 0 ;
995
+
996
+ mutex_lock (& mbox -> lock );
997
+ req = otx2_mbox_alloc_msg_cgx_set_fec_param (& pfvf -> mbox );
998
+ if (!req ) {
999
+ err = - ENOMEM ;
1000
+ goto end ;
1001
+ }
1002
+ req -> fec = fec ;
1003
+ err = otx2_sync_mbox_msg (& pfvf -> mbox );
1004
+ if (err )
1005
+ goto end ;
1006
+
1007
+ rsp = (struct fec_mode * )otx2_mbox_get_rsp (& pfvf -> mbox .mbox ,
1008
+ 0 , & req -> hdr );
1009
+ if (rsp -> fec >= 0 )
1010
+ pfvf -> linfo .fec = rsp -> fec ;
1011
+ else
1012
+ err = rsp -> fec ;
1013
+ end :
1014
+ mutex_unlock (& mbox -> lock );
1015
+ return err ;
1016
+ }
1017
+
862
1018
static const struct ethtool_ops otx2_ethtool_ops = {
863
1019
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
864
1020
ETHTOOL_COALESCE_MAX_FRAMES ,
@@ -886,6 +1042,8 @@ static const struct ethtool_ops otx2_ethtool_ops = {
886
1042
.get_pauseparam = otx2_get_pauseparam ,
887
1043
.set_pauseparam = otx2_set_pauseparam ,
888
1044
.get_ts_info = otx2_get_ts_info ,
1045
+ .get_fecparam = otx2_get_fecparam ,
1046
+ .set_fecparam = otx2_set_fecparam ,
889
1047
};
890
1048
891
1049
void otx2_set_ethtool_ops (struct net_device * netdev )
0 commit comments