| 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 * |
| 12 | vsc73xx_xmit(struct sk_buff *skb, struct net_device *netdev) |
| 13 | { |
| 14 | struct dsa_port *dp = dsa_user_to_port(dev: 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(dev: br)) |
| 24 | return skb; |
| 25 | |
| 26 | tx_vid = dsa_tag_8021q_bridge_vid(bridge_num); |
| 27 | } |
| 28 | |
| 29 | pcp = netdev_txq_to_tc(dev: netdev, txq: queue_mapping); |
| 30 | |
| 31 | return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q, |
| 32 | tci: ((pcp << VLAN_PRIO_SHIFT) | tx_vid)); |
| 33 | } |
| 34 | |
| 35 | static struct sk_buff * |
| 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, source_port: &src_port, switch_id: &switch_id, vbid: &vbid, vid: &vid); |
| 41 | |
| 42 | skb->dev = dsa_tag_8021q_find_user(conduit: netdev, source_port: 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 | |