1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /* Copyright (C) 2024 Pawel Dembicki <paweldembicki@gmail.com>
3  */
4 #include <linux/dsa/8021q.h>
5 
6 #include "tag.h"
7 #include "tag_8021q.h"
8 
9 #define VSC73XX_8021Q_NAME "vsc73xx-8021q"
10 
11 static struct sk_buff *
vsc73xx_xmit(struct sk_buff * skb,struct net_device * netdev)12 vsc73xx_xmit(struct sk_buff *skb, struct net_device *netdev)
13 {
14 	struct dsa_port *dp = dsa_user_to_port(netdev);
15 	u16 queue_mapping = skb_get_queue_mapping(skb);
16 	u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
17 	u8 pcp;
18 
19 	if (skb->offload_fwd_mark) {
20 		unsigned int bridge_num = dsa_port_bridge_num_get(dp);
21 		struct net_device *br = dsa_port_bridge_dev_get(dp);
22 
23 		if (br_vlan_enabled(br))
24 			return skb;
25 
26 		tx_vid = dsa_tag_8021q_bridge_vid(bridge_num);
27 	}
28 
29 	pcp = netdev_txq_to_tc(netdev, queue_mapping);
30 
31 	return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q,
32 			      ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
33 }
34 
35 static struct sk_buff *
vsc73xx_rcv(struct sk_buff * skb,struct net_device * netdev)36 vsc73xx_rcv(struct sk_buff *skb, struct net_device *netdev)
37 {
38 	int src_port = -1, switch_id = -1, vbid = -1, vid = -1;
39 
40 	dsa_8021q_rcv(skb, &src_port, &switch_id, &vbid, &vid);
41 
42 	skb->dev = dsa_tag_8021q_find_user(netdev, src_port, switch_id,
43 					   vid, vbid);
44 	if (!skb->dev) {
45 		dev_warn_ratelimited(&netdev->dev,
46 				     "Couldn't decode source port\n");
47 		return NULL;
48 	}
49 
50 	dsa_default_offload_fwd_mark(skb);
51 
52 	return skb;
53 }
54 
55 static const struct dsa_device_ops vsc73xx_8021q_netdev_ops = {
56 	.name			= VSC73XX_8021Q_NAME,
57 	.proto			= DSA_TAG_PROTO_VSC73XX_8021Q,
58 	.xmit			= vsc73xx_xmit,
59 	.rcv			= vsc73xx_rcv,
60 	.needed_headroom	= VLAN_HLEN,
61 	.promisc_on_conduit	= true,
62 };
63 
64 MODULE_LICENSE("GPL");
65 MODULE_DESCRIPTION("DSA tag driver for VSC73XX family of switches, using VLAN");
66 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_VSC73XX_8021Q, VSC73XX_8021Q_NAME);
67 
68 module_dsa_tag_driver(vsc73xx_8021q_netdev_ops);
69