1 // SPDX-License-Identifier: GPL-2.0
3 * Handler for Realtek 8 byte switch tags
5 * Copyright (C) 2021 Alvin Šipraga <alsi@bang-olufsen.dk>
7 * NOTE: Currently only supports protocol "4" found in the RTL8365MB, hence
10 * This tag header has the following format:
12 * -------------------------------------------
13 * | MAC DA | MAC SA | 8 byte tag | Type | ...
14 * -------------------------------------------
15 * _______________/ \______________________________________
18 * |-----------------------------------+-----------------------------------|---
20 * | Realtek EtherType [0x8899] | |
21 * |-----------------------------------+-----------------------------------| 8
22 * | (8-bit) | (8-bit) |
23 * | Protocol [0x04] | REASON | b
24 * |-----------------------------------+-----------------------------------| y
25 * | (1) | (1) | (2) | (1) | (3) | (1) | (1) | (1) | (5) | t
26 * | FID_EN | X | FID | PRI_EN | PRI | KEEP | X | LEARN_DIS | X | e
27 * |-----------------------------------+-----------------------------------| s
28 * | (1) | (15-bit) | |
30 * |-----------------------------------+-----------------------------------|---
32 * With the following field descriptions:
35 * ------------+-------------
36 * Realtek | 0x8899: indicates that this is a proprietary Realtek tag;
37 * EtherType | note that Realtek uses the same EtherType for
38 * | other incompatible tag formats (e.g. tag_rtl4_a.c)
39 * Protocol | 0x04: indicates that this tag conforms to this format
41 * ------------+-------------
42 * REASON | reason for forwarding packet to CPU
43 * | 0: packet was forwarded or flooded to CPU
44 * | 80: packet was trapped to CPU
45 * FID_EN | 1: packet has an FID
47 * FID | FID of packet (if FID_EN=1)
48 * PRI_EN | 1: force priority of packet
49 * | 0: don't force priority
50 * PRI | priority of packet (if PRI_EN=1)
51 * KEEP | preserve packet VLAN tag format
52 * LEARN_DIS | don't learn the source MAC address of the packet
53 * ALLOW | 1: treat TX/RX field as an allowance port mask, meaning the
54 * | packet may only be forwarded to ports specified in the
56 * | 0: no allowance port mask, TX/RX field is the forwarding
58 * TX/RX | TX (switch->CPU): port number the packet was received on
59 * | RX (CPU->switch): forwarding port mask (if ALLOW=0)
60 * | allowance port mask (if ALLOW=1)
63 #include <linux/bitfield.h>
64 #include <linux/bits.h>
65 #include <linux/etherdevice.h>
69 /* Protocols supported:
71 * 0x04 = RTL8365MB DSA protocol
74 #define RTL8_4_TAG_LEN 8
76 #define RTL8_4_PROTOCOL GENMASK(15, 8)
77 #define RTL8_4_PROTOCOL_RTL8365MB 0x04
78 #define RTL8_4_REASON GENMASK(7, 0)
79 #define RTL8_4_REASON_FORWARD 0
80 #define RTL8_4_REASON_TRAP 80
82 #define RTL8_4_LEARN_DIS BIT(5)
84 #define RTL8_4_TX GENMASK(3, 0)
85 #define RTL8_4_RX GENMASK(10, 0)
87 static struct sk_buff *rtl8_4_tag_xmit(struct sk_buff *skb,
88 struct net_device *dev)
90 struct dsa_port *dp = dsa_slave_to_port(dev);
93 skb_push(skb, RTL8_4_TAG_LEN);
95 dsa_alloc_etype_header(skb, RTL8_4_TAG_LEN);
96 tag = dsa_etype_header_pos_tx(skb);
98 /* Set Realtek EtherType */
99 tag[0] = htons(ETH_P_REALTEK);
101 /* Set Protocol; zero REASON */
102 tag[1] = htons(FIELD_PREP(RTL8_4_PROTOCOL, RTL8_4_PROTOCOL_RTL8365MB));
104 /* Zero FID_EN, FID, PRI_EN, PRI, KEEP; set LEARN_DIS */
105 tag[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1));
107 /* Zero ALLOW; set RX (CPU->switch) forwarding port mask */
108 tag[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index)));
113 static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
114 struct net_device *dev)
122 if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN)))
125 tag = dsa_etype_header_pos_rx(skb);
127 /* Parse Realtek EtherType */
128 etype = ntohs(tag[0]);
129 if (unlikely(etype != ETH_P_REALTEK)) {
130 dev_warn_ratelimited(&dev->dev,
131 "non-realtek ethertype 0x%04x\n", etype);
136 proto = FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag[1]));
137 if (unlikely(proto != RTL8_4_PROTOCOL_RTL8365MB)) {
138 dev_warn_ratelimited(&dev->dev,
139 "unknown realtek protocol 0x%02x\n",
145 reason = FIELD_GET(RTL8_4_REASON, ntohs(tag[1]));
147 /* Parse TX (switch->CPU) */
148 port = FIELD_GET(RTL8_4_TX, ntohs(tag[3]));
149 skb->dev = dsa_master_find_slave(dev, 0, port);
151 dev_warn_ratelimited(&dev->dev,
152 "could not find slave for port %d\n",
157 /* Remove tag and recalculate checksum */
158 skb_pull_rcsum(skb, RTL8_4_TAG_LEN);
160 dsa_strip_etype_header(skb, RTL8_4_TAG_LEN);
162 if (reason != RTL8_4_REASON_TRAP)
163 dsa_default_offload_fwd_mark(skb);
168 static const struct dsa_device_ops rtl8_4_netdev_ops = {
170 .proto = DSA_TAG_PROTO_RTL8_4,
171 .xmit = rtl8_4_tag_xmit,
172 .rcv = rtl8_4_tag_rcv,
173 .needed_headroom = RTL8_4_TAG_LEN,
175 module_dsa_tag_driver(rtl8_4_netdev_ops);
177 MODULE_LICENSE("GPL");
178 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4);