Merge branch 'dsa-b53-Support-prepended-Broadcom-tags'

Florian Fainelli says:

====================
net: dsa: b53: Support prepended Broadcom tags

This patch series adds support for prepended 4-bytes Broadcom tags that we
already support. This type of tag will typically be used when interfaced to
a SoC like BCM58xx (NorthStar Plus) which supports a Flow Accelerator (WIP).
In that case, we need to support a slightly different tagging format.

The first patch does a bit of re-factoring and passes a port index to
the get_tag_protocol() function since at least two different drivers need
that type of information (mt7530, b53) to support tagging or not.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-11-13 10:34:55 +09:00
commit aef1e0d5dd
18 changed files with 109 additions and 44 deletions

View file

@ -2,6 +2,7 @@ menuconfig B53
tristate "Broadcom BCM53xx managed switch support" tristate "Broadcom BCM53xx managed switch support"
depends on NET_DSA depends on NET_DSA
select NET_DSA_TAG_BRCM select NET_DSA_TAG_BRCM
select NET_DSA_TAG_BRCM_PREPEND
help help
This driver adds support for Broadcom managed switch chips. It supports This driver adds support for Broadcom managed switch chips. It supports
BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX

View file

@ -541,7 +541,8 @@ EXPORT_SYMBOL(b53_disable_port);
void b53_brcm_hdr_setup(struct dsa_switch *ds, int port) void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
{ {
bool tag_en = !!(ds->ops->get_tag_protocol(ds) == DSA_TAG_PROTO_BRCM); bool tag_en = !(ds->ops->get_tag_protocol(ds, port) ==
DSA_TAG_PROTO_NONE);
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
u8 hdr_ctl, val; u8 hdr_ctl, val;
u16 reg; u16 reg;
@ -1478,41 +1479,40 @@ void b53_br_fast_age(struct dsa_switch *ds, int port)
} }
EXPORT_SYMBOL(b53_br_fast_age); EXPORT_SYMBOL(b53_br_fast_age);
static bool b53_can_enable_brcm_tags(struct dsa_switch *ds) static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
{ {
unsigned int brcm_tag_mask;
unsigned int i;
/* Broadcom switches will accept enabling Broadcom tags on the /* Broadcom switches will accept enabling Broadcom tags on the
* following ports: 5, 7 and 8, any other port is not supported * following ports: 5, 7 and 8, any other port is not supported
*/ */
brcm_tag_mask = BIT(B53_CPU_PORT_25) | BIT(7) | BIT(B53_CPU_PORT); switch (port) {
case B53_CPU_PORT_25:
for (i = 0; i < ds->num_ports; i++) { case 7:
if (dsa_is_cpu_port(ds, i)) { case B53_CPU_PORT:
if (!(BIT(i) & brcm_tag_mask)) { return true;
dev_warn(ds->dev,
"Port %d is not Broadcom tag capable\n",
i);
return false;
}
}
} }
return true; dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n", port);
return false;
} }
static enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds,
int port)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
/* Older models support a different tag format that we do not /* Older models support a different tag format that we do not
* support in net/dsa/tag_brcm.c yet. * support in net/dsa/tag_brcm.c yet.
*/ */
if (is5325(dev) || is5365(dev) || !b53_can_enable_brcm_tags(ds)) if (is5325(dev) || is5365(dev) || !b53_can_enable_brcm_tags(ds, port))
return DSA_TAG_PROTO_NONE; return DSA_TAG_PROTO_NONE;
else
return DSA_TAG_PROTO_BRCM; /* Broadcom BCM58xx chips have a flow accelerator on Port 8
* which requires us to use the prepended Broadcom tag type
*/
if (dev->chip_id == BCM58XX_DEVICE_ID && port == B53_CPU_PORT)
return DSA_TAG_PROTO_BRCM_PREPEND;
return DSA_TAG_PROTO_BRCM;
} }
int b53_mirror_add(struct dsa_switch *ds, int port, int b53_mirror_add(struct dsa_switch *ds, int port,

View file

@ -35,7 +35,8 @@
#include "b53/b53_priv.h" #include "b53/b53_priv.h"
#include "b53/b53_regs.h" #include "b53/b53_regs.h"
static enum dsa_tag_protocol bcm_sf2_sw_get_tag_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol bcm_sf2_sw_get_tag_protocol(struct dsa_switch *ds,
int port)
{ {
return DSA_TAG_PROTO_BRCM; return DSA_TAG_PROTO_BRCM;
} }

View file

@ -64,7 +64,8 @@ struct dsa_loop_priv {
static struct phy_device *phydevs[PHY_MAX_ADDR]; static struct phy_device *phydevs[PHY_MAX_ADDR];
static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,
int port)
{ {
dev_dbg(ds->dev, "%s\n", __func__); dev_dbg(ds->dev, "%s\n", __func__);

View file

@ -894,7 +894,8 @@ static int lan9303_check_device(struct lan9303 *chip)
/* ---------------------------- DSA -----------------------------------*/ /* ---------------------------- DSA -----------------------------------*/
static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds,
int port)
{ {
return DSA_TAG_PROTO_LAN9303; return DSA_TAG_PROTO_LAN9303;
} }

View file

@ -394,7 +394,8 @@ static int ksz_setup(struct dsa_switch *ds)
return 0; return 0;
} }
static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
int port)
{ {
return DSA_TAG_PROTO_KSZ; return DSA_TAG_PROTO_KSZ;
} }

View file

@ -907,11 +907,11 @@ err:
} }
static enum dsa_tag_protocol static enum dsa_tag_protocol
mtk_get_tag_protocol(struct dsa_switch *ds) mtk_get_tag_protocol(struct dsa_switch *ds, int port)
{ {
struct mt7530_priv *priv = ds->priv; struct mt7530_priv *priv = ds->priv;
if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { if (port != MT7530_CPU_PORT) {
dev_warn(priv->dev, dev_warn(priv->dev,
"port not matched with tagging CPU port\n"); "port not matched with tagging CPU port\n");
return DSA_TAG_PROTO_NONE; return DSA_TAG_PROTO_NONE;

View file

@ -70,7 +70,8 @@ static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr)
return NULL; return NULL;
} }
static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds,
int port)
{ {
return DSA_TAG_PROTO_TRAILER; return DSA_TAG_PROTO_TRAILER;
} }

View file

@ -3731,7 +3731,8 @@ static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
return 0; return 0;
} }
static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds) static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
int port)
{ {
struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_chip *chip = ds->priv;

View file

@ -823,7 +823,7 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
} }
static enum dsa_tag_protocol static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds) qca8k_get_tag_protocol(struct dsa_switch *ds, int port)
{ {
return DSA_TAG_PROTO_QCA; return DSA_TAG_PROTO_QCA;
} }

View file

@ -29,6 +29,7 @@ struct fixed_phy_status;
enum dsa_tag_protocol { enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = 0, DSA_TAG_PROTO_NONE = 0,
DSA_TAG_PROTO_BRCM, DSA_TAG_PROTO_BRCM,
DSA_TAG_PROTO_BRCM_PREPEND,
DSA_TAG_PROTO_DSA, DSA_TAG_PROTO_DSA,
DSA_TAG_PROTO_EDSA, DSA_TAG_PROTO_EDSA,
DSA_TAG_PROTO_KSZ, DSA_TAG_PROTO_KSZ,
@ -321,7 +322,8 @@ struct dsa_switch_ops {
struct device *host_dev, int sw_addr, struct device *host_dev, int sw_addr,
void **priv); void **priv);
enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds); enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds,
int port);
int (*setup)(struct dsa_switch *ds); int (*setup)(struct dsa_switch *ds);
u32 (*get_phy_flags)(struct dsa_switch *ds, int port); u32 (*get_phy_flags)(struct dsa_switch *ds, int port);

View file

@ -19,6 +19,9 @@ if NET_DSA
config NET_DSA_TAG_BRCM config NET_DSA_TAG_BRCM
bool bool
config NET_DSA_TAG_BRCM_PREPEND
bool
config NET_DSA_TAG_DSA config NET_DSA_TAG_DSA
bool bool

View file

@ -5,6 +5,7 @@ dsa_core-y += dsa.o dsa2.o legacy.o master.o port.o slave.o switch.o
# tagging formats # tagging formats
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM_PREPEND) += tag_brcm.o
dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.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_EDSA) += tag_edsa.o
dsa_core-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o dsa_core-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o

View file

@ -44,6 +44,9 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
#ifdef CONFIG_NET_DSA_TAG_BRCM #ifdef CONFIG_NET_DSA_TAG_BRCM
[DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops, [DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops,
#endif #endif
#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND
[DSA_TAG_PROTO_BRCM_PREPEND] = &brcm_prepend_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_DSA #ifdef CONFIG_NET_DSA_TAG_DSA
[DSA_TAG_PROTO_DSA] = &dsa_netdev_ops, [DSA_TAG_PROTO_DSA] = &dsa_netdev_ops,
#endif #endif

View file

@ -539,7 +539,7 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
const struct dsa_device_ops *tag_ops; const struct dsa_device_ops *tag_ops;
enum dsa_tag_protocol tag_protocol; enum dsa_tag_protocol tag_protocol;
tag_protocol = ds->ops->get_tag_protocol(ds); tag_protocol = ds->ops->get_tag_protocol(ds, dp->index);
tag_ops = dsa_resolve_tag_protocol(tag_protocol); tag_ops = dsa_resolve_tag_protocol(tag_protocol);
if (IS_ERR(tag_ops)) { if (IS_ERR(tag_ops)) {
dev_warn(ds->dev, "No tagger for this switch\n"); dev_warn(ds->dev, "No tagger for this switch\n");

View file

@ -191,6 +191,7 @@ void dsa_switch_unregister_notifier(struct dsa_switch *ds);
/* tag_brcm.c */ /* tag_brcm.c */
extern const struct dsa_device_ops brcm_netdev_ops; extern const struct dsa_device_ops brcm_netdev_ops;
extern const struct dsa_device_ops brcm_prepend_netdev_ops;
/* tag_dsa.c */ /* tag_dsa.c */
extern const struct dsa_device_ops dsa_netdev_ops; extern const struct dsa_device_ops dsa_netdev_ops;

View file

@ -151,7 +151,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds,
const struct dsa_device_ops *tag_ops; const struct dsa_device_ops *tag_ops;
enum dsa_tag_protocol tag_protocol; enum dsa_tag_protocol tag_protocol;
tag_protocol = ops->get_tag_protocol(ds); tag_protocol = ops->get_tag_protocol(ds, dst->cpu_dp->index);
tag_ops = dsa_resolve_tag_protocol(tag_protocol); tag_ops = dsa_resolve_tag_protocol(tag_protocol);
if (IS_ERR(tag_ops)) if (IS_ERR(tag_ops))
return PTR_ERR(tag_ops); return PTR_ERR(tag_ops);

View file

@ -59,7 +59,9 @@
#define BRCM_EG_TC_MASK 0x7 #define BRCM_EG_TC_MASK 0x7
#define BRCM_EG_PID_MASK 0x1f #define BRCM_EG_PID_MASK 0x1f
static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
struct net_device *dev,
unsigned int offset)
{ {
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_port *dp = dsa_slave_to_port(dev);
u16 queue = skb_get_queue_mapping(skb); u16 queue = skb_get_queue_mapping(skb);
@ -70,10 +72,10 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev
skb_push(skb, BRCM_TAG_LEN); skb_push(skb, BRCM_TAG_LEN);
memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN); if (offset)
memmove(skb->data, skb->data + BRCM_TAG_LEN, offset);
/* Build the tag after the MAC Source Address */ brcm_tag = skb->data + offset;
brcm_tag = skb->data + 2 * ETH_ALEN;
/* Set the ingress opcode, traffic class, tag enforcment is /* Set the ingress opcode, traffic class, tag enforcment is
* deprecated * deprecated
@ -94,8 +96,10 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev
return skb; return skb;
} }
static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
struct packet_type *pt) struct net_device *dev,
struct packet_type *pt,
unsigned int offset)
{ {
int source_port; int source_port;
u8 *brcm_tag; u8 *brcm_tag;
@ -103,8 +107,7 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
return NULL; return NULL;
/* skb->data points to the EtherType, the tag is right before it */ brcm_tag = skb->data - offset;
brcm_tag = skb->data - 2;
/* The opcode should never be different than 0b000 */ /* The opcode should never be different than 0b000 */
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
@ -126,15 +129,60 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
/* Remove Broadcom tag and update checksum */ /* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN); skb_pull_rcsum(skb, BRCM_TAG_LEN);
return skb;
}
#ifdef CONFIG_NET_DSA_TAG_BRCM
static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb,
struct net_device *dev)
{
/* Build the tag after the MAC Source Address */
return brcm_tag_xmit_ll(skb, dev, 2 * ETH_ALEN);
}
static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt)
{
struct sk_buff *nskb;
/* skb->data points to the EtherType, the tag is right before it */
nskb = brcm_tag_rcv_ll(skb, dev, pt, 2);
if (!nskb)
return nskb;
/* Move the Ethernet DA and SA */ /* Move the Ethernet DA and SA */
memmove(skb->data - ETH_HLEN, memmove(nskb->data - ETH_HLEN,
skb->data - ETH_HLEN - BRCM_TAG_LEN, nskb->data - ETH_HLEN - BRCM_TAG_LEN,
2 * ETH_ALEN); 2 * ETH_ALEN);
return skb; return nskb;
} }
const struct dsa_device_ops brcm_netdev_ops = { const struct dsa_device_ops brcm_netdev_ops = {
.xmit = brcm_tag_xmit, .xmit = brcm_tag_xmit,
.rcv = brcm_tag_rcv, .rcv = brcm_tag_rcv,
}; };
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND
static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
struct net_device *dev)
{
/* tag is prepended to the packet */
return brcm_tag_xmit_ll(skb, dev, 0);
}
static struct sk_buff *brcm_tag_rcv_prepend(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt)
{
/* tag is prepended to the packet */
return brcm_tag_rcv_ll(skb, dev, pt, ETH_HLEN);
}
const struct dsa_device_ops brcm_prepend_netdev_ops = {
.xmit = brcm_tag_xmit_prepend,
.rcv = brcm_tag_rcv_prepend,
};
#endif