2019-11-14 15:03:29 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Copyright 2019 NXP Semiconductors
|
|
|
|
*/
|
|
|
|
#include <soc/mscc/ocelot.h>
|
|
|
|
#include <linux/packing.h>
|
|
|
|
#include "dsa_priv.h"
|
|
|
|
|
|
|
|
/* The CPU injection header and the CPU extraction header can have 3 types of
|
|
|
|
* prefixes: long, short and no prefix. The format of the header itself is the
|
|
|
|
* same in all 3 cases.
|
|
|
|
*
|
|
|
|
* Extraction with long prefix:
|
|
|
|
*
|
|
|
|
* +-------------------+-------------------+------+------+------------+-------+
|
|
|
|
* | ff:ff:ff:ff:ff:ff | ff:ff:ff:ff:ff:ff | 8880 | 000a | extraction | frame |
|
|
|
|
* | | | | | header | |
|
|
|
|
* +-------------------+-------------------+------+------+------------+-------+
|
|
|
|
* 48 bits 48 bits 16 bits 16 bits 128 bits
|
|
|
|
*
|
|
|
|
* Extraction with short prefix:
|
|
|
|
*
|
|
|
|
* +------+------+------------+-------+
|
|
|
|
* | 8880 | 000a | extraction | frame |
|
|
|
|
* | | | header | |
|
|
|
|
* +------+------+------------+-------+
|
|
|
|
* 16 bits 16 bits 128 bits
|
|
|
|
*
|
|
|
|
* Extraction with no prefix:
|
|
|
|
*
|
|
|
|
* +------------+-------+
|
|
|
|
* | extraction | frame |
|
|
|
|
* | header | |
|
|
|
|
* +------------+-------+
|
|
|
|
* 128 bits
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Injection with long prefix:
|
|
|
|
*
|
|
|
|
* +-------------------+-------------------+------+------+------------+-------+
|
|
|
|
* | any dmac | any smac | 8880 | 000a | injection | frame |
|
|
|
|
* | | | | | header | |
|
|
|
|
* +-------------------+-------------------+------+------+------------+-------+
|
|
|
|
* 48 bits 48 bits 16 bits 16 bits 128 bits
|
|
|
|
*
|
|
|
|
* Injection with short prefix:
|
|
|
|
*
|
|
|
|
* +------+------+------------+-------+
|
|
|
|
* | 8880 | 000a | injection | frame |
|
|
|
|
* | | | header | |
|
|
|
|
* +------+------+------------+-------+
|
|
|
|
* 16 bits 16 bits 128 bits
|
|
|
|
*
|
|
|
|
* Injection with no prefix:
|
|
|
|
*
|
|
|
|
* +------------+-------+
|
|
|
|
* | injection | frame |
|
|
|
|
* | header | |
|
|
|
|
* +------------+-------+
|
|
|
|
* 128 bits
|
|
|
|
*
|
|
|
|
* The injection header looks like this (network byte order, bit 127
|
|
|
|
* is part of lowest address byte in memory, bit 0 is part of highest
|
|
|
|
* address byte):
|
|
|
|
*
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 127:120 |BYPASS| MASQ | MASQ_PORT |REW_OP|REW_OP|
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 119:112 | REW_OP |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 111:104 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 103: 96 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 95: 88 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 87: 80 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 79: 72 | RSV |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 71: 64 | RSV | DEST |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 63: 56 | DEST |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 55: 48 | RSV |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 47: 40 | RSV | SRC_PORT | RSV |TFRM_TIMER|
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 39: 32 | TFRM_TIMER | RSV |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 31: 24 | RSV | DP | POP_CNT | CPUQ |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 23: 16 | CPUQ | QOS_CLASS |TAG_TYPE|
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 15: 8 | PCP | DEI | VID |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 7: 0 | VID |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
*
|
|
|
|
* And the extraction header looks like this:
|
|
|
|
*
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 127:120 | RSV | REW_OP |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 119:112 | REW_OP | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 111:104 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 103: 96 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 95: 88 | REW_VAL |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 87: 80 | REW_VAL | LLEN |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 79: 72 | LLEN | WLEN |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 71: 64 | WLEN | RSV |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 63: 56 | RSV |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 55: 48 | RSV |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 47: 40 | RSV | SRC_PORT | ACL_ID |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 39: 32 | ACL_ID | RSV | SFLOW_ID |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 31: 24 |ACL_HIT| DP | LRN_FLAGS | CPUQ |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 23: 16 | CPUQ | QOS_CLASS |TAG_TYPE|
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 15: 8 | PCP | DEI | VID |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
* 7: 0 | VID |
|
|
|
|
* +------+------+------+------+------+------+------+------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
|
|
|
|
struct net_device *netdev)
|
|
|
|
{
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(netdev);
|
2020-09-23 11:24:20 +00:00
|
|
|
struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
|
2019-11-14 15:03:29 +00:00
|
|
|
struct dsa_switch *ds = dp->ds;
|
2019-11-20 08:23:18 +00:00
|
|
|
struct ocelot *ocelot = ds->priv;
|
net: dsa: felix: create a template for the DSA tags on xmit
With this patch we try to kill 2 birds with 1 stone.
First of all, some switches that use tag_ocelot.c don't have the exact
same bitfield layout for the DSA tags. The destination ports field is
different for Seville VSC9953 for example. So the choices are to either
duplicate tag_ocelot.c into a new tag_seville.c (sub-optimal) or somehow
take into account a supposed ocelot->dest_ports_offset when packing this
field into the DSA injection header (again not ideal).
Secondly, tag_ocelot.c already needs to memset a 128-bit area to zero
and call some packing() functions of dubious performance in the
fastpath. And most of the values it needs to pack are pretty much
constant (BYPASS=1, SRC_PORT=CPU, DEST=port index). So it would be good
if we could improve that.
The proposed solution is to allocate a memory area per port at probe
time, initialize that with the statically defined bits as per chip
hardware revision, and just perform a simpler memcpy in the fastpath.
Other alternatives have been analyzed, such as:
- Create a separate tag_seville.c: too much code duplication for just 1
bit field difference.
- Create a separate DSA_TAG_PROTO_SEVILLE under tag_ocelot.c, just like
tag_brcm.c, which would have a separate .xmit function. Again, too
much code duplication for just 1 bit field difference.
- Allocate the template from the init function of the tag_ocelot.c
module, instead of from the driver: couldn't figure out a method of
accessing the correct port template corresponding to the correct
tagger in the .xmit function.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-07-13 16:57:04 +00:00
|
|
|
struct ocelot_port *ocelot_port;
|
|
|
|
u64 qos_class, rew_op;
|
2019-11-14 15:03:29 +00:00
|
|
|
u8 *injection;
|
|
|
|
|
|
|
|
if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
|
|
|
|
netdev_err(netdev, "Cannot make room for tag.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
net: dsa: felix: create a template for the DSA tags on xmit
With this patch we try to kill 2 birds with 1 stone.
First of all, some switches that use tag_ocelot.c don't have the exact
same bitfield layout for the DSA tags. The destination ports field is
different for Seville VSC9953 for example. So the choices are to either
duplicate tag_ocelot.c into a new tag_seville.c (sub-optimal) or somehow
take into account a supposed ocelot->dest_ports_offset when packing this
field into the DSA injection header (again not ideal).
Secondly, tag_ocelot.c already needs to memset a 128-bit area to zero
and call some packing() functions of dubious performance in the
fastpath. And most of the values it needs to pack are pretty much
constant (BYPASS=1, SRC_PORT=CPU, DEST=port index). So it would be good
if we could improve that.
The proposed solution is to allocate a memory area per port at probe
time, initialize that with the statically defined bits as per chip
hardware revision, and just perform a simpler memcpy in the fastpath.
Other alternatives have been analyzed, such as:
- Create a separate tag_seville.c: too much code duplication for just 1
bit field difference.
- Create a separate DSA_TAG_PROTO_SEVILLE under tag_ocelot.c, just like
tag_brcm.c, which would have a separate .xmit function. Again, too
much code duplication for just 1 bit field difference.
- Allocate the template from the init function of the tag_ocelot.c
module, instead of from the driver: couldn't figure out a method of
accessing the correct port template corresponding to the correct
tagger in the .xmit function.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-07-13 16:57:04 +00:00
|
|
|
ocelot_port = ocelot->ports[dp->index];
|
2019-11-14 15:03:29 +00:00
|
|
|
|
net: dsa: felix: create a template for the DSA tags on xmit
With this patch we try to kill 2 birds with 1 stone.
First of all, some switches that use tag_ocelot.c don't have the exact
same bitfield layout for the DSA tags. The destination ports field is
different for Seville VSC9953 for example. So the choices are to either
duplicate tag_ocelot.c into a new tag_seville.c (sub-optimal) or somehow
take into account a supposed ocelot->dest_ports_offset when packing this
field into the DSA injection header (again not ideal).
Secondly, tag_ocelot.c already needs to memset a 128-bit area to zero
and call some packing() functions of dubious performance in the
fastpath. And most of the values it needs to pack are pretty much
constant (BYPASS=1, SRC_PORT=CPU, DEST=port index). So it would be good
if we could improve that.
The proposed solution is to allocate a memory area per port at probe
time, initialize that with the statically defined bits as per chip
hardware revision, and just perform a simpler memcpy in the fastpath.
Other alternatives have been analyzed, such as:
- Create a separate tag_seville.c: too much code duplication for just 1
bit field difference.
- Create a separate DSA_TAG_PROTO_SEVILLE under tag_ocelot.c, just like
tag_brcm.c, which would have a separate .xmit function. Again, too
much code duplication for just 1 bit field difference.
- Allocate the template from the init function of the tag_ocelot.c
module, instead of from the driver: couldn't figure out a method of
accessing the correct port template corresponding to the correct
tagger in the .xmit function.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-07-13 16:57:04 +00:00
|
|
|
injection = skb_push(skb, OCELOT_TAG_LEN);
|
2019-11-14 15:03:29 +00:00
|
|
|
|
net: dsa: felix: create a template for the DSA tags on xmit
With this patch we try to kill 2 birds with 1 stone.
First of all, some switches that use tag_ocelot.c don't have the exact
same bitfield layout for the DSA tags. The destination ports field is
different for Seville VSC9953 for example. So the choices are to either
duplicate tag_ocelot.c into a new tag_seville.c (sub-optimal) or somehow
take into account a supposed ocelot->dest_ports_offset when packing this
field into the DSA injection header (again not ideal).
Secondly, tag_ocelot.c already needs to memset a 128-bit area to zero
and call some packing() functions of dubious performance in the
fastpath. And most of the values it needs to pack are pretty much
constant (BYPASS=1, SRC_PORT=CPU, DEST=port index). So it would be good
if we could improve that.
The proposed solution is to allocate a memory area per port at probe
time, initialize that with the statically defined bits as per chip
hardware revision, and just perform a simpler memcpy in the fastpath.
Other alternatives have been analyzed, such as:
- Create a separate tag_seville.c: too much code duplication for just 1
bit field difference.
- Create a separate DSA_TAG_PROTO_SEVILLE under tag_ocelot.c, just like
tag_brcm.c, which would have a separate .xmit function. Again, too
much code duplication for just 1 bit field difference.
- Allocate the template from the init function of the tag_ocelot.c
module, instead of from the driver: couldn't figure out a method of
accessing the correct port template corresponding to the correct
tagger in the .xmit function.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-07-13 16:57:04 +00:00
|
|
|
memcpy(injection, ocelot_port->xmit_template, OCELOT_TAG_LEN);
|
|
|
|
/* Fix up the fields which are not statically determined
|
|
|
|
* in the template
|
|
|
|
*/
|
2019-11-14 15:03:29 +00:00
|
|
|
qos_class = skb->priority;
|
|
|
|
packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
|
|
|
|
|
2020-09-23 11:24:20 +00:00
|
|
|
/* TX timestamping was requested */
|
|
|
|
if (clone) {
|
2019-11-20 08:23:18 +00:00
|
|
|
rew_op = ocelot_port->ptp_cmd;
|
2020-09-18 01:07:24 +00:00
|
|
|
/* Retrieve timestamp ID populated inside skb->cb[0] of the
|
|
|
|
* clone by ocelot_port_add_txtstamp_skb
|
|
|
|
*/
|
|
|
|
if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
|
|
|
|
rew_op |= clone->cb[0] << 3;
|
2019-11-20 08:23:18 +00:00
|
|
|
|
|
|
|
packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
|
|
|
|
}
|
|
|
|
|
2019-11-14 15:03:29 +00:00
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
|
|
|
|
struct net_device *netdev,
|
|
|
|
struct packet_type *pt)
|
|
|
|
{
|
|
|
|
u64 src_port, qos_class;
|
|
|
|
u8 *start = skb->data;
|
|
|
|
u8 *extraction;
|
|
|
|
|
|
|
|
/* Revert skb->data by the amount consumed by the DSA master,
|
|
|
|
* so it points to the beginning of the frame.
|
|
|
|
*/
|
|
|
|
skb_push(skb, ETH_HLEN);
|
|
|
|
/* We don't care about the long prefix, it is just for easy entrance
|
|
|
|
* into the DSA master's RX filter. Discard it now by moving it into
|
|
|
|
* the headroom.
|
|
|
|
*/
|
|
|
|
skb_pull(skb, OCELOT_LONG_PREFIX_LEN);
|
|
|
|
/* And skb->data now points to the extraction frame header.
|
|
|
|
* Keep a pointer to it.
|
|
|
|
*/
|
|
|
|
extraction = skb->data;
|
|
|
|
/* Now the EFH is part of the headroom as well */
|
|
|
|
skb_pull(skb, OCELOT_TAG_LEN);
|
|
|
|
/* Reset the pointer to the real MAC header */
|
|
|
|
skb_reset_mac_header(skb);
|
|
|
|
skb_reset_mac_len(skb);
|
|
|
|
/* And move skb->data to the correct location again */
|
|
|
|
skb_pull(skb, ETH_HLEN);
|
|
|
|
|
|
|
|
/* Remove from inet csum the extraction header */
|
|
|
|
skb_postpull_rcsum(skb, start, OCELOT_LONG_PREFIX_LEN + OCELOT_TAG_LEN);
|
|
|
|
|
|
|
|
packing(extraction, &src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
|
|
|
|
packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
|
|
|
|
|
|
|
|
skb->dev = dsa_master_find_slave(netdev, 0, src_port);
|
|
|
|
if (!skb->dev)
|
|
|
|
/* The switch will reflect back some frames sent through
|
|
|
|
* sockets opened on the bare DSA master. These will come back
|
|
|
|
* with src_port equal to the index of the CPU port, for which
|
|
|
|
* there is no slave registered. So don't print any error
|
|
|
|
* message here (ignore and drop those frames).
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
skb->offload_fwd_mark = 1;
|
|
|
|
skb->priority = qos_class;
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2020-05-11 23:47:14 +00:00
|
|
|
static const struct dsa_device_ops ocelot_netdev_ops = {
|
2019-11-14 15:03:29 +00:00
|
|
|
.name = "ocelot",
|
|
|
|
.proto = DSA_TAG_PROTO_OCELOT,
|
|
|
|
.xmit = ocelot_xmit,
|
|
|
|
.rcv = ocelot_rcv,
|
|
|
|
.overhead = OCELOT_TAG_LEN + OCELOT_LONG_PREFIX_LEN,
|
|
|
|
};
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT);
|
|
|
|
|
|
|
|
module_dsa_tag_driver(ocelot_netdev_ops);
|