Blame view
net/dsa/tag_mtk.c
3.17 KB
dfedd3b62 dsa: Add SPDX hea... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
5cd8985a1 net-next: dsa: ad... |
2 3 4 5 |
/* * Mediatek DSA Tag support * Copyright (C) 2017 Landen Chao <landen.chao@mediatek.com> * Sean Wang <sean.wang@mediatek.com> |
5cd8985a1 net-next: dsa: ad... |
6 7 8 |
*/ #include <linux/etherdevice.h> |
f0af34317 net: dsa: mediate... |
9 |
#include <linux/if_vlan.h> |
ea5dd34be net: dsa: include... |
10 |
|
5cd8985a1 net-next: dsa: ad... |
11 12 13 |
#include "dsa_priv.h" #define MTK_HDR_LEN 4 |
f0af34317 net: dsa: mediate... |
14 15 |
#define MTK_HDR_XMIT_UNTAGGED 0 #define MTK_HDR_XMIT_TAGGED_TPID_8100 1 |
5cd8985a1 net-next: dsa: ad... |
16 17 |
#define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) #define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0) |
5e5502e01 net: dsa: mt7530:... |
18 |
#define MTK_HDR_XMIT_SA_DIS BIT(6) |
5cd8985a1 net-next: dsa: ad... |
19 20 21 22 |
static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, struct net_device *dev) { |
d945097bb net: dsa: add sla... |
23 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
5cd8985a1 net-next: dsa: ad... |
24 |
u8 *mtk_tag; |
f0af34317 net: dsa: mediate... |
25 |
bool is_vlan_skb = true; |
5e5502e01 net: dsa: mt7530:... |
26 27 28 |
unsigned char *dest = eth_hdr(skb)->h_dest; bool is_multicast_skb = is_multicast_ether_addr(dest) && !is_broadcast_ether_addr(dest); |
5cd8985a1 net-next: dsa: ad... |
29 |
|
f0af34317 net: dsa: mediate... |
30 31 32 33 34 35 36 37 38 |
/* Build the special tag after the MAC Source Address. If VLAN header * is present, it's required that VLAN header and special tag is * being combined. Only in this way we can allow the switch can parse * the both special and VLAN tag at the same time and then look up VLAN * table with VID. */ if (!skb_vlan_tagged(skb)) { if (skb_cow_head(skb, MTK_HDR_LEN) < 0) return NULL; |
5cd8985a1 net-next: dsa: ad... |
39 |
|
f0af34317 net: dsa: mediate... |
40 41 42 43 |
skb_push(skb, MTK_HDR_LEN); memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN); is_vlan_skb = false; } |
5cd8985a1 net-next: dsa: ad... |
44 |
|
5cd8985a1 net-next: dsa: ad... |
45 |
mtk_tag = skb->data + 2 * ETH_ALEN; |
f0af34317 net: dsa: mediate... |
46 47 48 49 50 51 |
/* Mark tag attribute on special tag insertion to notify hardware * whether that's a combined special tag with 802.1Q header. */ mtk_tag[0] = is_vlan_skb ? MTK_HDR_XMIT_TAGGED_TPID_8100 : MTK_HDR_XMIT_UNTAGGED; |
d945097bb net: dsa: add sla... |
52 |
mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; |
f0af34317 net: dsa: mediate... |
53 |
|
5e5502e01 net: dsa: mt7530:... |
54 55 56 |
/* Disable SA learning for multicast frames */ if (unlikely(is_multicast_skb)) mtk_tag[1] |= MTK_HDR_XMIT_SA_DIS; |
f0af34317 net: dsa: mediate... |
57 58 59 60 61 |
/* Tag control information is kept for 802.1Q */ if (!is_vlan_skb) { mtk_tag[2] = 0; mtk_tag[3] = 0; } |
5cd8985a1 net-next: dsa: ad... |
62 63 |
return skb; |
5cd8985a1 net-next: dsa: ad... |
64 |
} |
a86d8becc net: dsa: Factor ... |
65 |
static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, |
89e49506b dsa: remove unuse... |
66 |
struct packet_type *pt) |
5cd8985a1 net-next: dsa: ad... |
67 |
{ |
04d63f9d9 net: dsa: tag_mtk... |
68 |
u16 hdr; |
5cd8985a1 net-next: dsa: ad... |
69 |
int port; |
04d63f9d9 net: dsa: tag_mtk... |
70 |
__be16 *phdr; |
5e5502e01 net: dsa: mt7530:... |
71 72 73 |
unsigned char *dest = eth_hdr(skb)->h_dest; bool is_multicast_skb = is_multicast_ether_addr(dest) && !is_broadcast_ether_addr(dest); |
5cd8985a1 net-next: dsa: ad... |
74 |
|
5cd8985a1 net-next: dsa: ad... |
75 |
if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) |
547097958 net: dsa: remove ... |
76 |
return NULL; |
5cd8985a1 net-next: dsa: ad... |
77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* The MTK header is added by the switch between src addr * and ethertype at this point, skb->data points to 2 bytes * after src addr so header should be 2 bytes right before. */ phdr = (__be16 *)(skb->data - 2); hdr = ntohs(*phdr); /* Remove MTK tag and recalculate checksum. */ skb_pull_rcsum(skb, MTK_HDR_LEN); memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - MTK_HDR_LEN, 2 * ETH_ALEN); |
5cd8985a1 net-next: dsa: ad... |
91 92 |
/* Get source port information */ port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK); |
5cd8985a1 net-next: dsa: ad... |
93 |
|
2231c43b5 net: dsa: rename ... |
94 |
skb->dev = dsa_master_find_slave(dev, 0, port); |
3775b1b7f net: dsa: add mas... |
95 96 |
if (!skb->dev) return NULL; |
5cd8985a1 net-next: dsa: ad... |
97 |
|
5e5502e01 net: dsa: mt7530:... |
98 99 100 |
/* Only unicast or broadcast frames are offloaded */ if (likely(!is_multicast_skb)) skb->offload_fwd_mark = 1; |
a86d8becc net: dsa: Factor ... |
101 |
return skb; |
5cd8985a1 net-next: dsa: ad... |
102 |
} |
f81a43e8d dsa: Cleanup unne... |
103 |
static const struct dsa_device_ops mtk_netdev_ops = { |
875138f81 dsa: Move tagger ... |
104 |
.name = "mtk", |
056eed2fb dsa: Add TAG prot... |
105 |
.proto = DSA_TAG_PROTO_MTK, |
2dd592b27 net-next: tag_mtk... |
106 107 |
.xmit = mtk_tag_xmit, .rcv = mtk_tag_rcv, |
a5dd30877 net: dsa: Add ove... |
108 |
.overhead = MTK_HDR_LEN, |
5cd8985a1 net-next: dsa: ad... |
109 |
}; |
0b42f0336 dsa: Add MODULE_A... |
110 |
|
f18bba50d dsa: Add MODULE_L... |
111 |
MODULE_LICENSE("GPL"); |
0b42f0336 dsa: Add MODULE_A... |
112 |
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MTK); |
d3b8c0498 dsa: Add boilerpl... |
113 114 |
module_dsa_tag_driver(mtk_netdev_ops); |