1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Handler for Realtek 8 byte switch tags 4 * 5 * Copyright (C) 2021 Alvin Šipraga <alsi@bang-olufsen.dk> 6 * 7 * NOTE: Currently only supports protocol "4" found in the RTL8365MB, hence 8 * named tag_rtl8_4. 9 * 10 * This tag header has the following format: 11 * 12 * ------------------------------------------- 13 * | MAC DA | MAC SA | 8 byte tag | Type | ... 14 * ------------------------------------------- 15 * _______________/ \______________________________________ 16 * / \ 17 * 0 7|8 15 18 * |-----------------------------------+-----------------------------------|--- 19 * | (16-bit) | ^ 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) | | 29 * | ALLOW | TX/RX | v 30 * |-----------------------------------+-----------------------------------|--- 31 * 32 * With the following field descriptions: 33 * 34 * field | description 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 40 * X | reserved 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 46 * | 0: no 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 55 * | mask 56 * | 0: no allowance port mask, TX/RX field is the forwarding 57 * | port mask 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) 61 */ 62 63 #include <linux/bitfield.h> 64 #include <linux/bits.h> 65 #include <linux/etherdevice.h> 66 67 #include "dsa_priv.h" 68 69 /* Protocols supported: 70 * 71 * 0x04 = RTL8365MB DSA protocol 72 */ 73 74 #define RTL8_4_TAG_LEN 8 75 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 81 82 #define RTL8_4_LEARN_DIS BIT(5) 83 84 #define RTL8_4_TX GENMASK(3, 0) 85 #define RTL8_4_RX GENMASK(10, 0) 86 87 static struct sk_buff *rtl8_4_tag_xmit(struct sk_buff *skb, 88 struct net_device *dev) 89 { 90 struct dsa_port *dp = dsa_slave_to_port(dev); 91 __be16 *tag; 92 93 skb_push(skb, RTL8_4_TAG_LEN); 94 95 dsa_alloc_etype_header(skb, RTL8_4_TAG_LEN); 96 tag = dsa_etype_header_pos_tx(skb); 97 98 /* Set Realtek EtherType */ 99 tag[0] = htons(ETH_P_REALTEK); 100 101 /* Set Protocol; zero REASON */ 102 tag[1] = htons(FIELD_PREP(RTL8_4_PROTOCOL, RTL8_4_PROTOCOL_RTL8365MB)); 103 104 /* Zero FID_EN, FID, PRI_EN, PRI, KEEP; set LEARN_DIS */ 105 tag[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1)); 106 107 /* Zero ALLOW; set RX (CPU->switch) forwarding port mask */ 108 tag[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index))); 109 110 return skb; 111 } 112 113 static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb, 114 struct net_device *dev) 115 { 116 __be16 *tag; 117 u16 etype; 118 u8 reason; 119 u8 proto; 120 u8 port; 121 122 if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) 123 return NULL; 124 125 tag = dsa_etype_header_pos_rx(skb); 126 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); 132 return NULL; 133 } 134 135 /* Parse Protocol */ 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", 140 proto); 141 return NULL; 142 } 143 144 /* Parse REASON */ 145 reason = FIELD_GET(RTL8_4_REASON, ntohs(tag[1])); 146 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); 150 if (!skb->dev) { 151 dev_warn_ratelimited(&dev->dev, 152 "could not find slave for port %d\n", 153 port); 154 return NULL; 155 } 156 157 /* Remove tag and recalculate checksum */ 158 skb_pull_rcsum(skb, RTL8_4_TAG_LEN); 159 160 dsa_strip_etype_header(skb, RTL8_4_TAG_LEN); 161 162 if (reason != RTL8_4_REASON_TRAP) 163 dsa_default_offload_fwd_mark(skb); 164 165 return skb; 166 } 167 168 static const struct dsa_device_ops rtl8_4_netdev_ops = { 169 .name = "rtl8_4", 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, 174 }; 175 module_dsa_tag_driver(rtl8_4_netdev_ops); 176 177 MODULE_LICENSE("GPL"); 178 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4); 179