cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tag_brcm.c (8795B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Broadcom tag support
      4 *
      5 * Copyright (C) 2014 Broadcom Corporation
      6 */
      7
      8#include <linux/dsa/brcm.h>
      9#include <linux/etherdevice.h>
     10#include <linux/list.h>
     11#include <linux/slab.h>
     12
     13#include "dsa_priv.h"
     14
     15/* Legacy Broadcom tag (6 bytes) */
     16#define BRCM_LEG_TAG_LEN	6
     17
     18/* Type fields */
     19/* 1st byte in the tag */
     20#define BRCM_LEG_TYPE_HI	0x88
     21/* 2nd byte in the tag */
     22#define BRCM_LEG_TYPE_LO	0x74
     23
     24/* Tag fields */
     25/* 3rd byte in the tag */
     26#define BRCM_LEG_UNICAST	(0 << 5)
     27#define BRCM_LEG_MULTICAST	(1 << 5)
     28#define BRCM_LEG_EGRESS		(2 << 5)
     29#define BRCM_LEG_INGRESS	(3 << 5)
     30
     31/* 6th byte in the tag */
     32#define BRCM_LEG_PORT_ID	(0xf)
     33
     34/* Newer Broadcom tag (4 bytes) */
     35#define BRCM_TAG_LEN	4
     36
     37/* Tag is constructed and desconstructed using byte by byte access
     38 * because the tag is placed after the MAC Source Address, which does
     39 * not make it 4-bytes aligned, so this might cause unaligned accesses
     40 * on most systems where this is used.
     41 */
     42
     43/* Ingress and egress opcodes */
     44#define BRCM_OPCODE_SHIFT	5
     45#define BRCM_OPCODE_MASK	0x7
     46
     47/* Ingress fields */
     48/* 1st byte in the tag */
     49#define BRCM_IG_TC_SHIFT	2
     50#define BRCM_IG_TC_MASK		0x7
     51/* 2nd byte in the tag */
     52#define BRCM_IG_TE_MASK		0x3
     53#define BRCM_IG_TS_SHIFT	7
     54/* 3rd byte in the tag */
     55#define BRCM_IG_DSTMAP2_MASK	1
     56#define BRCM_IG_DSTMAP1_MASK	0xff
     57
     58/* Egress fields */
     59
     60/* 2nd byte in the tag */
     61#define BRCM_EG_CID_MASK	0xff
     62
     63/* 3rd byte in the tag */
     64#define BRCM_EG_RC_MASK		0xff
     65#define  BRCM_EG_RC_RSVD	(3 << 6)
     66#define  BRCM_EG_RC_EXCEPTION	(1 << 5)
     67#define  BRCM_EG_RC_PROT_SNOOP	(1 << 4)
     68#define  BRCM_EG_RC_PROT_TERM	(1 << 3)
     69#define  BRCM_EG_RC_SWITCH	(1 << 2)
     70#define  BRCM_EG_RC_MAC_LEARN	(1 << 1)
     71#define  BRCM_EG_RC_MIRROR	(1 << 0)
     72#define BRCM_EG_TC_SHIFT	5
     73#define BRCM_EG_TC_MASK		0x7
     74#define BRCM_EG_PID_MASK	0x1f
     75
     76#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM) || \
     77	IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
     78
     79static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
     80					struct net_device *dev,
     81					unsigned int offset)
     82{
     83	struct dsa_port *dp = dsa_slave_to_port(dev);
     84	u16 queue = skb_get_queue_mapping(skb);
     85	u8 *brcm_tag;
     86
     87	/* The Ethernet switch we are interfaced with needs packets to be at
     88	 * least 64 bytes (including FCS) otherwise they will be discarded when
     89	 * they enter the switch port logic. When Broadcom tags are enabled, we
     90	 * need to make sure that packets are at least 68 bytes
     91	 * (including FCS and tag) because the length verification is done after
     92	 * the Broadcom tag is stripped off the ingress packet.
     93	 *
     94	 * Let dsa_slave_xmit() free the SKB
     95	 */
     96	if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false))
     97		return NULL;
     98
     99	skb_push(skb, BRCM_TAG_LEN);
    100
    101	if (offset)
    102		dsa_alloc_etype_header(skb, BRCM_TAG_LEN);
    103
    104	brcm_tag = skb->data + offset;
    105
    106	/* Set the ingress opcode, traffic class, tag enforcment is
    107	 * deprecated
    108	 */
    109	brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
    110		       ((queue & BRCM_IG_TC_MASK) << BRCM_IG_TC_SHIFT);
    111	brcm_tag[1] = 0;
    112	brcm_tag[2] = 0;
    113	if (dp->index == 8)
    114		brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
    115	brcm_tag[3] = (1 << dp->index) & BRCM_IG_DSTMAP1_MASK;
    116
    117	/* Now tell the master network device about the desired output queue
    118	 * as well
    119	 */
    120	skb_set_queue_mapping(skb, BRCM_TAG_SET_PORT_QUEUE(dp->index, queue));
    121
    122	return skb;
    123}
    124
    125/* Frames with this tag have one of these two layouts:
    126 * -----------------------------------
    127 * | MAC DA | MAC SA | 4b tag | Type | DSA_TAG_PROTO_BRCM
    128 * -----------------------------------
    129 * -----------------------------------
    130 * | 4b tag | MAC DA | MAC SA | Type | DSA_TAG_PROTO_BRCM_PREPEND
    131 * -----------------------------------
    132 * In both cases, at receive time, skb->data points 2 bytes before the actual
    133 * Ethernet type field and we have an offset of 4bytes between where skb->data
    134 * and where the payload starts. So the same low-level receive function can be
    135 * used.
    136 */
    137static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
    138				       struct net_device *dev,
    139				       unsigned int offset)
    140{
    141	int source_port;
    142	u8 *brcm_tag;
    143
    144	if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
    145		return NULL;
    146
    147	brcm_tag = skb->data - offset;
    148
    149	/* The opcode should never be different than 0b000 */
    150	if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
    151		return NULL;
    152
    153	/* We should never see a reserved reason code without knowing how to
    154	 * handle it
    155	 */
    156	if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
    157		return NULL;
    158
    159	/* Locate which port this is coming from */
    160	source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
    161
    162	skb->dev = dsa_master_find_slave(dev, 0, source_port);
    163	if (!skb->dev)
    164		return NULL;
    165
    166	/* Remove Broadcom tag and update checksum */
    167	skb_pull_rcsum(skb, BRCM_TAG_LEN);
    168
    169	dsa_default_offload_fwd_mark(skb);
    170
    171	return skb;
    172}
    173#endif
    174
    175#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
    176static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb,
    177				     struct net_device *dev)
    178{
    179	/* Build the tag after the MAC Source Address */
    180	return brcm_tag_xmit_ll(skb, dev, 2 * ETH_ALEN);
    181}
    182
    183
    184static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev)
    185{
    186	struct sk_buff *nskb;
    187
    188	/* skb->data points to the EtherType, the tag is right before it */
    189	nskb = brcm_tag_rcv_ll(skb, dev, 2);
    190	if (!nskb)
    191		return nskb;
    192
    193	dsa_strip_etype_header(skb, BRCM_TAG_LEN);
    194
    195	return nskb;
    196}
    197
    198static const struct dsa_device_ops brcm_netdev_ops = {
    199	.name	= "brcm",
    200	.proto	= DSA_TAG_PROTO_BRCM,
    201	.xmit	= brcm_tag_xmit,
    202	.rcv	= brcm_tag_rcv,
    203	.needed_headroom = BRCM_TAG_LEN,
    204};
    205
    206DSA_TAG_DRIVER(brcm_netdev_ops);
    207MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM);
    208#endif
    209
    210#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
    211static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
    212					 struct net_device *dev)
    213{
    214	struct dsa_port *dp = dsa_slave_to_port(dev);
    215	u8 *brcm_tag;
    216
    217	/* The Ethernet switch we are interfaced with needs packets to be at
    218	 * least 64 bytes (including FCS) otherwise they will be discarded when
    219	 * they enter the switch port logic. When Broadcom tags are enabled, we
    220	 * need to make sure that packets are at least 70 bytes
    221	 * (including FCS and tag) because the length verification is done after
    222	 * the Broadcom tag is stripped off the ingress packet.
    223	 *
    224	 * Let dsa_slave_xmit() free the SKB
    225	 */
    226	if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
    227		return NULL;
    228
    229	skb_push(skb, BRCM_LEG_TAG_LEN);
    230
    231	dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
    232
    233	brcm_tag = skb->data + 2 * ETH_ALEN;
    234
    235	/* Broadcom tag type */
    236	brcm_tag[0] = BRCM_LEG_TYPE_HI;
    237	brcm_tag[1] = BRCM_LEG_TYPE_LO;
    238
    239	/* Broadcom tag value */
    240	brcm_tag[2] = BRCM_LEG_EGRESS;
    241	brcm_tag[3] = 0;
    242	brcm_tag[4] = 0;
    243	brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
    244
    245	return skb;
    246}
    247
    248static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
    249					struct net_device *dev)
    250{
    251	int source_port;
    252	u8 *brcm_tag;
    253
    254	if (unlikely(!pskb_may_pull(skb, BRCM_LEG_PORT_ID)))
    255		return NULL;
    256
    257	brcm_tag = dsa_etype_header_pos_rx(skb);
    258
    259	source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
    260
    261	skb->dev = dsa_master_find_slave(dev, 0, source_port);
    262	if (!skb->dev)
    263		return NULL;
    264
    265	/* Remove Broadcom tag and update checksum */
    266	skb_pull_rcsum(skb, BRCM_LEG_TAG_LEN);
    267
    268	dsa_default_offload_fwd_mark(skb);
    269
    270	dsa_strip_etype_header(skb, BRCM_LEG_TAG_LEN);
    271
    272	return skb;
    273}
    274
    275static const struct dsa_device_ops brcm_legacy_netdev_ops = {
    276	.name = "brcm-legacy",
    277	.proto = DSA_TAG_PROTO_BRCM_LEGACY,
    278	.xmit = brcm_leg_tag_xmit,
    279	.rcv = brcm_leg_tag_rcv,
    280	.needed_headroom = BRCM_LEG_TAG_LEN,
    281};
    282
    283DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
    284MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY);
    285#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */
    286
    287#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
    288static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
    289					     struct net_device *dev)
    290{
    291	/* tag is prepended to the packet */
    292	return brcm_tag_xmit_ll(skb, dev, 0);
    293}
    294
    295static struct sk_buff *brcm_tag_rcv_prepend(struct sk_buff *skb,
    296					    struct net_device *dev)
    297{
    298	/* tag is prepended to the packet */
    299	return brcm_tag_rcv_ll(skb, dev, ETH_HLEN);
    300}
    301
    302static const struct dsa_device_ops brcm_prepend_netdev_ops = {
    303	.name	= "brcm-prepend",
    304	.proto	= DSA_TAG_PROTO_BRCM_PREPEND,
    305	.xmit	= brcm_tag_xmit_prepend,
    306	.rcv	= brcm_tag_rcv_prepend,
    307	.needed_headroom = BRCM_TAG_LEN,
    308};
    309
    310DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
    311MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND);
    312#endif
    313
    314static struct dsa_tag_driver *dsa_tag_driver_array[] =	{
    315#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
    316	&DSA_TAG_DRIVER_NAME(brcm_netdev_ops),
    317#endif
    318#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
    319	&DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops),
    320#endif
    321#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
    322	&DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
    323#endif
    324};
    325
    326module_dsa_tag_drivers(dsa_tag_driver_array);
    327
    328MODULE_LICENSE("GPL");