0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/dsa/brcm.h>
0009 #include <linux/etherdevice.h>
0010 #include <linux/list.h>
0011 #include <linux/slab.h>
0012
0013 #include "dsa_priv.h"
0014
0015
0016 #define BRCM_LEG_TAG_LEN 6
0017
0018
0019
0020 #define BRCM_LEG_TYPE_HI 0x88
0021
0022 #define BRCM_LEG_TYPE_LO 0x74
0023
0024
0025
0026 #define BRCM_LEG_UNICAST (0 << 5)
0027 #define BRCM_LEG_MULTICAST (1 << 5)
0028 #define BRCM_LEG_EGRESS (2 << 5)
0029 #define BRCM_LEG_INGRESS (3 << 5)
0030
0031
0032 #define BRCM_LEG_PORT_ID (0xf)
0033
0034
0035 #define BRCM_TAG_LEN 4
0036
0037
0038
0039
0040
0041
0042
0043
0044 #define BRCM_OPCODE_SHIFT 5
0045 #define BRCM_OPCODE_MASK 0x7
0046
0047
0048
0049 #define BRCM_IG_TC_SHIFT 2
0050 #define BRCM_IG_TC_MASK 0x7
0051
0052 #define BRCM_IG_TE_MASK 0x3
0053 #define BRCM_IG_TS_SHIFT 7
0054
0055 #define BRCM_IG_DSTMAP2_MASK 1
0056 #define BRCM_IG_DSTMAP1_MASK 0xff
0057
0058
0059
0060
0061 #define BRCM_EG_CID_MASK 0xff
0062
0063
0064 #define BRCM_EG_RC_MASK 0xff
0065 #define BRCM_EG_RC_RSVD (3 << 6)
0066 #define BRCM_EG_RC_EXCEPTION (1 << 5)
0067 #define BRCM_EG_RC_PROT_SNOOP (1 << 4)
0068 #define BRCM_EG_RC_PROT_TERM (1 << 3)
0069 #define BRCM_EG_RC_SWITCH (1 << 2)
0070 #define BRCM_EG_RC_MAC_LEARN (1 << 1)
0071 #define BRCM_EG_RC_MIRROR (1 << 0)
0072 #define BRCM_EG_TC_SHIFT 5
0073 #define BRCM_EG_TC_MASK 0x7
0074 #define BRCM_EG_PID_MASK 0x1f
0075
0076 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM) || \
0077 IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
0078
0079 static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
0080 struct net_device *dev,
0081 unsigned int offset)
0082 {
0083 struct dsa_port *dp = dsa_slave_to_port(dev);
0084 u16 queue = skb_get_queue_mapping(skb);
0085 u8 *brcm_tag;
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false))
0097 return NULL;
0098
0099 skb_push(skb, BRCM_TAG_LEN);
0100
0101 if (offset)
0102 dsa_alloc_etype_header(skb, BRCM_TAG_LEN);
0103
0104 brcm_tag = skb->data + offset;
0105
0106
0107
0108
0109 brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
0110 ((queue & BRCM_IG_TC_MASK) << BRCM_IG_TC_SHIFT);
0111 brcm_tag[1] = 0;
0112 brcm_tag[2] = 0;
0113 if (dp->index == 8)
0114 brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
0115 brcm_tag[3] = (1 << dp->index) & BRCM_IG_DSTMAP1_MASK;
0116
0117
0118
0119
0120 skb_set_queue_mapping(skb, BRCM_TAG_SET_PORT_QUEUE(dp->index, queue));
0121
0122 return skb;
0123 }
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
0138 struct net_device *dev,
0139 unsigned int offset)
0140 {
0141 int source_port;
0142 u8 *brcm_tag;
0143
0144 if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
0145 return NULL;
0146
0147 brcm_tag = skb->data - offset;
0148
0149
0150 if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
0151 return NULL;
0152
0153
0154
0155
0156 if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
0157 return NULL;
0158
0159
0160 source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
0161
0162 skb->dev = dsa_master_find_slave(dev, 0, source_port);
0163 if (!skb->dev)
0164 return NULL;
0165
0166
0167 skb_pull_rcsum(skb, BRCM_TAG_LEN);
0168
0169 dsa_default_offload_fwd_mark(skb);
0170
0171 return skb;
0172 }
0173 #endif
0174
0175 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
0176 static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb,
0177 struct net_device *dev)
0178 {
0179
0180 return brcm_tag_xmit_ll(skb, dev, 2 * ETH_ALEN);
0181 }
0182
0183
0184 static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev)
0185 {
0186 struct sk_buff *nskb;
0187
0188
0189 nskb = brcm_tag_rcv_ll(skb, dev, 2);
0190 if (!nskb)
0191 return nskb;
0192
0193 dsa_strip_etype_header(skb, BRCM_TAG_LEN);
0194
0195 return nskb;
0196 }
0197
0198 static const struct dsa_device_ops brcm_netdev_ops = {
0199 .name = "brcm",
0200 .proto = DSA_TAG_PROTO_BRCM,
0201 .xmit = brcm_tag_xmit,
0202 .rcv = brcm_tag_rcv,
0203 .needed_headroom = BRCM_TAG_LEN,
0204 };
0205
0206 DSA_TAG_DRIVER(brcm_netdev_ops);
0207 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM);
0208 #endif
0209
0210 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
0211 static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
0212 struct net_device *dev)
0213 {
0214 struct dsa_port *dp = dsa_slave_to_port(dev);
0215 u8 *brcm_tag;
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
0227 return NULL;
0228
0229 skb_push(skb, BRCM_LEG_TAG_LEN);
0230
0231 dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
0232
0233 brcm_tag = skb->data + 2 * ETH_ALEN;
0234
0235
0236 brcm_tag[0] = BRCM_LEG_TYPE_HI;
0237 brcm_tag[1] = BRCM_LEG_TYPE_LO;
0238
0239
0240 brcm_tag[2] = BRCM_LEG_EGRESS;
0241 brcm_tag[3] = 0;
0242 brcm_tag[4] = 0;
0243 brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
0244
0245 return skb;
0246 }
0247
0248 static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
0249 struct net_device *dev)
0250 {
0251 int source_port;
0252 u8 *brcm_tag;
0253
0254 if (unlikely(!pskb_may_pull(skb, BRCM_LEG_PORT_ID)))
0255 return NULL;
0256
0257 brcm_tag = dsa_etype_header_pos_rx(skb);
0258
0259 source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
0260
0261 skb->dev = dsa_master_find_slave(dev, 0, source_port);
0262 if (!skb->dev)
0263 return NULL;
0264
0265
0266 skb_pull_rcsum(skb, BRCM_LEG_TAG_LEN);
0267
0268 dsa_default_offload_fwd_mark(skb);
0269
0270 dsa_strip_etype_header(skb, BRCM_LEG_TAG_LEN);
0271
0272 return skb;
0273 }
0274
0275 static const struct dsa_device_ops brcm_legacy_netdev_ops = {
0276 .name = "brcm-legacy",
0277 .proto = DSA_TAG_PROTO_BRCM_LEGACY,
0278 .xmit = brcm_leg_tag_xmit,
0279 .rcv = brcm_leg_tag_rcv,
0280 .needed_headroom = BRCM_LEG_TAG_LEN,
0281 };
0282
0283 DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
0284 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY);
0285 #endif
0286
0287 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
0288 static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
0289 struct net_device *dev)
0290 {
0291
0292 return brcm_tag_xmit_ll(skb, dev, 0);
0293 }
0294
0295 static struct sk_buff *brcm_tag_rcv_prepend(struct sk_buff *skb,
0296 struct net_device *dev)
0297 {
0298
0299 return brcm_tag_rcv_ll(skb, dev, ETH_HLEN);
0300 }
0301
0302 static const struct dsa_device_ops brcm_prepend_netdev_ops = {
0303 .name = "brcm-prepend",
0304 .proto = DSA_TAG_PROTO_BRCM_PREPEND,
0305 .xmit = brcm_tag_xmit_prepend,
0306 .rcv = brcm_tag_rcv_prepend,
0307 .needed_headroom = BRCM_TAG_LEN,
0308 };
0309
0310 DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
0311 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND);
0312 #endif
0313
0314 static struct dsa_tag_driver *dsa_tag_driver_array[] = {
0315 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
0316 &DSA_TAG_DRIVER_NAME(brcm_netdev_ops),
0317 #endif
0318 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
0319 &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops),
0320 #endif
0321 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
0322 &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
0323 #endif
0324 };
0325
0326 module_dsa_tag_drivers(dsa_tag_driver_array);
0327
0328 MODULE_LICENSE("GPL");