mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
net: dsa: add support for Atheros AR9331 TAG format
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>
This commit is contained in:
parent
4eb7ae7a30
commit
48fda74f0a
@ -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,
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
96
net/dsa/tag_ar9331.c
Normal file
96
net/dsa/tag_ar9331.c
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user