@@ -66,6 +66,8 @@ static const unsigned int otx2_n_dev_stats = ARRAY_SIZE(otx2_dev_stats);
6666static const unsigned int otx2_n_drv_stats = ARRAY_SIZE (otx2_drv_stats );
6767static const unsigned int otx2_n_queue_stats = ARRAY_SIZE (otx2_queue_stats );
6868
69+ static struct cgx_fw_data * otx2_get_fwdata (struct otx2_nic * pfvf );
70+
6971static void otx2_get_drvinfo (struct net_device * netdev ,
7072 struct ethtool_drvinfo * info )
7173{
@@ -128,6 +130,10 @@ static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
128130
129131 strcpy (data , "reset_count" );
130132 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 ;
131137}
132138
133139static void otx2_get_qset_stats (struct otx2_nic * pfvf ,
@@ -160,11 +166,30 @@ static void otx2_get_qset_stats(struct otx2_nic *pfvf,
160166 }
161167}
162168
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+
163186/* Get device and per queue statistics */
164187static void otx2_get_ethtool_stats (struct net_device * netdev ,
165188 struct ethtool_stats * stats , u64 * data )
166189{
167190 struct otx2_nic * pfvf = netdev_priv (netdev );
191+ u64 fec_corr_blks , fec_uncorr_blks ;
192+ struct cgx_fw_data * rsp ;
168193 int stat ;
169194
170195 otx2_get_dev_stats (pfvf );
@@ -183,6 +208,32 @@ static void otx2_get_ethtool_stats(struct net_device *netdev,
183208 for (stat = 0 ; stat < CGX_TX_STATS_COUNT ; stat ++ )
184209 * (data ++ ) = pfvf -> hw .cgx_tx_stats [stat ];
185210 * (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 ;
186237}
187238
188239static 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)
195246
196247 qstats_count = otx2_n_queue_stats *
197248 (pfvf -> hw .rx_queues + pfvf -> hw .tx_queues );
249+ otx2_update_lmac_fec_stats (pfvf );
198250
199251 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 ;
201254}
202255
203256/* Get no of queues device supports and current queue count */
@@ -859,6 +912,109 @@ static int otx2_get_ts_info(struct net_device *netdev,
859912 return 0 ;
860913}
861914
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+
8621018static const struct ethtool_ops otx2_ethtool_ops = {
8631019 .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
8641020 ETHTOOL_COALESCE_MAX_FRAMES ,
@@ -886,6 +1042,8 @@ static const struct ethtool_ops otx2_ethtool_ops = {
8861042 .get_pauseparam = otx2_get_pauseparam ,
8871043 .set_pauseparam = otx2_set_pauseparam ,
8881044 .get_ts_info = otx2_get_ts_info ,
1045+ .get_fecparam = otx2_get_fecparam ,
1046+ .set_fecparam = otx2_set_fecparam ,
8891047};
8901048
8911049void otx2_set_ethtool_ops (struct net_device * netdev )
0 commit comments