1/* 2 * Broadcom tag support 3 * 4 * Copyright (C) 2014 Broadcom Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12#include <linux/etherdevice.h> 13#include <linux/list.h> 14#include <linux/slab.h> 15#include "dsa_priv.h" 16 17/* This tag length is 4 bytes, older ones were 6 bytes, we do not 18 * handle them 19 */ 20#define BRCM_TAG_LEN 4 21 22/* Tag is constructed and desconstructed using byte by byte access 23 * because the tag is placed after the MAC Source Address, which does 24 * not make it 4-bytes aligned, so this might cause unaligned accesses 25 * on most systems where this is used. 26 */ 27 28/* Ingress and egress opcodes */ 29#define BRCM_OPCODE_SHIFT 5 30#define BRCM_OPCODE_MASK 0x7 31 32/* Ingress fields */ 33/* 1st byte in the tag */ 34#define BRCM_IG_TC_SHIFT 2 35#define BRCM_IG_TC_MASK 0x7 36/* 2nd byte in the tag */ 37#define BRCM_IG_TE_MASK 0x3 38#define BRCM_IG_TS_SHIFT 7 39/* 3rd byte in the tag */ 40#define BRCM_IG_DSTMAP2_MASK 1 41#define BRCM_IG_DSTMAP1_MASK 0xff 42 43/* Egress fields */ 44 45/* 2nd byte in the tag */ 46#define BRCM_EG_CID_MASK 0xff 47 48/* 3rd byte in the tag */ 49#define BRCM_EG_RC_MASK 0xff 50#define BRCM_EG_RC_RSVD (3 << 6) 51#define BRCM_EG_RC_EXCEPTION (1 << 5) 52#define BRCM_EG_RC_PROT_SNOOP (1 << 4) 53#define BRCM_EG_RC_PROT_TERM (1 << 3) 54#define BRCM_EG_RC_SWITCH (1 << 2) 55#define BRCM_EG_RC_MAC_LEARN (1 << 1) 56#define BRCM_EG_RC_MIRROR (1 << 0) 57#define BRCM_EG_TC_SHIFT 5 58#define BRCM_EG_TC_MASK 0x7 59#define BRCM_EG_PID_MASK 0x1f 60 61static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev) 62{ 63 struct dsa_slave_priv *p = netdev_priv(dev); 64 u8 *brcm_tag; 65 66 dev->stats.tx_packets++; 67 dev->stats.tx_bytes += skb->len; 68 69 if (skb_cow_head(skb, BRCM_TAG_LEN) < 0) 70 goto out_free; 71 72 skb_push(skb, BRCM_TAG_LEN); 73 74 memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN); 75 76 /* Build the tag after the MAC Source Address */ 77 brcm_tag = skb->data + 2 * ETH_ALEN; 78 79 /* Set the ingress opcode, traffic class, tag enforcment is 80 * deprecated 81 */ 82 brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) | 83 ((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK); 84 brcm_tag[1] = 0; 85 brcm_tag[2] = 0; 86 if (p->port == 8) 87 brcm_tag[2] = BRCM_IG_DSTMAP2_MASK; 88 brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK; 89 90 /* Queue the SKB for transmission on the parent interface, but 91 * do not modify its EtherType 92 */ 93 skb->dev = p->parent->dst->master_netdev; 94 dev_queue_xmit(skb); 95 96 return NETDEV_TX_OK; 97 98out_free: 99 kfree_skb(skb); 100 return NETDEV_TX_OK; 101} 102 103static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, 104 struct packet_type *pt, struct net_device *orig_dev) 105{ 106 struct dsa_switch_tree *dst = dev->dsa_ptr; 107 struct dsa_switch *ds; 108 int source_port; 109 u8 *brcm_tag; 110 111 if (unlikely(dst == NULL)) 112 goto out_drop; 113 114 ds = dst->ds[0]; 115 116 skb = skb_unshare(skb, GFP_ATOMIC); 117 if (skb == NULL) 118 goto out; 119 120 if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) 121 goto out_drop; 122 123 /* skb->data points to the EtherType, the tag is right before it */ 124 brcm_tag = skb->data - 2; 125 126 /* The opcode should never be different than 0b000 */ 127 if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) 128 goto out_drop; 129 130 /* We should never see a reserved reason code without knowing how to 131 * handle it 132 */ 133 WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD); 134 135 /* Locate which port this is coming from */ 136 source_port = brcm_tag[3] & BRCM_EG_PID_MASK; 137 138 /* Validate port against switch setup, either the port is totally */ 139 if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) 140 goto out_drop; 141 142 /* Remove Broadcom tag and update checksum */ 143 skb_pull_rcsum(skb, BRCM_TAG_LEN); 144 145 /* Move the Ethernet DA and SA */ 146 memmove(skb->data - ETH_HLEN, 147 skb->data - ETH_HLEN - BRCM_TAG_LEN, 148 2 * ETH_ALEN); 149 150 skb_push(skb, ETH_HLEN); 151 skb->pkt_type = PACKET_HOST; 152 skb->dev = ds->ports[source_port]; 153 skb->protocol = eth_type_trans(skb, skb->dev); 154 155 skb->dev->stats.rx_packets++; 156 skb->dev->stats.rx_bytes += skb->len; 157 158 netif_receive_skb(skb); 159 160 return 0; 161 162out_drop: 163 kfree_skb(skb); 164out: 165 return 0; 166} 167 168const struct dsa_device_ops brcm_netdev_ops = { 169 .xmit = brcm_tag_xmit, 170 .rcv = brcm_tag_rcv, 171}; 172