summaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorVladimir Oltean <olteanv@gmail.com>2019-06-08 08:04:39 -0400
committerDavid S. Miller <davem@davemloft.net>2019-06-08 18:20:40 -0400
commite53e18a6fe4d3ae04c28ca2327ef7e7656cb07ce (patch)
tree11d8d66ae2b477cde4fed8a534fa3df7c69c91bc /net/dsa
parent79fa7061397a372256b466d62a0a81690b512d5f (diff)
net: dsa: sja1105: Receive and decode meta frames
This adds support in the tagger for understanding the source port and switch id of meta frames. Their timestamp is also extracted but not used yet - this needs to be done in a state machine that modifies the previously received timestampable frame - will be added in a follow-up patch. Also take the opportunity to: - Remove a comment in sja1105_filter made obsolete by e8d67fa5696e ("net: dsa: sja1105: Don't store frame type in skb->cb") - Reorder the checks in sja1105_filter to optimize for the most likely scenario first: regular traffic. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/tag_sja1105.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index 094711ced5c0..5b51e96130c7 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -24,6 +24,36 @@ static inline bool sja1105_is_link_local(const struct sk_buff *skb)
24 return false; 24 return false;
25} 25}
26 26
27struct sja1105_meta {
28 u64 tstamp;
29 u64 dmac_byte_4;
30 u64 dmac_byte_3;
31 u64 source_port;
32 u64 switch_id;
33};
34
35static void sja1105_meta_unpack(const struct sk_buff *skb,
36 struct sja1105_meta *meta)
37{
38 u8 *buf = skb_mac_header(skb) + ETH_HLEN;
39
40 /* UM10944.pdf section 4.2.17 AVB Parameters:
41 * Structure of the meta-data follow-up frame.
42 * It is in network byte order, so there are no quirks
43 * while unpacking the meta frame.
44 *
45 * Also SJA1105 E/T only populates bits 23:0 of the timestamp
46 * whereas P/Q/R/S does 32 bits. Since the structure is the
47 * same and the E/T puts zeroes in the high-order byte, use
48 * a unified unpacking command for both device series.
49 */
50 packing(buf, &meta->tstamp, 31, 0, 4, UNPACK, 0);
51 packing(buf + 4, &meta->dmac_byte_4, 7, 0, 1, UNPACK, 0);
52 packing(buf + 5, &meta->dmac_byte_3, 7, 0, 1, UNPACK, 0);
53 packing(buf + 6, &meta->source_port, 7, 0, 1, UNPACK, 0);
54 packing(buf + 7, &meta->switch_id, 7, 0, 1, UNPACK, 0);
55}
56
27static inline bool sja1105_is_meta_frame(const struct sk_buff *skb) 57static inline bool sja1105_is_meta_frame(const struct sk_buff *skb)
28{ 58{
29 const struct ethhdr *hdr = eth_hdr(skb); 59 const struct ethhdr *hdr = eth_hdr(skb);
@@ -40,14 +70,15 @@ static inline bool sja1105_is_meta_frame(const struct sk_buff *skb)
40} 70}
41 71
42/* This is the first time the tagger sees the frame on RX. 72/* This is the first time the tagger sees the frame on RX.
43 * Figure out if we can decode it, and if we can, annotate skb->cb with how we 73 * Figure out if we can decode it.
44 * plan to do that, so we don't need to check again in the rcv function.
45 */ 74 */
46static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev) 75static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev)
47{ 76{
77 if (!dsa_port_is_vlan_filtering(dev->dsa_ptr))
78 return true;
48 if (sja1105_is_link_local(skb)) 79 if (sja1105_is_link_local(skb))
49 return true; 80 return true;
50 if (!dsa_port_is_vlan_filtering(dev->dsa_ptr)) 81 if (sja1105_is_meta_frame(skb))
51 return true; 82 return true;
52 return false; 83 return false;
53} 84}
@@ -83,16 +114,19 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
83 struct net_device *netdev, 114 struct net_device *netdev,
84 struct packet_type *pt) 115 struct packet_type *pt)
85{ 116{
117 struct sja1105_meta meta = {0};
86 int source_port, switch_id; 118 int source_port, switch_id;
87 struct vlan_ethhdr *hdr; 119 struct vlan_ethhdr *hdr;
88 u16 tpid, vid, tci; 120 u16 tpid, vid, tci;
89 bool is_link_local; 121 bool is_link_local;
90 bool is_tagged; 122 bool is_tagged;
123 bool is_meta;
91 124
92 hdr = vlan_eth_hdr(skb); 125 hdr = vlan_eth_hdr(skb);
93 tpid = ntohs(hdr->h_vlan_proto); 126 tpid = ntohs(hdr->h_vlan_proto);
94 is_tagged = (tpid == ETH_P_SJA1105); 127 is_tagged = (tpid == ETH_P_SJA1105);
95 is_link_local = sja1105_is_link_local(skb); 128 is_link_local = sja1105_is_link_local(skb);
129 is_meta = sja1105_is_meta_frame(skb);
96 130
97 skb->offload_fwd_mark = 1; 131 skb->offload_fwd_mark = 1;
98 132
@@ -113,6 +147,10 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
113 /* Clear the DMAC bytes that were mangled by the switch */ 147 /* Clear the DMAC bytes that were mangled by the switch */
114 hdr->h_dest[3] = 0; 148 hdr->h_dest[3] = 0;
115 hdr->h_dest[4] = 0; 149 hdr->h_dest[4] = 0;
150 } else if (is_meta) {
151 sja1105_meta_unpack(skb, &meta);
152 source_port = meta.source_port;
153 switch_id = meta.switch_id;
116 } else { 154 } else {
117 return NULL; 155 return NULL;
118 } 156 }