提交 5037d532 编写于 作者: F Florian Fainelli 提交者: David S. Miller

net: dsa: add Broadcom tag RX/TX handler

Add support for the 4-bytes Broadcom tag that built-in switches such as
the Starfighter 2 might insert when receiving packets, or that we need
to insert while targetting specific switch ports. We use a fake local
EtherType value for this 4-bytes switch tag: ETH_P_BRCMTAG to make sure
we can assign DSA-specific network operations within the DSA drivers.
Signed-off-by: NFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 ce31b31c
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -19,6 +19,11 @@
#include <linux/phy.h>
#include <linux/phy_fixed.h>
/* Not an official ethertype value, used only internally for DSA
* demultiplexing
*/
#define ETH_P_BRCMTAG (ETH_P_XDSA + 1)
#define DSA_MAX_SWITCHES 4
#define DSA_MAX_PORTS 12
......
......@@ -12,6 +12,9 @@ config NET_DSA
if NET_DSA
# tagging formats
config NET_DSA_TAG_BRCM
bool
config NET_DSA_TAG_DSA
bool
......
......@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o slave.o
# tagging formats
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
......@@ -57,5 +57,8 @@ extern const struct dsa_device_ops edsa_netdev_ops;
/* tag_trailer.c */
extern const struct dsa_device_ops trailer_netdev_ops;
/* tag_brcm.c */
extern const struct dsa_device_ops brcm_netdev_ops;
#endif
......@@ -450,6 +450,11 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
case htons(ETH_P_TRAILER):
ds->dst->ops = &trailer_netdev_ops;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM
case htons(ETH_P_BRCMTAG):
ds->dst->ops = &brcm_netdev_ops;
break;
#endif
default:
ds->dst->ops = &notag_netdev_ops;
......
/*
* Broadcom tag support
*
* Copyright (C) 2014 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/etherdevice.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include "dsa_priv.h"
/* This tag length is 4 bytes, older ones were 6 bytes, we do not
* handle them
*/
#define BRCM_TAG_LEN 4
/* Tag is constructed and desconstructed using byte by byte access
* because the tag is placed after the MAC Source Address, which does
* not make it 4-bytes aligned, so this might cause unaligned accesses
* on most systems where this is used.
*/
/* Ingress and egress opcodes */
#define BRCM_OPCODE_SHIFT 5
#define BRCM_OPCODE_MASK 0x7
/* Ingress fields */
/* 1st byte in the tag */
#define BRCM_IG_TC_SHIFT 2
#define BRCM_IG_TC_MASK 0x7
/* 2nd byte in the tag */
#define BRCM_IG_TE_MASK 0x3
#define BRCM_IG_TS_SHIFT 7
/* 3rd byte in the tag */
#define BRCM_IG_DSTMAP2_MASK 1
#define BRCM_IG_DSTMAP1_MASK 0xff
/* Egress fields */
/* 2nd byte in the tag */
#define BRCM_EG_CID_MASK 0xff
/* 3rd byte in the tag */
#define BRCM_EG_RC_MASK 0xff
#define BRCM_EG_RC_RSVD (3 << 6)
#define BRCM_EG_RC_EXCEPTION (1 << 5)
#define BRCM_EG_RC_PROT_SNOOP (1 << 4)
#define BRCM_EG_RC_PROT_TERM (1 << 3)
#define BRCM_EG_RC_SWITCH (1 << 2)
#define BRCM_EG_RC_MAC_LEARN (1 << 1)
#define BRCM_EG_RC_MIRROR (1 << 0)
#define BRCM_EG_TC_SHIFT 5
#define BRCM_EG_TC_MASK 0x7
#define BRCM_EG_PID_MASK 0x1f
static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
u8 *brcm_tag;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
goto out_free;
skb_push(skb, BRCM_TAG_LEN);
memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN);
/* Build the tag after the MAC Source Address */
brcm_tag = skb->data + 2 * ETH_ALEN;
/* Set the ingress opcode, traffic class, tag enforcment is
* deprecated
*/
brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK);
brcm_tag[1] = 0;
brcm_tag[2] = 0;
if (p->port == 8)
brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
/* Queue the SKB for transmission on the parent interface, but
* do not modify its EtherType
*/
skb->protocol = htons(ETH_P_BRCMTAG);
skb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(skb);
return NETDEV_TX_OK;
out_free:
kfree_skb(skb);
return NETDEV_TX_OK;
}
static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
int source_port;
u8 *brcm_tag;
if (unlikely(dst == NULL))
goto out_drop;
ds = dst->ds[0];
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL)
goto out;
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
goto out_drop;
/* skb->data points to the EtherType, the tag is right before it */
brcm_tag = skb->data - 2;
/* The opcode should never be different than 0b000 */
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
goto out_drop;
/* We should never see a reserved reason code without knowing how to
* handle it
*/
WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD);
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
/* Validate port against switch setup, either the port is totally */
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
goto out_drop;
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
/* Move the Ethernet DA and SA */
memmove(skb->data - ETH_HLEN,
skb->data - ETH_HLEN - BRCM_TAG_LEN,
2 * ETH_ALEN);
skb_push(skb, ETH_HLEN);
skb->pkt_type = PACKET_HOST;
skb->dev = ds->ports[source_port];
skb->protocol = eth_type_trans(skb, skb->dev);
skb->dev->stats.rx_packets++;
skb->dev->stats.rx_bytes += skb->len;
netif_receive_skb(skb);
return 0;
out_drop:
kfree_skb(skb);
out:
return 0;
}
const struct dsa_device_ops brcm_netdev_ops = {
.xmit = brcm_tag_xmit,
.rcv = brcm_tag_rcv,
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部