xref: /openbmc/linux/net/dsa/tag_gswip.c (revision b7019ac5)
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);
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 static const struct dsa_device_ops gswip_netdev_ops = {
107 	.name = "gwsip",
108 	.proto	= DSA_TAG_PROTO_GSWIP,
109 	.xmit = gswip_tag_xmit,
110 	.rcv = gswip_tag_rcv,
111 	.overhead = GSWIP_RX_HEADER_LEN,
112 };
113 
114 MODULE_LICENSE("GPL");
115 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP);
116 
117 module_dsa_tag_driver(gswip_netdev_ops);
118