1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Intel / Lantiq GSWIP V2.0 PMAC tag support |
4 | * |
5 | * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de> |
6 | */ |
7 | |
8 | #include <linux/bitops.h> |
9 | #include <linux/etherdevice.h> |
10 | #include <linux/skbuff.h> |
11 | #include <net/dsa.h> |
12 | |
13 | #include "tag.h" |
14 | |
15 | #define GSWIP_NAME "gswip" |
16 | |
17 | #define 4 |
18 | |
19 | /* special tag in TX path header */ |
20 | /* Byte 0 */ |
21 | #define GSWIP_TX_SLPID_SHIFT 0 /* source port ID */ |
22 | #define GSWIP_TX_SLPID_CPU 2 |
23 | #define GSWIP_TX_SLPID_APP1 3 |
24 | #define GSWIP_TX_SLPID_APP2 4 |
25 | #define GSWIP_TX_SLPID_APP3 5 |
26 | #define GSWIP_TX_SLPID_APP4 6 |
27 | #define GSWIP_TX_SLPID_APP5 7 |
28 | |
29 | /* Byte 1 */ |
30 | #define GSWIP_TX_CRCGEN_DIS BIT(7) |
31 | #define GSWIP_TX_DPID_SHIFT 0 /* destination group ID */ |
32 | #define GSWIP_TX_DPID_ELAN 0 |
33 | #define GSWIP_TX_DPID_EWAN 1 |
34 | #define GSWIP_TX_DPID_CPU 2 |
35 | #define GSWIP_TX_DPID_APP1 3 |
36 | #define GSWIP_TX_DPID_APP2 4 |
37 | #define GSWIP_TX_DPID_APP3 5 |
38 | #define GSWIP_TX_DPID_APP4 6 |
39 | #define GSWIP_TX_DPID_APP5 7 |
40 | |
41 | /* Byte 2 */ |
42 | #define GSWIP_TX_PORT_MAP_EN BIT(7) |
43 | #define GSWIP_TX_PORT_MAP_SEL BIT(6) |
44 | #define GSWIP_TX_LRN_DIS BIT(5) |
45 | #define GSWIP_TX_CLASS_EN BIT(4) |
46 | #define GSWIP_TX_CLASS_SHIFT 0 |
47 | #define GSWIP_TX_CLASS_MASK GENMASK(3, 0) |
48 | |
49 | /* Byte 3 */ |
50 | #define GSWIP_TX_DPID_EN BIT(0) |
51 | #define GSWIP_TX_PORT_MAP_SHIFT 1 |
52 | #define GSWIP_TX_PORT_MAP_MASK GENMASK(6, 1) |
53 | |
54 | #define 8 |
55 | |
56 | /* special tag in RX path header */ |
57 | /* Byte 7 */ |
58 | #define GSWIP_RX_SPPID_SHIFT 4 |
59 | #define GSWIP_RX_SPPID_MASK GENMASK(6, 4) |
60 | |
61 | static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb, |
62 | struct net_device *dev) |
63 | { |
64 | struct dsa_port *dp = dsa_user_to_port(dev); |
65 | u8 *gswip_tag; |
66 | |
67 | skb_push(skb, GSWIP_TX_HEADER_LEN); |
68 | |
69 | gswip_tag = skb->data; |
70 | gswip_tag[0] = GSWIP_TX_SLPID_CPU; |
71 | gswip_tag[1] = GSWIP_TX_DPID_ELAN; |
72 | gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL; |
73 | gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK; |
74 | gswip_tag[3] |= GSWIP_TX_DPID_EN; |
75 | |
76 | return skb; |
77 | } |
78 | |
79 | static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, |
80 | struct net_device *dev) |
81 | { |
82 | int port; |
83 | u8 *gswip_tag; |
84 | |
85 | if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) |
86 | return NULL; |
87 | |
88 | gswip_tag = skb->data - ETH_HLEN; |
89 | |
90 | /* Get source port information */ |
91 | port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; |
92 | skb->dev = dsa_conduit_find_user(dev, device: 0, port); |
93 | if (!skb->dev) |
94 | return NULL; |
95 | |
96 | /* remove GSWIP tag */ |
97 | skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN); |
98 | |
99 | return skb; |
100 | } |
101 | |
102 | static const struct dsa_device_ops gswip_netdev_ops = { |
103 | .name = GSWIP_NAME, |
104 | .proto = DSA_TAG_PROTO_GSWIP, |
105 | .xmit = gswip_tag_xmit, |
106 | .rcv = gswip_tag_rcv, |
107 | .needed_headroom = GSWIP_RX_HEADER_LEN, |
108 | }; |
109 | |
110 | MODULE_LICENSE("GPL" ); |
111 | MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP, GSWIP_NAME); |
112 | |
113 | module_dsa_tag_driver(gswip_netdev_ops); |
114 | |