]>
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 <[email protected]> | |
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); | |
63 | int err; | |
64 | u8 *gswip_tag; | |
65 | ||
66 | err = skb_cow_head(skb, GSWIP_TX_HEADER_LEN); | |
67 | if (err) | |
68 | return NULL; | |
69 | ||
70 | skb_push(skb, GSWIP_TX_HEADER_LEN); | |
71 | ||
72 | gswip_tag = skb->data; | |
73 | gswip_tag[0] = GSWIP_TX_SLPID_CPU; | |
74 | gswip_tag[1] = GSWIP_TX_DPID_ELAN; | |
75 | gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL; | |
76 | gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK; | |
77 | gswip_tag[3] |= GSWIP_TX_DPID_EN; | |
78 | ||
79 | return skb; | |
80 | } | |
81 | ||
82 | static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, | |
83 | struct net_device *dev, | |
84 | struct packet_type *pt) | |
85 | { | |
86 | int port; | |
87 | u8 *gswip_tag; | |
88 | ||
89 | if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) | |
90 | return NULL; | |
91 | ||
92 | gswip_tag = skb->data - ETH_HLEN; | |
93 | ||
94 | /* Get source port information */ | |
95 | port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; | |
96 | skb->dev = dsa_master_find_slave(dev, 0, port); | |
97 | if (!skb->dev) | |
98 | return NULL; | |
99 | ||
100 | /* remove GSWIP tag */ | |
101 | skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN); | |
102 | ||
103 | return skb; | |
104 | } | |
105 | ||
106 | const struct dsa_device_ops gswip_netdev_ops = { | |
107 | .xmit = gswip_tag_xmit, | |
108 | .rcv = gswip_tag_rcv, | |
a5dd3087 | 109 | .overhead = GSWIP_RX_HEADER_LEN, |
79691192 | 110 | }; |