Commit 40d3f295 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: mscc: ocelot: use common tag parsing code with DSA

The Injection Frame Header and Extraction Frame Header that the switch
prepends to frames over the NPI port is also prepended to frames
delivered over the CPU port module's queues.

Let's unify the handling of the frame headers by making the ocelot
driver call some helpers exported by the DSA tagger. Among other things,
this allows us to get rid of the strange cpu_to_be32 when transmitting
the Injection Frame Header on ocelot, since the packing API uses
network byte order natively (when "quirks" is 0).

The comments above ocelot_gen_ifh talk about setting pop_cnt to 3, and
the cpu extraction queue mask to something, but the code doesn't do it,
so we don't do it either.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8a678bb2
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include <soc/mscc/ocelot_ptp.h> #include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include <linux/dsa/8021q.h> #include <linux/dsa/8021q.h>
#include <linux/dsa/ocelot.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/packing.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -1161,9 +1161,9 @@ static int felix_hwtstamp_set(struct dsa_switch *ds, int port, ...@@ -1161,9 +1161,9 @@ static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
static bool felix_rxtstamp(struct dsa_switch *ds, int port, static bool felix_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type) struct sk_buff *skb, unsigned int type)
{ {
u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
struct skb_shared_hwtstamps *shhwtstamps; struct skb_shared_hwtstamps *shhwtstamps;
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
u32 tstamp_lo, tstamp_hi; u32 tstamp_lo, tstamp_hi;
struct timespec64 ts; struct timespec64 ts;
u64 tstamp, val; u64 tstamp, val;
...@@ -1171,7 +1171,7 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port, ...@@ -1171,7 +1171,7 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); ocelot_xfh_get_rew_val(extraction, &val);
tstamp_lo = (u32)val; tstamp_lo = (u32)val;
tstamp_hi = tstamp >> 32; tstamp_hi = tstamp >> 32;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <soc/mscc/ocelot_ptp.h> #include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot_sys.h> #include <soc/mscc/ocelot_sys.h>
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include <linux/packing.h> #include <linux/dsa/ocelot.h>
#include <linux/pcs-lynx.h> #include <linux/pcs-lynx.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pcs-lynx.h> #include <linux/pcs-lynx.h>
#include <linux/packing.h> #include <linux/dsa/ocelot.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include "felix.h" #include "felix.h"
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* *
* Copyright (c) 2017 Microsemi Corporation * Copyright (c) 2017 Microsemi Corporation
*/ */
#include <linux/dsa/ocelot.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <soc/mscc/ocelot_vcap.h> #include <soc/mscc/ocelot_vcap.h>
#include "ocelot.h" #include "ocelot.h"
...@@ -628,26 +629,6 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) ...@@ -628,26 +629,6 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
} }
EXPORT_SYMBOL(ocelot_get_txtstamp); EXPORT_SYMBOL(ocelot_get_txtstamp);
/* Generate the IFH for frame injection
*
* The IFH is a 128bit-value
* bit 127: bypass the analyzer processing
* bit 56-67: destination mask
* bit 28-29: pop_cnt: 3 disables all rewriting of the frame
* bit 20-27: cpu extraction queue mask
* bit 16: tag type 0: C-tag, 1: S-tag
* bit 0-11: VID
*/
static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info)
{
ifh[0] = IFH_INJ_BYPASS | ((0x1ff & info->rew_op) << 21);
ifh[1] = (0xf00 & info->port) >> 8;
ifh[2] = (0xff & info->port) << 24;
ifh[3] = (info->tag_type << 16) | info->vid;
return 0;
}
bool ocelot_can_inject(struct ocelot *ocelot, int grp) bool ocelot_can_inject(struct ocelot *ocelot, int grp)
{ {
u32 val = ocelot_read(ocelot, QS_INJ_STATUS); u32 val = ocelot_read(ocelot, QS_INJ_STATUS);
...@@ -664,23 +645,20 @@ EXPORT_SYMBOL(ocelot_can_inject); ...@@ -664,23 +645,20 @@ EXPORT_SYMBOL(ocelot_can_inject);
void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp, void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
u32 rew_op, struct sk_buff *skb) u32 rew_op, struct sk_buff *skb)
{ {
struct frame_info info = {}; u32 ifh[OCELOT_TAG_LEN / 4] = {0};
u32 ifh[OCELOT_TAG_LEN / 4];
unsigned int i, count, last; unsigned int i, count, last;
ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) | ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp); QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp);
info.port = BIT(port); ocelot_ifh_set_bypass(ifh, 1);
info.tag_type = IFH_TAG_TYPE_C; ocelot_ifh_set_dest(ifh, BIT(port));
info.vid = skb_vlan_tag_get(skb); ocelot_ifh_set_tag_type(ifh, IFH_TAG_TYPE_C);
info.rew_op = rew_op; ocelot_ifh_set_vid(ifh, skb_vlan_tag_get(skb));
ocelot_ifh_set_rew_op(ifh, rew_op);
ocelot_gen_ifh(ifh, &info);
for (i = 0; i < OCELOT_TAG_LEN / 4; i++) for (i = 0; i < OCELOT_TAG_LEN / 4; i++)
ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]), ocelot_write_rix(ocelot, ifh[i], QS_INJ_WR, grp);
QS_INJ_WR, grp);
count = DIV_ROUND_UP(skb->len, 4); count = DIV_ROUND_UP(skb->len, 4);
last = skb->len % 4; last = skb->len % 4;
......
...@@ -32,15 +32,6 @@ ...@@ -32,15 +32,6 @@
#define OCELOT_PTP_QUEUE_SZ 128 #define OCELOT_PTP_QUEUE_SZ 128
struct frame_info {
u32 len;
u16 port;
u16 vid;
u8 tag_type;
u16 rew_op;
u32 timestamp; /* rew_val */
};
struct ocelot_port_tc { struct ocelot_port_tc {
bool block_shared; bool block_shared;
unsigned long offload_cnt; unsigned long offload_cnt;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* *
* Copyright (c) 2017 Microsemi Corporation * Copyright (c) 2017 Microsemi Corporation
*/ */
#include <linux/dsa/ocelot.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_net.h> #include <linux/of_net.h>
...@@ -18,8 +19,6 @@ ...@@ -18,8 +19,6 @@
#include <soc/mscc/ocelot_hsio.h> #include <soc/mscc/ocelot_hsio.h>
#include "ocelot.h" #include "ocelot.h"
#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))
static const u32 ocelot_ana_regmap[] = { static const u32 ocelot_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x009000), REG(ANA_ADVLEARN, 0x009000),
REG(ANA_VLANMASK, 0x009004), REG(ANA_VLANMASK, 0x009004),
...@@ -532,29 +531,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops) ...@@ -532,29 +531,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
return 0; return 0;
} }
static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
{
u8 llen, wlen;
u64 ifh[2];
ifh[0] = be64_to_cpu(((__force __be64 *)_ifh)[0]);
ifh[1] = be64_to_cpu(((__force __be64 *)_ifh)[1]);
wlen = IFH_EXTRACT_BITFIELD64(ifh[0], 7, 8);
llen = IFH_EXTRACT_BITFIELD64(ifh[0], 15, 6);
info->len = OCELOT_BUFFER_CELL_SZ * wlen + llen - 80;
info->timestamp = IFH_EXTRACT_BITFIELD64(ifh[0], 21, 32);
info->port = IFH_EXTRACT_BITFIELD64(ifh[1], 43, 4);
info->tag_type = IFH_EXTRACT_BITFIELD64(ifh[1], 16, 1);
info->vid = IFH_EXTRACT_BITFIELD64(ifh[1], 0, 12);
return 0;
}
static int ocelot_rx_frame_word(struct ocelot *ocelot, u8 grp, bool ifh, static int ocelot_rx_frame_word(struct ocelot *ocelot, u8 grp, bool ifh,
u32 *rval) u32 *rval)
{ {
...@@ -609,20 +585,20 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) ...@@ -609,20 +585,20 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
struct ocelot_port_private *priv; struct ocelot_port_private *priv;
struct ocelot_port *ocelot_port; struct ocelot_port *ocelot_port;
u64 tod_in_ns, full_ts_in_ns; u64 tod_in_ns, full_ts_in_ns;
struct frame_info info = {}; u64 src_port, len, timestamp;
struct net_device *dev; struct net_device *dev;
u32 ifh[4], val, *buf; u32 xfh[4], val, *buf;
struct timespec64 ts; struct timespec64 ts;
int sz, len, buf_len;
struct sk_buff *skb; struct sk_buff *skb;
int sz, buf_len;
for (i = 0; i < OCELOT_TAG_LEN / 4; i++) { for (i = 0; i < OCELOT_TAG_LEN / 4; i++) {
err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]); err = ocelot_rx_frame_word(ocelot, grp, true, &xfh[i]);
if (err != 4) if (err != 4)
goto out; goto out;
} }
/* At this point the IFH was read correctly, so it is safe to /* At this point the XFH was read correctly, so it is safe to
* presume that there is no error. The err needs to be reset * presume that there is no error. The err needs to be reset
* otherwise a frame could come in CPU queue between the while * otherwise a frame could come in CPU queue between the while
* condition and the check for error later on. And in that case * condition and the check for error later on. And in that case
...@@ -630,21 +606,23 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) ...@@ -630,21 +606,23 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
*/ */
err = 0; err = 0;
ocelot_parse_ifh(ifh, &info); ocelot_xfh_get_src_port(xfh, &src_port);
ocelot_xfh_get_len(xfh, &len);
ocelot_xfh_get_rew_val(xfh, &timestamp);
ocelot_port = ocelot->ports[info.port]; ocelot_port = ocelot->ports[src_port];
priv = container_of(ocelot_port, struct ocelot_port_private, priv = container_of(ocelot_port, struct ocelot_port_private,
port); port);
dev = priv->dev; dev = priv->dev;
skb = netdev_alloc_skb(dev, info.len); skb = netdev_alloc_skb(dev, len);
if (unlikely(!skb)) { if (unlikely(!skb)) {
netdev_err(dev, "Unable to allocate sk_buff\n"); netdev_err(dev, "Unable to allocate sk_buff\n");
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
buf_len = info.len - ETH_FCS_LEN; buf_len = len - ETH_FCS_LEN;
buf = (u32 *)skb_put(skb, buf_len); buf = (u32 *)skb_put(skb, buf_len);
len = 0; len = 0;
...@@ -677,12 +655,12 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) ...@@ -677,12 +655,12 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
tod_in_ns = ktime_set(ts.tv_sec, ts.tv_nsec); tod_in_ns = ktime_set(ts.tv_sec, ts.tv_nsec);
if ((tod_in_ns & 0xffffffff) < info.timestamp) if ((tod_in_ns & 0xffffffff) < timestamp)
full_ts_in_ns = (((tod_in_ns >> 32) - 1) << 32) | full_ts_in_ns = (((tod_in_ns >> 32) - 1) << 32) |
info.timestamp; timestamp;
else else
full_ts_in_ns = (tod_in_ns & GENMASK_ULL(63, 32)) | full_ts_in_ns = (tod_in_ns & GENMASK_ULL(63, 32)) |
info.timestamp; timestamp;
shhwtstamps = skb_hwtstamps(skb); shhwtstamps = skb_hwtstamps(skb);
memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
...@@ -692,7 +670,7 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) ...@@ -692,7 +670,7 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
/* Everything we see on an interface that is in the HW bridge /* Everything we see on an interface that is in the HW bridge
* has already been forwarded. * has already been forwarded.
*/ */
if (ocelot->bridge_mask & BIT(info.port)) if (ocelot->bridge_mask & BIT(src_port))
skb->offload_fwd_mark = 1; skb->offload_fwd_mark = 1;
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
......
/* SPDX-License-Identifier: GPL-2.0
* Copyright 2019-2021 NXP Semiconductors
*/
#ifndef _NET_DSA_TAG_OCELOT_H
#define _NET_DSA_TAG_OCELOT_H
#include <linux/packing.h>
#define OCELOT_TAG_LEN 16
#define OCELOT_SHORT_PREFIX_LEN 4
#define OCELOT_LONG_PREFIX_LEN 16
#define OCELOT_TOTAL_TAG_LEN (OCELOT_SHORT_PREFIX_LEN + OCELOT_TAG_LEN)
/* 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 | fe: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 inline void ocelot_xfh_get_rew_val(void *extraction, u64 *rew_val)
{
packing(extraction, rew_val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0);
}
static inline void ocelot_xfh_get_len(void *extraction, u64 *len)
{
u64 llen, wlen;
packing(extraction, &llen, 84, 79, OCELOT_TAG_LEN, UNPACK, 0);
packing(extraction, &wlen, 78, 71, OCELOT_TAG_LEN, UNPACK, 0);
*len = 60 * wlen + llen - 80;
}
static inline void ocelot_xfh_get_src_port(void *extraction, u64 *src_port)
{
packing(extraction, src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
}
static inline void ocelot_xfh_get_qos_class(void *extraction, u64 *qos_class)
{
packing(extraction, qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
}
static inline void ocelot_xfh_get_tag_type(void *extraction, u64 *tag_type)
{
packing(extraction, tag_type, 16, 16, OCELOT_TAG_LEN, UNPACK, 0);
}
static inline void ocelot_xfh_get_vlan_tci(void *extraction, u64 *vlan_tci)
{
packing(extraction, vlan_tci, 15, 0, OCELOT_TAG_LEN, UNPACK, 0);
}
static inline void ocelot_ifh_set_bypass(void *injection, u64 bypass)
{
packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
}
static inline void ocelot_ifh_set_rew_op(void *injection, u64 rew_op)
{
packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
}
static inline void ocelot_ifh_set_dest(void *injection, u64 dest)
{
packing(injection, &dest, 67, 56, OCELOT_TAG_LEN, PACK, 0);
}
static inline void ocelot_ifh_set_qos_class(void *injection, u64 qos_class)
{
packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
}
static inline void ocelot_ifh_set_tag_type(void *injection, u64 tag_type)
{
packing(injection, &tag_type, 16, 16, OCELOT_TAG_LEN, PACK, 0);
}
static inline void ocelot_ifh_set_vid(void *injection, u64 vid)
{
packing(injection, &vid, 11, 0, OCELOT_TAG_LEN, PACK, 0);
}
#endif
...@@ -87,9 +87,6 @@ ...@@ -87,9 +87,6 @@
/* Source PGIDs, one per physical port */ /* Source PGIDs, one per physical port */
#define PGID_SRC 80 #define PGID_SRC 80
#define IFH_INJ_BYPASS BIT(31)
#define IFH_INJ_POP_CNT_DISABLE (3 << 28)
#define IFH_TAG_TYPE_C 0 #define IFH_TAG_TYPE_C 0
#define IFH_TAG_TYPE_S 1 #define IFH_TAG_TYPE_S 1
...@@ -100,10 +97,6 @@ ...@@ -100,10 +97,6 @@
#define IFH_REW_OP_ORIGIN_PTP 0x5 #define IFH_REW_OP_ORIGIN_PTP 0x5
#define OCELOT_NUM_TC 8 #define OCELOT_NUM_TC 8
#define OCELOT_TAG_LEN 16
#define OCELOT_SHORT_PREFIX_LEN 4
#define OCELOT_LONG_PREFIX_LEN 16
#define OCELOT_TOTAL_TAG_LEN (OCELOT_SHORT_PREFIX_LEN + OCELOT_TAG_LEN)
#define OCELOT_SPEED_2500 0 #define OCELOT_SPEED_2500 0
#define OCELOT_SPEED_1000 1 #define OCELOT_SPEED_1000 1
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright 2019 NXP Semiconductors /* Copyright 2019 NXP Semiconductors
*/ */
#include <linux/dsa/ocelot.h>
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include <linux/packing.h>
#include "dsa_priv.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, static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev) struct net_device *netdev)
{ {
...@@ -142,7 +14,6 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, ...@@ -142,7 +14,6 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
struct ocelot_port *ocelot_port; struct ocelot_port *ocelot_port;
u8 *prefix, *injection; u8 *prefix, *injection;
u64 qos_class, rew_op;
ocelot_port = ocelot->ports[dp->index]; ocelot_port = ocelot->ports[dp->index];
...@@ -155,19 +26,19 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, ...@@ -155,19 +26,19 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
/* Fix up the fields which are not statically determined /* Fix up the fields which are not statically determined
* in the template * in the template
*/ */
qos_class = skb->priority; ocelot_ifh_set_qos_class(injection, skb->priority);
packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
/* TX timestamping was requested */ /* TX timestamping was requested */
if (clone) { if (clone) {
rew_op = ocelot_port->ptp_cmd; u64 rew_op = ocelot_port->ptp_cmd;
/* Retrieve timestamp ID populated inside skb->cb[0] of the /* Retrieve timestamp ID populated inside skb->cb[0] of the
* clone by ocelot_port_add_txtstamp_skb * clone by ocelot_port_add_txtstamp_skb
*/ */
if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
rew_op |= clone->cb[0] << 3; rew_op |= clone->cb[0] << 3;
packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0); ocelot_ifh_set_rew_op(injection, rew_op);
} }
return skb; return skb;
...@@ -208,10 +79,10 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, ...@@ -208,10 +79,10 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
/* Remove from inet csum the extraction header */ /* Remove from inet csum the extraction header */
skb_postpull_rcsum(skb, start, OCELOT_TOTAL_TAG_LEN); skb_postpull_rcsum(skb, start, OCELOT_TOTAL_TAG_LEN);
packing(extraction, &src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0); ocelot_xfh_get_src_port(extraction, &src_port);
packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0); ocelot_xfh_get_qos_class(extraction, &qos_class);
packing(extraction, &tag_type, 16, 16, OCELOT_TAG_LEN, UNPACK, 0); ocelot_xfh_get_tag_type(extraction, &tag_type);
packing(extraction, &vlan_tci, 15, 0, OCELOT_TAG_LEN, UNPACK, 0); ocelot_xfh_get_vlan_tci(extraction, &vlan_tci);
skb->dev = dsa_master_find_slave(netdev, 0, src_port); skb->dev = dsa_master_find_slave(netdev, 0, src_port);
if (!skb->dev) if (!skb->dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment