root/net/dsa/tag_brcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. brcm_tag_xmit_ll
  2. brcm_tag_rcv_ll
  3. brcm_tag_xmit
  4. brcm_tag_rcv
  5. brcm_tag_xmit_prepend
  6. brcm_tag_rcv_prepend

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Broadcom tag support
   4  *
   5  * Copyright (C) 2014 Broadcom Corporation
   6  */
   7 
   8 #include <linux/etherdevice.h>
   9 #include <linux/list.h>
  10 #include <linux/slab.h>
  11 
  12 #include "dsa_priv.h"
  13 
  14 /* This tag length is 4 bytes, older ones were 6 bytes, we do not
  15  * handle them
  16  */
  17 #define BRCM_TAG_LEN    4
  18 
  19 /* Tag is constructed and desconstructed using byte by byte access
  20  * because the tag is placed after the MAC Source Address, which does
  21  * not make it 4-bytes aligned, so this might cause unaligned accesses
  22  * on most systems where this is used.
  23  */
  24 
  25 /* Ingress and egress opcodes */
  26 #define BRCM_OPCODE_SHIFT       5
  27 #define BRCM_OPCODE_MASK        0x7
  28 
  29 /* Ingress fields */
  30 /* 1st byte in the tag */
  31 #define BRCM_IG_TC_SHIFT        2
  32 #define BRCM_IG_TC_MASK         0x7
  33 /* 2nd byte in the tag */
  34 #define BRCM_IG_TE_MASK         0x3
  35 #define BRCM_IG_TS_SHIFT        7
  36 /* 3rd byte in the tag */
  37 #define BRCM_IG_DSTMAP2_MASK    1
  38 #define BRCM_IG_DSTMAP1_MASK    0xff
  39 
  40 /* Egress fields */
  41 
  42 /* 2nd byte in the tag */
  43 #define BRCM_EG_CID_MASK        0xff
  44 
  45 /* 3rd byte in the tag */
  46 #define BRCM_EG_RC_MASK         0xff
  47 #define  BRCM_EG_RC_RSVD        (3 << 6)
  48 #define  BRCM_EG_RC_EXCEPTION   (1 << 5)
  49 #define  BRCM_EG_RC_PROT_SNOOP  (1 << 4)
  50 #define  BRCM_EG_RC_PROT_TERM   (1 << 3)
  51 #define  BRCM_EG_RC_SWITCH      (1 << 2)
  52 #define  BRCM_EG_RC_MAC_LEARN   (1 << 1)
  53 #define  BRCM_EG_RC_MIRROR      (1 << 0)
  54 #define BRCM_EG_TC_SHIFT        5
  55 #define BRCM_EG_TC_MASK         0x7
  56 #define BRCM_EG_PID_MASK        0x1f
  57 
  58 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM) || \
  59         IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
  60 
  61 static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
  62                                         struct net_device *dev,
  63                                         unsigned int offset)
  64 {
  65         struct dsa_port *dp = dsa_slave_to_port(dev);
  66         u16 queue = skb_get_queue_mapping(skb);
  67         u8 *brcm_tag;
  68 
  69         if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
  70                 return NULL;
  71 
  72         /* The Ethernet switch we are interfaced with needs packets to be at
  73          * least 64 bytes (including FCS) otherwise they will be discarded when
  74          * they enter the switch port logic. When Broadcom tags are enabled, we
  75          * need to make sure that packets are at least 68 bytes
  76          * (including FCS and tag) because the length verification is done after
  77          * the Broadcom tag is stripped off the ingress packet.
  78          *
  79          * Let dsa_slave_xmit() free the SKB
  80          */
  81         if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false))
  82                 return NULL;
  83 
  84         skb_push(skb, BRCM_TAG_LEN);
  85 
  86         if (offset)
  87                 memmove(skb->data, skb->data + BRCM_TAG_LEN, offset);
  88 
  89         brcm_tag = skb->data + offset;
  90 
  91         /* Set the ingress opcode, traffic class, tag enforcment is
  92          * deprecated
  93          */
  94         brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
  95                        ((queue & BRCM_IG_TC_MASK) << BRCM_IG_TC_SHIFT);
  96         brcm_tag[1] = 0;
  97         brcm_tag[2] = 0;
  98         if (dp->index == 8)
  99                 brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
 100         brcm_tag[3] = (1 << dp->index) & BRCM_IG_DSTMAP1_MASK;
 101 
 102         /* Now tell the master network device about the desired output queue
 103          * as well
 104          */
 105         skb_set_queue_mapping(skb, BRCM_TAG_SET_PORT_QUEUE(dp->index, queue));
 106 
 107         return skb;
 108 }
 109 
 110 static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
 111                                        struct net_device *dev,
 112                                        struct packet_type *pt,
 113                                        unsigned int offset)
 114 {
 115         int source_port;
 116         u8 *brcm_tag;
 117 
 118         if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
 119                 return NULL;
 120 
 121         brcm_tag = skb->data - offset;
 122 
 123         /* The opcode should never be different than 0b000 */
 124         if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
 125                 return NULL;
 126 
 127         /* We should never see a reserved reason code without knowing how to
 128          * handle it
 129          */
 130         if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
 131                 return NULL;
 132 
 133         /* Locate which port this is coming from */
 134         source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
 135 
 136         skb->dev = dsa_master_find_slave(dev, 0, source_port);
 137         if (!skb->dev)
 138                 return NULL;
 139 
 140         /* Remove Broadcom tag and update checksum */
 141         skb_pull_rcsum(skb, BRCM_TAG_LEN);
 142 
 143         skb->offload_fwd_mark = 1;
 144 
 145         return skb;
 146 }
 147 #endif
 148 
 149 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
 150 static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb,
 151                                      struct net_device *dev)
 152 {
 153         /* Build the tag after the MAC Source Address */
 154         return brcm_tag_xmit_ll(skb, dev, 2 * ETH_ALEN);
 155 }
 156 
 157 
 158 static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
 159                                     struct packet_type *pt)
 160 {
 161         struct sk_buff *nskb;
 162 
 163         /* skb->data points to the EtherType, the tag is right before it */
 164         nskb = brcm_tag_rcv_ll(skb, dev, pt, 2);
 165         if (!nskb)
 166                 return nskb;
 167 
 168         /* Move the Ethernet DA and SA */
 169         memmove(nskb->data - ETH_HLEN,
 170                 nskb->data - ETH_HLEN - BRCM_TAG_LEN,
 171                 2 * ETH_ALEN);
 172 
 173         return nskb;
 174 }
 175 
 176 static const struct dsa_device_ops brcm_netdev_ops = {
 177         .name   = "brcm",
 178         .proto  = DSA_TAG_PROTO_BRCM,
 179         .xmit   = brcm_tag_xmit,
 180         .rcv    = brcm_tag_rcv,
 181         .overhead = BRCM_TAG_LEN,
 182 };
 183 
 184 DSA_TAG_DRIVER(brcm_netdev_ops);
 185 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM);
 186 #endif
 187 
 188 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
 189 static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
 190                                              struct net_device *dev)
 191 {
 192         /* tag is prepended to the packet */
 193         return brcm_tag_xmit_ll(skb, dev, 0);
 194 }
 195 
 196 static struct sk_buff *brcm_tag_rcv_prepend(struct sk_buff *skb,
 197                                             struct net_device *dev,
 198                                             struct packet_type *pt)
 199 {
 200         /* tag is prepended to the packet */
 201         return brcm_tag_rcv_ll(skb, dev, pt, ETH_HLEN);
 202 }
 203 
 204 static const struct dsa_device_ops brcm_prepend_netdev_ops = {
 205         .name   = "brcm-prepend",
 206         .proto  = DSA_TAG_PROTO_BRCM_PREPEND,
 207         .xmit   = brcm_tag_xmit_prepend,
 208         .rcv    = brcm_tag_rcv_prepend,
 209         .overhead = BRCM_TAG_LEN,
 210 };
 211 
 212 DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
 213 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND);
 214 #endif
 215 
 216 static struct dsa_tag_driver *dsa_tag_driver_array[] =  {
 217 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
 218         &DSA_TAG_DRIVER_NAME(brcm_netdev_ops),
 219 #endif
 220 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
 221         &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
 222 #endif
 223 };
 224 
 225 module_dsa_tag_drivers(dsa_tag_driver_array);
 226 
 227 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */