1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel / Lantiq GSWIP V2.0 PMAC tag support 4 * 5 * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de> 6 */ 7 8 #include <linux/bitops.h> 9 #include <linux/etherdevice.h> 10 #include <linux/skbuff.h> 11 #include <net/dsa.h> 12 13 #include "tag.h" 14 15 #define GSWIP_NAME "gswip" 16 17 #define GSWIP_TX_HEADER_LEN 4 18 19 /* special tag in TX path header */ 20 /* Byte 0 */ 21 #define GSWIP_TX_SLPID_SHIFT 0 /* source port ID */ 22 #define GSWIP_TX_SLPID_CPU 2 23 #define GSWIP_TX_SLPID_APP1 3 24 #define GSWIP_TX_SLPID_APP2 4 25 #define GSWIP_TX_SLPID_APP3 5 26 #define GSWIP_TX_SLPID_APP4 6 27 #define GSWIP_TX_SLPID_APP5 7 28 29 /* Byte 1 */ 30 #define GSWIP_TX_CRCGEN_DIS BIT(7) 31 #define GSWIP_TX_DPID_SHIFT 0 /* destination group ID */ 32 #define GSWIP_TX_DPID_ELAN 0 33 #define GSWIP_TX_DPID_EWAN 1 34 #define GSWIP_TX_DPID_CPU 2 35 #define GSWIP_TX_DPID_APP1 3 36 #define GSWIP_TX_DPID_APP2 4 37 #define GSWIP_TX_DPID_APP3 5 38 #define GSWIP_TX_DPID_APP4 6 39 #define GSWIP_TX_DPID_APP5 7 40 41 /* Byte 2 */ 42 #define GSWIP_TX_PORT_MAP_EN BIT(7) 43 #define GSWIP_TX_PORT_MAP_SEL BIT(6) 44 #define GSWIP_TX_LRN_DIS BIT(5) 45 #define GSWIP_TX_CLASS_EN BIT(4) 46 #define GSWIP_TX_CLASS_SHIFT 0 47 #define GSWIP_TX_CLASS_MASK GENMASK(3, 0) 48 49 /* Byte 3 */ 50 #define GSWIP_TX_DPID_EN BIT(0) 51 #define GSWIP_TX_PORT_MAP_SHIFT 1 52 #define GSWIP_TX_PORT_MAP_MASK GENMASK(6, 1) 53 54 #define GSWIP_RX_HEADER_LEN 8 55 56 /* special tag in RX path header */ 57 /* Byte 7 */ 58 #define GSWIP_RX_SPPID_SHIFT 4 59 #define GSWIP_RX_SPPID_MASK GENMASK(6, 4) 60 61 static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb, 62 struct net_device *dev) 63 { 64 struct dsa_port *dp = dsa_user_to_port(dev); 65 u8 *gswip_tag; 66 67 skb_push(skb, GSWIP_TX_HEADER_LEN); 68 69 gswip_tag = skb->data; 70 gswip_tag[0] = GSWIP_TX_SLPID_CPU; 71 gswip_tag[1] = GSWIP_TX_DPID_ELAN; 72 gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL; 73 gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK; 74 gswip_tag[3] |= GSWIP_TX_DPID_EN; 75 76 return skb; 77 } 78 79 static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, 80 struct net_device *dev) 81 { 82 int port; 83 u8 *gswip_tag; 84 85 if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) 86 return NULL; 87 88 gswip_tag = skb->data - ETH_HLEN; 89 90 /* Get source port information */ 91 port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; 92 skb->dev = dsa_conduit_find_user(dev, 0, port); 93 if (!skb->dev) 94 return NULL; 95 96 /* remove GSWIP tag */ 97 skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN); 98 99 return skb; 100 } 101 102 static const struct dsa_device_ops gswip_netdev_ops = { 103 .name = GSWIP_NAME, 104 .proto = DSA_TAG_PROTO_GSWIP, 105 .xmit = gswip_tag_xmit, 106 .rcv = gswip_tag_rcv, 107 .needed_headroom = GSWIP_RX_HEADER_LEN, 108 }; 109 110 MODULE_LICENSE("GPL"); 111 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP, GSWIP_NAME); 112 113 module_dsa_tag_driver(gswip_netdev_ops); 114