20
20
#include <net/pkt_cls.h>
21
21
#include <net/sch_generic.h>
22
22
23
+ static LIST_HEAD (taprio_list );
24
+ static DEFINE_SPINLOCK (taprio_list_lock );
25
+
23
26
#define TAPRIO_ALL_GATES_OPEN -1
24
27
25
28
struct sched_entry {
@@ -42,9 +45,9 @@ struct taprio_sched {
42
45
struct Qdisc * root ;
43
46
s64 base_time ;
44
47
int clockid ;
45
- int picos_per_byte ; /* Using picoseconds because for 10Gbps+
46
- * speeds it's sub-nanoseconds per byte
47
- */
48
+ atomic64_t picos_per_byte ; /* Using picoseconds because for 10Gbps+
49
+ * speeds it's sub-nanoseconds per byte
50
+ */
48
51
size_t num_entries ;
49
52
50
53
/* Protects the update side of the RCU protected current_entry */
@@ -53,6 +56,7 @@ struct taprio_sched {
53
56
struct list_head entries ;
54
57
ktime_t (* get_time )(void );
55
58
struct hrtimer advance_timer ;
59
+ struct list_head taprio_list ;
56
60
};
57
61
58
62
static int taprio_enqueue (struct sk_buff * skb , struct Qdisc * sch ,
@@ -117,7 +121,7 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch)
117
121
118
122
static inline int length_to_duration (struct taprio_sched * q , int len )
119
123
{
120
- return (len * q -> picos_per_byte ) / 1000 ;
124
+ return (len * atomic64_read ( & q -> picos_per_byte ) ) / 1000 ;
121
125
}
122
126
123
127
static struct sk_buff * taprio_dequeue (struct Qdisc * sch )
@@ -129,6 +133,11 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
129
133
u32 gate_mask ;
130
134
int i ;
131
135
136
+ if (atomic64_read (& q -> picos_per_byte ) == -1 ) {
137
+ WARN_ONCE (1 , "taprio: dequeue() called with unknown picos per byte." );
138
+ return NULL ;
139
+ }
140
+
132
141
rcu_read_lock ();
133
142
entry = rcu_dereference (q -> current_entry );
134
143
/* if there's no entry, it means that the schedule didn't
@@ -233,7 +242,7 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer)
233
242
234
243
next -> close_time = close_time ;
235
244
atomic_set (& next -> budget ,
236
- (next -> interval * 1000 ) / q -> picos_per_byte );
245
+ (next -> interval * 1000 ) / atomic64_read ( & q -> picos_per_byte ) );
237
246
238
247
first_run :
239
248
rcu_assign_pointer (q -> current_entry , next );
@@ -567,24 +576,69 @@ static void taprio_start_sched(struct Qdisc *sch, ktime_t start)
567
576
568
577
first -> close_time = ktime_add_ns (start , first -> interval );
569
578
atomic_set (& first -> budget ,
570
- (first -> interval * 1000 ) / q -> picos_per_byte );
579
+ (first -> interval * 1000 ) /
580
+ atomic64_read (& q -> picos_per_byte ));
571
581
rcu_assign_pointer (q -> current_entry , NULL );
572
582
573
583
spin_unlock_irqrestore (& q -> current_entry_lock , flags );
574
584
575
585
hrtimer_start (& q -> advance_timer , start , HRTIMER_MODE_ABS );
576
586
}
577
587
588
+ static void taprio_set_picos_per_byte (struct net_device * dev ,
589
+ struct taprio_sched * q )
590
+ {
591
+ struct ethtool_link_ksettings ecmd ;
592
+ int picos_per_byte = -1 ;
593
+
594
+ if (!__ethtool_get_link_ksettings (dev , & ecmd ) &&
595
+ ecmd .base .speed != SPEED_UNKNOWN )
596
+ picos_per_byte = div64_s64 (NSEC_PER_SEC * 1000LL * 8 ,
597
+ ecmd .base .speed * 1000 * 1000 );
598
+
599
+ atomic64_set (& q -> picos_per_byte , picos_per_byte );
600
+ netdev_dbg (dev , "taprio: set %s's picos_per_byte to: %lld, linkspeed: %d\n" ,
601
+ dev -> name , (long long )atomic64_read (& q -> picos_per_byte ),
602
+ ecmd .base .speed );
603
+ }
604
+
605
+ static int taprio_dev_notifier (struct notifier_block * nb , unsigned long event ,
606
+ void * ptr )
607
+ {
608
+ struct net_device * dev = netdev_notifier_info_to_dev (ptr );
609
+ struct net_device * qdev ;
610
+ struct taprio_sched * q ;
611
+ bool found = false;
612
+
613
+ ASSERT_RTNL ();
614
+
615
+ if (event != NETDEV_UP && event != NETDEV_CHANGE )
616
+ return NOTIFY_DONE ;
617
+
618
+ spin_lock (& taprio_list_lock );
619
+ list_for_each_entry (q , & taprio_list , taprio_list ) {
620
+ qdev = qdisc_dev (q -> root );
621
+ if (qdev == dev ) {
622
+ found = true;
623
+ break ;
624
+ }
625
+ }
626
+ spin_unlock (& taprio_list_lock );
627
+
628
+ if (found )
629
+ taprio_set_picos_per_byte (dev , q );
630
+
631
+ return NOTIFY_DONE ;
632
+ }
633
+
578
634
static int taprio_change (struct Qdisc * sch , struct nlattr * opt ,
579
635
struct netlink_ext_ack * extack )
580
636
{
581
637
struct nlattr * tb [TCA_TAPRIO_ATTR_MAX + 1 ] = { };
582
638
struct taprio_sched * q = qdisc_priv (sch );
583
639
struct net_device * dev = qdisc_dev (sch );
584
640
struct tc_mqprio_qopt * mqprio = NULL ;
585
- struct ethtool_link_ksettings ecmd ;
586
641
int i , err , size ;
587
- s64 link_speed ;
588
642
ktime_t start ;
589
643
590
644
err = nla_parse_nested (tb , TCA_TAPRIO_ATTR_MAX , opt ,
@@ -657,14 +711,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
657
711
mqprio -> prio_tc_map [i ]);
658
712
}
659
713
660
- if (!__ethtool_get_link_ksettings (dev , & ecmd ))
661
- link_speed = ecmd .base .speed ;
662
- else
663
- link_speed = SPEED_1000 ;
664
-
665
- q -> picos_per_byte = div64_s64 (NSEC_PER_SEC * 1000LL * 8 ,
666
- link_speed * 1000 * 1000 );
667
-
714
+ taprio_set_picos_per_byte (dev , q );
668
715
start = taprio_get_start_time (sch );
669
716
if (!start )
670
717
return 0 ;
@@ -681,6 +728,10 @@ static void taprio_destroy(struct Qdisc *sch)
681
728
struct sched_entry * entry , * n ;
682
729
unsigned int i ;
683
730
731
+ spin_lock (& taprio_list_lock );
732
+ list_del (& q -> taprio_list );
733
+ spin_unlock (& taprio_list_lock );
734
+
684
735
hrtimer_cancel (& q -> advance_timer );
685
736
686
737
if (q -> qdiscs ) {
@@ -735,6 +786,10 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
735
786
if (!opt )
736
787
return - EINVAL ;
737
788
789
+ spin_lock (& taprio_list_lock );
790
+ list_add (& q -> taprio_list , & taprio_list );
791
+ spin_unlock (& taprio_list_lock );
792
+
738
793
return taprio_change (sch , opt , extack );
739
794
}
740
795
@@ -947,14 +1002,24 @@ static struct Qdisc_ops taprio_qdisc_ops __read_mostly = {
947
1002
.owner = THIS_MODULE ,
948
1003
};
949
1004
1005
+ static struct notifier_block taprio_device_notifier = {
1006
+ .notifier_call = taprio_dev_notifier ,
1007
+ };
1008
+
950
1009
static int __init taprio_module_init (void )
951
1010
{
1011
+ int err = register_netdevice_notifier (& taprio_device_notifier );
1012
+
1013
+ if (err )
1014
+ return err ;
1015
+
952
1016
return register_qdisc (& taprio_qdisc_ops );
953
1017
}
954
1018
955
1019
static void __exit taprio_module_exit (void )
956
1020
{
957
1021
unregister_qdisc (& taprio_qdisc_ops );
1022
+ unregister_netdevice_notifier (& taprio_device_notifier );
958
1023
}
959
1024
960
1025
module_init (taprio_module_init );
0 commit comments