FILE
tag_mxl-gsw1xx.c
File preview with syntax highlighting.
linux-6.19.14/net/dsa/tag_mxl-gsw1xx.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * DSA driver Special Tag support for MaxLinear GSW1xx switch chips 4 * 5 * Copyright (C) 2025 Daniel Golle <daniel@makrotopia.org> 6 * Copyright (C) 2023 - 2024 MaxLinear Inc. 7 */ 8 9#include <linux/bitops.h> 10#include <linux/etherdevice.h> 11#include <linux/skbuff.h> 12#include <net/dsa.h> 13 14#include "tag.h" 15 16/* To define the outgoing port and to discover the incoming port a special 17 * tag is used by the GSW1xx. 18 * 19 * Dest MAC Src MAC special TAG EtherType 20 * ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 7 8 | 1 2 |... 21 * |<--------------->| 22 */ 23 24#define GSW1XX_TAG_NAME "gsw1xx" 25 26/* special tag header length (RX and TX) */ 27#define GSW1XX_HEADER_LEN 8 28 29/* Word 0 = Ethertype -> 0x88C3 */ 30 31/* Word 1 */ 32#define GSW1XX_TX_PORT_MAP GENMASK(7, 0) 33#define GSW1XX_TX_PORT_MAP_EN BIT(15) 34#define GSW1XX_TX_CLASS_EN BIT(14) 35#define GSW1XX_TX_TIME_STAMP_EN BIT(13) 36#define GSW1XX_TX_LRN_DIS BIT(12) 37#define GSW1XX_TX_CLASS GENMASK(11, 8) 38 39/* special tag in RX path header */ 40/* Word 2 */ 41#define GSW1XX_RX_PORT_MAP GENMASK(15, 8) 42 43static struct sk_buff *gsw1xx_tag_xmit(struct sk_buff *skb, 44 struct net_device *dev) 45{ 46 __be16 *gsw1xx_tag; 47 u16 tag; 48 49 /* provide additional space 'GSW1XX_HEADER_LEN' bytes */ 50 skb_push(skb, GSW1XX_HEADER_LEN); 51 52 /* add space between MAC address and Ethertype */ 53 dsa_alloc_etype_header(skb, GSW1XX_HEADER_LEN); 54 55 /* special tag ingress */ 56 gsw1xx_tag = dsa_etype_header_pos_tx(skb); 57 gsw1xx_tag[0] = htons(ETH_P_MXLGSW); 58 59 tag = FIELD_PREP(GSW1XX_TX_PORT_MAP, dsa_xmit_port_mask(skb, dev)) | 60 GSW1XX_TX_PORT_MAP_EN | GSW1XX_TX_LRN_DIS; 61 gsw1xx_tag[1] = htons(tag); 62 gsw1xx_tag[2] = 0; 63 gsw1xx_tag[3] = 0; 64 65 return skb; 66} 67 68static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb, 69 struct net_device *dev) 70{ 71 int port; 72 __be16 *gsw1xx_tag; 73 74 if (unlikely(!pskb_may_pull(skb, GSW1XX_HEADER_LEN))) { 75 dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull SKB\n"); 76 return NULL; 77 } 78 79 gsw1xx_tag = dsa_etype_header_pos_rx(skb); 80 81 if (unlikely(ntohs(gsw1xx_tag[0]) != ETH_P_MXLGSW)) { 82 dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid special tag\n"); 83 dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag); 84 return NULL; 85 } 86 87 /* Get source port information */ 88 port = FIELD_GET(GSW1XX_RX_PORT_MAP, ntohs(gsw1xx_tag[1])); 89 skb->dev = dsa_conduit_find_user(dev, 0, port); 90 if (!skb->dev) { 91 dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n"); 92 dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag); 93 return NULL; 94 } 95 96 /* remove the GSW1xx special tag between MAC addresses and the current 97 * ethertype field. 98 */ 99 skb_pull_rcsum(skb, GSW1XX_HEADER_LEN); 100 dsa_strip_etype_header(skb, GSW1XX_HEADER_LEN); 101 102 return skb; 103} 104 105static const struct dsa_device_ops gsw1xx_netdev_ops = { 106 .name = GSW1XX_TAG_NAME, 107 .proto = DSA_TAG_PROTO_MXL_GSW1XX, 108 .xmit = gsw1xx_tag_xmit, 109 .rcv = gsw1xx_tag_rcv, 110 .needed_headroom = GSW1XX_HEADER_LEN, 111}; 112 113MODULE_DESCRIPTION("DSA tag driver for MaxLinear GSW1xx 8 byte protocol"); 114MODULE_LICENSE("GPL"); 115MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL_GSW1XX, GSW1XX_TAG_NAME); 116 117module_dsa_tag_driver(gsw1xx_netdev_ops);
~/
Read-only file preview.