1414#include <soc/mscc/ocelot.h>
1515#include "ocelot.h"
1616
17+ #define OCELOT_PTP_TX_TSTAMP_TIMEOUT (5 * HZ)
18+
1719int ocelot_ptp_gettime64 (struct ptp_clock_info * ptp , struct timespec64 * ts )
1820{
1921 struct ocelot * ocelot = container_of (ptp , struct ocelot , ptp_info );
@@ -495,6 +497,28 @@ static int ocelot_traps_to_ptp_rx_filter(unsigned int proto)
495497 return HWTSTAMP_FILTER_NONE ;
496498}
497499
500+ static int ocelot_ptp_tx_type_to_cmd (int tx_type , int * ptp_cmd )
501+ {
502+ switch (tx_type ) {
503+ case HWTSTAMP_TX_ON :
504+ * ptp_cmd = IFH_REW_OP_TWO_STEP_PTP ;
505+ break ;
506+ case HWTSTAMP_TX_ONESTEP_SYNC :
507+ /* IFH_REW_OP_ONE_STEP_PTP updates the correctionField,
508+ * what we need to update is the originTimestamp.
509+ */
510+ * ptp_cmd = IFH_REW_OP_ORIGIN_PTP ;
511+ break ;
512+ case HWTSTAMP_TX_OFF :
513+ * ptp_cmd = 0 ;
514+ break ;
515+ default :
516+ return - ERANGE ;
517+ }
518+
519+ return 0 ;
520+ }
521+
498522int ocelot_hwstamp_get (struct ocelot * ocelot , int port , struct ifreq * ifr )
499523{
500524 struct ocelot_port * ocelot_port = ocelot -> ports [port ];
@@ -521,30 +545,19 @@ EXPORT_SYMBOL(ocelot_hwstamp_get);
521545int ocelot_hwstamp_set (struct ocelot * ocelot , int port , struct ifreq * ifr )
522546{
523547 struct ocelot_port * ocelot_port = ocelot -> ports [port ];
548+ int ptp_cmd , old_ptp_cmd = ocelot_port -> ptp_cmd ;
524549 bool l2 = false, l4 = false;
525550 struct hwtstamp_config cfg ;
551+ bool old_l2 , old_l4 ;
526552 int err ;
527553
528554 if (copy_from_user (& cfg , ifr -> ifr_data , sizeof (cfg )))
529555 return - EFAULT ;
530556
531557 /* Tx type sanity check */
532- switch (cfg .tx_type ) {
533- case HWTSTAMP_TX_ON :
534- ocelot_port -> ptp_cmd = IFH_REW_OP_TWO_STEP_PTP ;
535- break ;
536- case HWTSTAMP_TX_ONESTEP_SYNC :
537- /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
538- * need to update the origin time.
539- */
540- ocelot_port -> ptp_cmd = IFH_REW_OP_ORIGIN_PTP ;
541- break ;
542- case HWTSTAMP_TX_OFF :
543- ocelot_port -> ptp_cmd = 0 ;
544- break ;
545- default :
546- return - ERANGE ;
547- }
558+ err = ocelot_ptp_tx_type_to_cmd (cfg .tx_type , & ptp_cmd );
559+ if (err )
560+ return err ;
548561
549562 switch (cfg .rx_filter ) {
550563 case HWTSTAMP_FILTER_NONE :
@@ -569,13 +582,27 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
569582 return - ERANGE ;
570583 }
571584
585+ old_l2 = ocelot_port -> trap_proto & OCELOT_PROTO_PTP_L2 ;
586+ old_l4 = ocelot_port -> trap_proto & OCELOT_PROTO_PTP_L4 ;
587+
572588 err = ocelot_setup_ptp_traps (ocelot , port , l2 , l4 );
573589 if (err )
574590 return err ;
575591
592+ ocelot_port -> ptp_cmd = ptp_cmd ;
593+
576594 cfg .rx_filter = ocelot_traps_to_ptp_rx_filter (ocelot_port -> trap_proto );
577595
578- return copy_to_user (ifr -> ifr_data , & cfg , sizeof (cfg )) ? - EFAULT : 0 ;
596+ if (copy_to_user (ifr -> ifr_data , & cfg , sizeof (cfg ))) {
597+ err = - EFAULT ;
598+ goto out_restore_ptp_traps ;
599+ }
600+
601+ return 0 ;
602+ out_restore_ptp_traps :
603+ ocelot_setup_ptp_traps (ocelot , port , old_l2 , old_l4 );
604+ ocelot_port -> ptp_cmd = old_ptp_cmd ;
605+ return err ;
579606}
580607EXPORT_SYMBOL (ocelot_hwstamp_set );
581608
@@ -603,34 +630,87 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
603630}
604631EXPORT_SYMBOL (ocelot_get_ts_info );
605632
606- static int ocelot_port_add_txtstamp_skb (struct ocelot * ocelot , int port ,
607- struct sk_buff * clone )
633+ static struct sk_buff * ocelot_port_dequeue_ptp_tx_skb (struct ocelot * ocelot ,
634+ int port , u8 ts_id ,
635+ u32 seqid )
608636{
609637 struct ocelot_port * ocelot_port = ocelot -> ports [port ];
610- unsigned long flags ;
638+ struct sk_buff * skb , * skb_tmp , * skb_match = NULL ;
639+ struct ptp_header * hdr ;
611640
612- spin_lock_irqsave (& ocelot -> ts_id_lock , flags );
641+ spin_lock (& ocelot -> ts_id_lock );
613642
614- if (ocelot_port -> ptp_skbs_in_flight == OCELOT_MAX_PTP_ID ||
615- ocelot -> ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE ) {
616- spin_unlock_irqrestore (& ocelot -> ts_id_lock , flags );
617- return - EBUSY ;
643+ skb_queue_walk_safe (& ocelot_port -> tx_skbs , skb , skb_tmp ) {
644+ if (OCELOT_SKB_CB (skb )-> ts_id != ts_id )
645+ continue ;
646+
647+ /* Check that the timestamp ID is for the expected PTP
648+ * sequenceId. We don't have to test ptp_parse_header() against
649+ * NULL, because we've pre-validated the packet's ptp_class.
650+ */
651+ hdr = ptp_parse_header (skb , OCELOT_SKB_CB (skb )-> ptp_class );
652+ if (seqid != ntohs (hdr -> sequence_id ))
653+ continue ;
654+
655+ __skb_unlink (skb , & ocelot_port -> tx_skbs );
656+ ocelot -> ptp_skbs_in_flight -- ;
657+ skb_match = skb ;
658+ break ;
618659 }
619660
620- skb_shinfo (clone )-> tx_flags |= SKBTX_IN_PROGRESS ;
621- /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
622- OCELOT_SKB_CB (clone )-> ts_id = ocelot_port -> ts_id ;
661+ spin_unlock (& ocelot -> ts_id_lock );
623662
624- ocelot_port -> ts_id ++ ;
625- if (ocelot_port -> ts_id == OCELOT_MAX_PTP_ID )
626- ocelot_port -> ts_id = 0 ;
663+ return skb_match ;
664+ }
665+
666+ static int ocelot_port_queue_ptp_tx_skb (struct ocelot * ocelot , int port ,
667+ struct sk_buff * clone )
668+ {
669+ struct ocelot_port * ocelot_port = ocelot -> ports [port ];
670+ DECLARE_BITMAP (ts_id_in_flight , OCELOT_MAX_PTP_ID );
671+ struct sk_buff * skb , * skb_tmp ;
672+ unsigned long n ;
673+
674+ spin_lock (& ocelot -> ts_id_lock );
675+
676+ /* To get a better chance of acquiring a timestamp ID, first flush the
677+ * stale packets still waiting in the TX timestamping queue. They are
678+ * probably lost.
679+ */
680+ skb_queue_walk_safe (& ocelot_port -> tx_skbs , skb , skb_tmp ) {
681+ if (time_before (OCELOT_SKB_CB (skb )-> ptp_tx_time +
682+ OCELOT_PTP_TX_TSTAMP_TIMEOUT , jiffies )) {
683+ dev_warn_ratelimited (ocelot -> dev ,
684+ "port %d invalidating stale timestamp ID %u which seems lost\n" ,
685+ port , OCELOT_SKB_CB (skb )-> ts_id );
686+ __skb_unlink (skb , & ocelot_port -> tx_skbs );
687+ kfree_skb (skb );
688+ ocelot -> ptp_skbs_in_flight -- ;
689+ } else {
690+ __set_bit (OCELOT_SKB_CB (skb )-> ts_id , ts_id_in_flight );
691+ }
692+ }
693+
694+ if (ocelot -> ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE ) {
695+ spin_unlock (& ocelot -> ts_id_lock );
696+ return - EBUSY ;
697+ }
698+
699+ n = find_first_zero_bit (ts_id_in_flight , OCELOT_MAX_PTP_ID );
700+ if (n == OCELOT_MAX_PTP_ID ) {
701+ spin_unlock (& ocelot -> ts_id_lock );
702+ return - EBUSY ;
703+ }
627704
628- ocelot_port -> ptp_skbs_in_flight ++ ;
705+ /* Found an available timestamp ID, use it */
706+ OCELOT_SKB_CB (clone )-> ts_id = n ;
707+ OCELOT_SKB_CB (clone )-> ptp_tx_time = jiffies ;
629708 ocelot -> ptp_skbs_in_flight ++ ;
709+ __skb_queue_tail (& ocelot_port -> tx_skbs , clone );
630710
631- skb_queue_tail ( & ocelot_port -> tx_skbs , clone );
711+ spin_unlock ( & ocelot -> ts_id_lock );
632712
633- spin_unlock_irqrestore ( & ocelot -> ts_id_lock , flags );
713+ dev_dbg_ratelimited ( ocelot -> dev , "port %d timestamp id %lu\n" , port , n );
634714
635715 return 0 ;
636716}
@@ -687,10 +767,14 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
687767 if (!(* clone ))
688768 return - ENOMEM ;
689769
690- err = ocelot_port_add_txtstamp_skb (ocelot , port , * clone );
691- if (err )
770+ /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
771+ err = ocelot_port_queue_ptp_tx_skb (ocelot , port , * clone );
772+ if (err ) {
773+ kfree_skb (* clone );
692774 return err ;
775+ }
693776
777+ skb_shinfo (* clone )-> tx_flags |= SKBTX_IN_PROGRESS ;
694778 OCELOT_SKB_CB (skb )-> ptp_cmd = ptp_cmd ;
695779 OCELOT_SKB_CB (* clone )-> ptp_class = ptp_class ;
696780 }
@@ -726,28 +810,15 @@ static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
726810 spin_unlock_irqrestore (& ocelot -> ptp_clock_lock , flags );
727811}
728812
729- static bool ocelot_validate_ptp_skb (struct sk_buff * clone , u16 seqid )
730- {
731- struct ptp_header * hdr ;
732-
733- hdr = ptp_parse_header (clone , OCELOT_SKB_CB (clone )-> ptp_class );
734- if (WARN_ON (!hdr ))
735- return false;
736-
737- return seqid == ntohs (hdr -> sequence_id );
738- }
739-
740813void ocelot_get_txtstamp (struct ocelot * ocelot )
741814{
742815 int budget = OCELOT_PTP_QUEUE_SZ ;
743816
744817 while (budget -- ) {
745- struct sk_buff * skb , * skb_tmp , * skb_match = NULL ;
746818 struct skb_shared_hwtstamps shhwtstamps ;
747819 u32 val , id , seqid , txport ;
748- struct ocelot_port * port ;
820+ struct sk_buff * skb_match ;
749821 struct timespec64 ts ;
750- unsigned long flags ;
751822
752823 val = ocelot_read (ocelot , SYS_PTP_STATUS );
753824
@@ -762,36 +833,14 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
762833 txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X (val );
763834 seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID (val );
764835
765- port = ocelot -> ports [txport ];
766-
767- spin_lock (& ocelot -> ts_id_lock );
768- port -> ptp_skbs_in_flight -- ;
769- ocelot -> ptp_skbs_in_flight -- ;
770- spin_unlock (& ocelot -> ts_id_lock );
771-
772836 /* Retrieve its associated skb */
773- try_again :
774- spin_lock_irqsave (& port -> tx_skbs .lock , flags );
775-
776- skb_queue_walk_safe (& port -> tx_skbs , skb , skb_tmp ) {
777- if (OCELOT_SKB_CB (skb )-> ts_id != id )
778- continue ;
779- __skb_unlink (skb , & port -> tx_skbs );
780- skb_match = skb ;
781- break ;
782- }
783-
784- spin_unlock_irqrestore (& port -> tx_skbs .lock , flags );
785-
786- if (WARN_ON (!skb_match ))
787- continue ;
788-
789- if (!ocelot_validate_ptp_skb (skb_match , seqid )) {
790- dev_err_ratelimited (ocelot -> dev ,
791- "port %d received stale TX timestamp for seqid %d, discarding\n" ,
792- txport , seqid );
793- dev_kfree_skb_any (skb );
794- goto try_again ;
837+ skb_match = ocelot_port_dequeue_ptp_tx_skb (ocelot , txport , id ,
838+ seqid );
839+ if (!skb_match ) {
840+ dev_warn_ratelimited (ocelot -> dev ,
841+ "port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n" ,
842+ txport , seqid , id );
843+ goto next_ts ;
795844 }
796845
797846 /* Get the h/w timestamp */
@@ -802,7 +851,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
802851 shhwtstamps .hwtstamp = ktime_set (ts .tv_sec , ts .tv_nsec );
803852 skb_complete_tx_timestamp (skb_match , & shhwtstamps );
804853
805- /* Next ts */
854+ next_ts :
806855 ocelot_write (ocelot , SYS_PTP_NXT_PTP_NXT , SYS_PTP_NXT );
807856 }
808857}
0 commit comments