]>
Commit | Line | Data |
---|---|---|
79691192 HM |
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 "dsa_priv.h" | |
14 | ||
15 | #define GSWIP_TX_HEADER_LEN 4 | |
16 | ||
17 | /* special tag in TX path header */ | |
18 | /* Byte 0 */ | |
19 | #define GSWIP_TX_SLPID_SHIFT 0 /* source port ID */ | |
20 | #define GSWIP_TX_SLPID_CPU 2 | |
21 | #define GSWIP_TX_SLPID_APP1 3 | |
22 | #define GSWIP_TX_SLPID_APP2 4 | |
23 | #define GSWIP_TX_SLPID_APP3 5 | |
24 | #define GSWIP_TX_SLPID_APP4 6 | |
25 | #define GSWIP_TX_SLPID_APP5 7 | |
26 | ||
27 | /* Byte 1 */ | |
28 | #define GSWIP_TX_CRCGEN_DIS BIT(7) | |
29 | #define GSWIP_TX_DPID_SHIFT 0 /* destination group ID */ | |
30 | #define GSWIP_TX_DPID_ELAN 0 | |
31 | #define GSWIP_TX_DPID_EWAN 1 | |
32 | #define GSWIP_TX_DPID_CPU 2 | |
33 | #define GSWIP_TX_DPID_APP1 3 | |
34 | #define GSWIP_TX_DPID_APP2 4 | |
35 | #define GSWIP_TX_DPID_APP3 5 | |
36 | #define GSWIP_TX_DPID_APP4 6 | |
37 | #define GSWIP_TX_DPID_APP5 7 | |
38 | ||
39 | /* Byte 2 */ | |
40 | #define GSWIP_TX_PORT_MAP_EN BIT(7) | |
41 | #define GSWIP_TX_PORT_MAP_SEL BIT(6) | |
42 | #define GSWIP_TX_LRN_DIS BIT(5) | |
43 | #define GSWIP_TX_CLASS_EN BIT(4) | |
44 | #define GSWIP_TX_CLASS_SHIFT 0 | |
45 | #define GSWIP_TX_CLASS_MASK GENMASK(3, 0) | |
46 | ||
47 | /* Byte 3 */ | |
48 | #define GSWIP_TX_DPID_EN BIT(0) | |
49 | #define GSWIP_TX_PORT_MAP_SHIFT 1 | |
50 | #define GSWIP_TX_PORT_MAP_MASK GENMASK(6, 1) | |
51 | ||
52 | #define GSWIP_RX_HEADER_LEN 8 | |
53 | ||
54 | /* special tag in RX path header */ | |
55 | /* Byte 7 */ | |
56 | #define GSWIP_RX_SPPID_SHIFT 4 | |
57 | #define GSWIP_RX_SPPID_MASK GENMASK(6, 4) | |
58 | ||
59 | static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb, | |
60 | struct net_device *dev) | |
61 | { | |
62 | struct dsa_port *dp = dsa_slave_to_port(dev); | |
79691192 HM |
63 | u8 *gswip_tag; |
64 | ||
79691192 HM |
65 | skb_push(skb, GSWIP_TX_HEADER_LEN); |
66 | ||
67 | gswip_tag = skb->data; | |
68 | gswip_tag[0] = GSWIP_TX_SLPID_CPU; | |
69 | gswip_tag[1] = GSWIP_TX_DPID_ELAN; | |
70 | gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL; | |
71 | gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK; | |
72 | gswip_tag[3] |= GSWIP_TX_DPID_EN; | |
73 | ||
74 | return skb; | |
75 | } | |
76 | ||
77 | static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, | |
29a097b7 | 78 | struct net_device *dev) |
79691192 HM |
79 | { |
80 | int port; | |
81 | u8 *gswip_tag; | |
82 | ||
83 | if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) | |
84 | return NULL; | |
85 | ||
86 | gswip_tag = skb->data - ETH_HLEN; | |
87 | ||
88 | /* Get source port information */ | |
89 | port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; | |
90 | skb->dev = dsa_master_find_slave(dev, 0, port); | |
91 | if (!skb->dev) | |
92 | return NULL; | |
93 | ||
94 | /* remove GSWIP tag */ | |
95 | skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN); | |
96 | ||
97 | return skb; | |
98 | } | |
99 | ||
f81a43e8 | 100 | static const struct dsa_device_ops gswip_netdev_ops = { |
ad322054 | 101 | .name = "gswip", |
056eed2f | 102 | .proto = DSA_TAG_PROTO_GSWIP, |
79691192 HM |
103 | .xmit = gswip_tag_xmit, |
104 | .rcv = gswip_tag_rcv, | |
4e500251 | 105 | .needed_headroom = GSWIP_RX_HEADER_LEN, |
79691192 | 106 | }; |
0b42f033 | 107 | |
f18bba50 | 108 | MODULE_LICENSE("GPL"); |
0b42f033 | 109 | MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP); |
d3b8c049 AL |
110 | |
111 | module_dsa_tag_driver(gswip_netdev_ops); |