Skip to content

Commit

Permalink
net: mscc: ocelot: use common tag parsing code with DSA
Browse files Browse the repository at this point in the history
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: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vladimir Oltean authored and David S. Miller committed Feb 15, 2021
1 parent 8a678bb commit 40d3f29
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 227 deletions.
6 changes: 3 additions & 3 deletions drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
#include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot.h>
#include <linux/dsa/8021q.h>
#include <linux/dsa/ocelot.h>
#include <linux/platform_device.h>
#include <linux/packing.h>
#include <linux/module.h>
#include <linux/of_net.h>
#include <linux/pci.h>
Expand Down Expand Up @@ -1161,17 +1161,17 @@ static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
static bool felix_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type)
{
u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
struct skb_shared_hwtstamps *shhwtstamps;
struct ocelot *ocelot = ds->priv;
u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
u32 tstamp_lo, tstamp_hi;
struct timespec64 ts;
u64 tstamp, val;

ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
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_hi = tstamp >> 32;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/dsa/ocelot/felix_vsc9959.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot_sys.h>
#include <soc/mscc/ocelot.h>
#include <linux/packing.h>
#include <linux/dsa/ocelot.h>
#include <linux/pcs-lynx.h>
#include <net/pkt_sched.h>
#include <linux/iopoll.h>
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/dsa/ocelot/seville_vsc9953.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <soc/mscc/ocelot.h>
#include <linux/of_platform.h>
#include <linux/pcs-lynx.h>
#include <linux/packing.h>
#include <linux/dsa/ocelot.h>
#include <linux/iopoll.h>
#include "felix.h"

Expand Down
38 changes: 8 additions & 30 deletions drivers/net/ethernet/mscc/ocelot.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*
* Copyright (c) 2017 Microsemi Corporation
*/
#include <linux/dsa/ocelot.h>
#include <linux/if_bridge.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot.h"
Expand Down Expand Up @@ -628,26 +629,6 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
}
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)
{
u32 val = ocelot_read(ocelot, QS_INJ_STATUS);
Expand All @@ -664,23 +645,20 @@ EXPORT_SYMBOL(ocelot_can_inject);
void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
u32 rew_op, struct sk_buff *skb)
{
struct frame_info info = {};
u32 ifh[OCELOT_TAG_LEN / 4];
u32 ifh[OCELOT_TAG_LEN / 4] = {0};
unsigned int i, count, last;

ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp);

info.port = BIT(port);
info.tag_type = IFH_TAG_TYPE_C;
info.vid = skb_vlan_tag_get(skb);
info.rew_op = rew_op;

ocelot_gen_ifh(ifh, &info);
ocelot_ifh_set_bypass(ifh, 1);
ocelot_ifh_set_dest(ifh, BIT(port));
ocelot_ifh_set_tag_type(ifh, IFH_TAG_TYPE_C);
ocelot_ifh_set_vid(ifh, skb_vlan_tag_get(skb));
ocelot_ifh_set_rew_op(ifh, rew_op);

for (i = 0; i < OCELOT_TAG_LEN / 4; i++)
ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]),
QS_INJ_WR, grp);
ocelot_write_rix(ocelot, ifh[i], QS_INJ_WR, grp);

count = DIV_ROUND_UP(skb->len, 4);
last = skb->len % 4;
Expand Down
9 changes: 0 additions & 9 deletions drivers/net/ethernet/mscc/ocelot.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@

#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 {
bool block_shared;
unsigned long offload_cnt;
Expand Down
54 changes: 16 additions & 38 deletions drivers/net/ethernet/mscc/ocelot_vsc7514.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*
* Copyright (c) 2017 Microsemi Corporation
*/
#include <linux/dsa/ocelot.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_net.h>
Expand All @@ -18,8 +19,6 @@
#include <soc/mscc/ocelot_hsio.h>
#include "ocelot.h"

#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))

static const u32 ocelot_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x009000),
REG(ANA_VLANMASK, 0x009004),
Expand Down Expand Up @@ -532,29 +531,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
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,
u32 *rval)
{
Expand Down Expand Up @@ -609,42 +585,44 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
struct ocelot_port_private *priv;
struct ocelot_port *ocelot_port;
u64 tod_in_ns, full_ts_in_ns;
struct frame_info info = {};
u64 src_port, len, timestamp;
struct net_device *dev;
u32 ifh[4], val, *buf;
u32 xfh[4], val, *buf;
struct timespec64 ts;
int sz, len, buf_len;
struct sk_buff *skb;
int sz, buf_len;

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)
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
* otherwise a frame could come in CPU queue between the while
* condition and the check for error later on. And in that case
* the new frame is just removed and not processed.
*/
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,
port);
dev = priv->dev;

skb = netdev_alloc_skb(dev, info.len);
skb = netdev_alloc_skb(dev, len);

if (unlikely(!skb)) {
netdev_err(dev, "Unable to allocate sk_buff\n");
err = -ENOMEM;
goto out;
}
buf_len = info.len - ETH_FCS_LEN;
buf_len = len - ETH_FCS_LEN;
buf = (u32 *)skb_put(skb, buf_len);

len = 0;
Expand Down Expand Up @@ -677,12 +655,12 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);

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) |
info.timestamp;
timestamp;
else
full_ts_in_ns = (tod_in_ns & GENMASK_ULL(63, 32)) |
info.timestamp;
timestamp;

shhwtstamps = skb_hwtstamps(skb);
memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
Expand All @@ -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
* has already been forwarded.
*/
if (ocelot->bridge_mask & BIT(info.port))
if (ocelot->bridge_mask & BIT(src_port))
skb->offload_fwd_mark = 1;

skb->protocol = eth_type_trans(skb, dev);
Expand Down
Loading

0 comments on commit 40d3f29

Please sign in to comment.