@@ -192,6 +192,8 @@ int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4],
192192 struct range * x_range , struct range * y_range ,
193193 int step_interval )
194194{
195+ int err ;
196+ int ret ;
195197 struct switchtec_diag_port_eye_start in = {
196198 .sub_cmd = MRPC_EYE_OBSERVE_START ,
197199 .lane_mask [0 ] = lane_mask [0 ],
@@ -207,7 +209,14 @@ int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4],
207209 .step_interval = step_interval ,
208210 };
209211
210- return switchtec_diag_eye_cmd (dev , & in , sizeof (in ));
212+ ret = switchtec_diag_eye_cmd (dev , & in , sizeof (in ));
213+
214+ /* Add delay so hardware has enough time to start */
215+ err = errno ;
216+ usleep (200000 );
217+ errno = err ;
218+
219+ return ret ;
211220}
212221
213222static uint64_t hi_lo_to_uint64 (uint32_t lo , uint32_t hi )
@@ -296,11 +305,20 @@ int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels,
296305 */
297306int switchtec_diag_eye_cancel (struct switchtec_dev * dev )
298307{
308+ int ret ;
309+ int err ;
299310 struct switchtec_diag_port_eye_cmd in = {
300311 .sub_cmd = MRPC_EYE_OBSERVE_CANCEL ,
301312 };
302313
303- return switchtec_diag_eye_cmd (dev , & in , sizeof (in ));
314+ ret = switchtec_diag_eye_cmd (dev , & in , sizeof (in ));
315+
316+ /* Add delay so hardware can stop completely */
317+ err = errno ;
318+ usleep (200000 );
319+ errno = err ;
320+
321+ return ret ;
304322}
305323
306324/**
@@ -844,7 +862,7 @@ int switchtec_diag_rcvr_ext(struct switchtec_dev *dev, int port_id,
844862int switchtec_diag_perm_table (struct switchtec_dev * dev ,
845863 struct switchtec_mrpc table [MRPC_MAX_ID ])
846864{
847- uint32_t perms [MRPC_MAX_ID / 32 ];
865+ uint32_t perms [( MRPC_MAX_ID + 31 ) / 32 ];
848866 int i , ret ;
849867
850868 ret = switchtec_cmd (dev , MRPC_MRPC_PERM_TABLE_GET , NULL , 0 ,
@@ -888,4 +906,125 @@ int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en)
888906 return switchtec_cmd (dev , MRPC_REFCLK_S , & cmd , sizeof (cmd ), NULL , 0 );
889907}
890908
909+ /**
910+ * @brief Get the LTSSM log of a port on a switchtec device
911+ * @param[in] dev Switchtec device handle
912+ * @param[in] port Switchtec Port
913+ * @param[inout] log_count number of log entries
914+ * @param[out] log A pointer to an array containing the log
915+ *
916+ */
917+ int switchtec_diag_ltssm_log (struct switchtec_dev * dev ,
918+ int port , int * log_count ,
919+ struct switchtec_diag_ltssm_log * log_data )
920+ {
921+ struct {
922+ uint8_t sub_cmd ;
923+ uint8_t port ;
924+ uint8_t freeze ;
925+ uint8_t unused ;
926+ } ltssm_freeze ;
927+
928+ struct {
929+ uint8_t sub_cmd ;
930+ uint8_t port ;
931+ } status ;
932+ struct {
933+ uint32_t w0_trigger_count ;
934+ uint32_t w1_trigger_count ;
935+ uint8_t log_num ;
936+ } status_output ;
937+
938+ struct {
939+ uint8_t sub_cmd ;
940+ uint8_t port ;
941+ uint8_t log_index ;
942+ uint8_t no_of_logs ;
943+ } log_dump ;
944+ struct {
945+ uint32_t dw0 ;
946+ uint32_t dw1 ;
947+ } log_dump_out [256 ];
948+
949+ uint32_t dw1 ;
950+ uint32_t dw0 ;
951+ int major ;
952+ int minor ;
953+ int rate ;
954+ int ret ;
955+ int i ;
956+
957+ /* freeze logs */
958+ ltssm_freeze .sub_cmd = 14 ;
959+ ltssm_freeze .port = port ;
960+ ltssm_freeze .freeze = 1 ;
961+
962+ ret = switchtec_cmd (dev , MRPC_DIAG_PORT_LTSSM_LOG , & ltssm_freeze ,
963+ sizeof (ltssm_freeze ), NULL , 0 );
964+ if (ret )
965+ return ret ;
966+
967+ /* get number of entries */
968+ status .sub_cmd = 13 ;
969+ status .port = port ;
970+ ret = switchtec_cmd (dev , MRPC_DIAG_PORT_LTSSM_LOG , & status ,
971+ sizeof (status ), & status_output ,
972+ sizeof (status_output ));
973+ if (ret )
974+ return ret ;
975+
976+ if (status_output .log_num < * log_count )
977+ * log_count = status_output .log_num ;
978+
979+ /* get log data */
980+ log_dump .sub_cmd = 15 ;
981+ log_dump .port = port ;
982+ log_dump .log_index = 0 ;
983+ log_dump .no_of_logs = * log_count ;
984+ if (log_dump .no_of_logs <= 126 ) {
985+ ret = switchtec_cmd (dev , MRPC_DIAG_PORT_LTSSM_LOG , & log_dump ,
986+ sizeof (log_dump ), log_dump_out ,
987+ 8 * log_dump .no_of_logs );
988+ if (ret )
989+ return ret ;
990+ } else {
991+ log_dump .no_of_logs = 126 ;
992+ ret = switchtec_cmd (dev , MRPC_DIAG_PORT_LTSSM_LOG , & log_dump ,
993+ sizeof (log_dump ), log_dump_out ,
994+ 8 * log_dump .no_of_logs );
995+ if (ret )
996+ return ret ;
997+
998+ log_dump .log_index = 126 ;
999+ log_dump .no_of_logs = * log_count - 126 ;
1000+
1001+ ret = switchtec_cmd (dev , MRPC_DIAG_PORT_LTSSM_LOG , & log_dump ,
1002+ sizeof (log_dump ), log_dump_out + 126 ,
1003+ 8 * log_dump .no_of_logs );
1004+ if (ret )
1005+ return ret ;
1006+ }
1007+ for (i = 0 ; i < * log_count ; i ++ ) {
1008+ dw1 = log_dump_out [i ].dw1 ;
1009+ dw0 = log_dump_out [i ].dw0 ;
1010+ rate = (dw0 >> 13 ) & 0x3 ;
1011+ major = (dw0 >> 7 ) & 0xf ;
1012+ minor = (dw0 >> 3 ) & 0xf ;
1013+
1014+ log_data [i ].timestamp = dw1 & 0x3ffffff ;
1015+ log_data [i ].link_rate = switchtec_gen_transfers [rate + 1 ];
1016+ log_data [i ].link_state = major | (minor << 8 );
1017+ }
1018+
1019+ /* unfreeze logs */
1020+ ltssm_freeze .sub_cmd = 14 ;
1021+ ltssm_freeze .port = port ;
1022+ ltssm_freeze .freeze = 0 ;
1023+
1024+ ret = switchtec_cmd (dev , MRPC_DIAG_PORT_LTSSM_LOG , & ltssm_freeze ,
1025+ sizeof (ltssm_freeze ), NULL , 0 );
1026+
1027+ return ret ;
1028+ }
1029+
8911030/**@}*/
0 commit comments