Skip to content

Commit

Permalink
net: dsa: add support for Atheros AR9331 TAG format
Browse files Browse the repository at this point in the history
Add support for tag format used in Atheros AR9331 built-in switch.

Reviewed-by: Vivien Didelot <vivien.didelot@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
olerem authored and davem330 committed Dec 21, 2019
1 parent 4eb7ae7 commit 48fda74
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/net/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct phylink_link_state;
#define DSA_TAG_PROTO_SJA1105_VALUE 13
#define DSA_TAG_PROTO_KSZ8795_VALUE 14
#define DSA_TAG_PROTO_OCELOT_VALUE 15
#define DSA_TAG_PROTO_AR9331_VALUE 16

enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
Expand All @@ -61,6 +62,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE,
DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE,
DSA_TAG_PROTO_OCELOT = DSA_TAG_PROTO_OCELOT_VALUE,
DSA_TAG_PROTO_AR9331 = DSA_TAG_PROTO_AR9331_VALUE,
};

struct packet_type;
Expand Down
6 changes: 6 additions & 0 deletions net/dsa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ config NET_DSA_TAG_8021Q

Drivers which use these helpers should select this as dependency.

config NET_DSA_TAG_AR9331
tristate "Tag driver for Atheros AR9331 SoC with built-in switch"
help
Say Y or M if you want to enable support for tagging frames for
the Atheros AR9331 SoC with built-in switch.

config NET_DSA_TAG_BRCM_COMMON
tristate
default n
Expand Down
1 change: 1 addition & 0 deletions net/dsa/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o

# tagging formats
obj-$(CONFIG_NET_DSA_TAG_8021Q) += tag_8021q.o
obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o
obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
Expand Down
96 changes: 96 additions & 0 deletions net/dsa/tag_ar9331.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
*/


#include <linux/bitfield.h>
#include <linux/etherdevice.h>

#include "dsa_priv.h"

#define AR9331_HDR_LEN 2
#define AR9331_HDR_VERSION 1

#define AR9331_HDR_VERSION_MASK GENMASK(15, 14)
#define AR9331_HDR_PRIORITY_MASK GENMASK(13, 12)
#define AR9331_HDR_TYPE_MASK GENMASK(10, 8)
#define AR9331_HDR_BROADCAST BIT(7)
#define AR9331_HDR_FROM_CPU BIT(6)
/* AR9331_HDR_RESERVED - not used or may be version field.
* According to the AR8216 doc it should 0b10. On AR9331 it is 0b11 on RX path
* and should be set to 0b11 to make it work.
*/
#define AR9331_HDR_RESERVED_MASK GENMASK(5, 4)
#define AR9331_HDR_PORT_NUM_MASK GENMASK(3, 0)

static struct sk_buff *ar9331_tag_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
__le16 *phdr;
u16 hdr;

if (skb_cow_head(skb, 0) < 0)
return NULL;

phdr = skb_push(skb, AR9331_HDR_LEN);

hdr = FIELD_PREP(AR9331_HDR_VERSION_MASK, AR9331_HDR_VERSION);
hdr |= AR9331_HDR_FROM_CPU | dp->index;
/* 0b10 for AR8216 and 0b11 for AR9331 */
hdr |= AR9331_HDR_RESERVED_MASK;

phdr[0] = cpu_to_le16(hdr);

return skb;
}

static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
struct net_device *ndev,
struct packet_type *pt)
{
u8 ver, port;
u16 hdr;

if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
return NULL;

hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb));

ver = FIELD_GET(AR9331_HDR_VERSION_MASK, hdr);
if (unlikely(ver != AR9331_HDR_VERSION)) {
netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n",
__func__, __LINE__, hdr);
return NULL;
}

if (unlikely(hdr & AR9331_HDR_FROM_CPU)) {
netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n",
__func__, __LINE__, hdr);
return NULL;
}

skb_pull_rcsum(skb, AR9331_HDR_LEN);

/* Get source port information */
port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);

skb->dev = dsa_master_find_slave(ndev, 0, port);
if (!skb->dev)
return NULL;

return skb;
}

static const struct dsa_device_ops ar9331_netdev_ops = {
.name = "ar9331",
.proto = DSA_TAG_PROTO_AR9331,
.xmit = ar9331_tag_xmit,
.rcv = ar9331_tag_rcv,
.overhead = AR9331_HDR_LEN,
};

MODULE_LICENSE("GPL v2");
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_AR9331);
module_dsa_tag_driver(ar9331_netdev_ops);

0 comments on commit 48fda74

Please sign in to comment.