diff options
Diffstat (limited to 'net/dsa/dsa.c')
-rw-r--r-- | net/dsa/dsa.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 6a9d0f50fbee..e63c554e0623 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
24 | #include <linux/sysfs.h> | 24 | #include <linux/sysfs.h> |
25 | #include <linux/phy_fixed.h> | 25 | #include <linux/phy_fixed.h> |
26 | #include <linux/ptp_classify.h> | ||
26 | #include <linux/gpio/consumer.h> | 27 | #include <linux/gpio/consumer.h> |
27 | #include <linux/etherdevice.h> | 28 | #include <linux/etherdevice.h> |
28 | 29 | ||
@@ -122,6 +123,38 @@ struct net_device *dsa_dev_to_net_device(struct device *dev) | |||
122 | } | 123 | } |
123 | EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); | 124 | EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); |
124 | 125 | ||
126 | /* Determine if we should defer delivery of skb until we have a rx timestamp. | ||
127 | * | ||
128 | * Called from dsa_switch_rcv. For now, this will only work if tagging is | ||
129 | * enabled on the switch. Normally the MAC driver would retrieve the hardware | ||
130 | * timestamp when it reads the packet out of the hardware. However in a DSA | ||
131 | * switch, the DSA driver owning the interface to which the packet is | ||
132 | * delivered is never notified unless we do so here. | ||
133 | */ | ||
134 | static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p, | ||
135 | struct sk_buff *skb) | ||
136 | { | ||
137 | struct dsa_switch *ds = p->dp->ds; | ||
138 | unsigned int type; | ||
139 | |||
140 | if (skb_headroom(skb) < ETH_HLEN) | ||
141 | return false; | ||
142 | |||
143 | __skb_push(skb, ETH_HLEN); | ||
144 | |||
145 | type = ptp_classify_raw(skb); | ||
146 | |||
147 | __skb_pull(skb, ETH_HLEN); | ||
148 | |||
149 | if (type == PTP_CLASS_NONE) | ||
150 | return false; | ||
151 | |||
152 | if (likely(ds->ops->port_rxtstamp)) | ||
153 | return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type); | ||
154 | |||
155 | return false; | ||
156 | } | ||
157 | |||
125 | static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, | 158 | static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, |
126 | struct packet_type *pt, struct net_device *unused) | 159 | struct packet_type *pt, struct net_device *unused) |
127 | { | 160 | { |
@@ -157,6 +190,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, | |||
157 | s->rx_bytes += skb->len; | 190 | s->rx_bytes += skb->len; |
158 | u64_stats_update_end(&s->syncp); | 191 | u64_stats_update_end(&s->syncp); |
159 | 192 | ||
193 | if (dsa_skb_defer_rx_timestamp(p, skb)) | ||
194 | return 0; | ||
195 | |||
160 | netif_receive_skb(skb); | 196 | netif_receive_skb(skb); |
161 | 197 | ||
162 | return 0; | 198 | return 0; |