Commit a3ae1603 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'mv88e6xxx-add-mab-offload-support'

Hans J. Schultz says:

====================
mv88e6xxx: Add MAB offload support

This patch-set adds MAB [1] offload support in mv88e6xxx.

Patch #1: Correct default return value for mv88e6xxx_port_bridge_flags.

Patch #2: Shorten the locked section in
          mv88e6xxx_g1_atu_prob_irq_thread_fn().

Patch #3: The MAB implementation for mv88e6xxx.

[1] https://git.kernel.org/netdev/net-next/c/4bf24ad09bc0
====================

Link: https://lore.kernel.org/r/20230108094849.1789162-1-netdev@kapio-technology.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 07445f3c 830763b9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ mv88e6xxx-objs += port_hidden.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
mv88e6xxx-objs += serdes.o
mv88e6xxx-objs += smi.o
mv88e6xxx-objs += switchdev.o
mv88e6xxx-objs += trace.o

# for tracing framework to find trace.h
+13 −7
Original line number Diff line number Diff line
@@ -1728,7 +1728,7 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
	return err;
}

static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
		       int (*cb)(struct mv88e6xxx_chip *chip,
				 const struct mv88e6xxx_vtu_entry *entry,
				 void *priv),
@@ -6526,7 +6526,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
	const struct mv88e6xxx_ops *ops;

	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
			   BR_BCAST_FLOOD | BR_PORT_LOCKED))
			   BR_BCAST_FLOOD | BR_PORT_LOCKED | BR_PORT_MAB))
		return -EINVAL;

	ops = chip->info->ops;
@@ -6545,7 +6545,7 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
				       struct netlink_ext_ack *extack)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err = -EOPNOTSUPP;
	int err = 0;

	mv88e6xxx_reg_lock(chip);

@@ -6584,6 +6584,12 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
			goto out;
	}

	if (flags.mask & BR_PORT_MAB) {
		bool mab = !!(flags.val & BR_PORT_MAB);

		mv88e6xxx_port_set_mab(chip, port, mab);
	}

	if (flags.mask & BR_PORT_LOCKED) {
		bool locked = !!(flags.val & BR_PORT_LOCKED);

+15 −0
Original line number Diff line number Diff line
@@ -280,6 +280,9 @@ struct mv88e6xxx_port {
	unsigned int serdes_irq;
	char serdes_irq_name[64];
	struct devlink_region *region;

	/* MacAuth Bypass control flag */
	bool mab;
};

enum mv88e6xxx_region_id {
@@ -784,6 +787,12 @@ static inline bool mv88e6xxx_is_invalid_port(struct mv88e6xxx_chip *chip, int po
	return (chip->info->invalid_port_mask & BIT(port)) != 0;
}

static inline void mv88e6xxx_port_set_mab(struct mv88e6xxx_chip *chip,
					  int port, bool mab)
{
	chip->ports[port].mab = mab;
}

int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
@@ -802,6 +811,12 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
	mutex_unlock(&chip->reg_lock);
}

int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
		       int (*cb)(struct mv88e6xxx_chip *chip,
				 const struct mv88e6xxx_vtu_entry *entry,
				 void *priv),
		       void *priv);

int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);

#endif /* _MV88E6XXX_CHIP_H */
+17 −7
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#include "chip.h"
#include "global1.h"
#include "switchdev.h"
#include "trace.h"

/* Offset 0x01: ATU FID Register */
@@ -409,23 +410,25 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)

	err = mv88e6xxx_g1_read_atu_violation(chip);
	if (err)
		goto out;
		goto out_unlock;

	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val);
	if (err)
		goto out;
		goto out_unlock;

	err = mv88e6xxx_g1_atu_fid_read(chip, &fid);
	if (err)
		goto out;
		goto out_unlock;

	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
	if (err)
		goto out;
		goto out_unlock;

	err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
	if (err)
		goto out;
		goto out_unlock;

	mv88e6xxx_reg_unlock(chip);

	spid = entry.state;

@@ -441,6 +444,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
						   entry.portvec, entry.mac,
						   fid);
		chip->ports[spid].atu_miss_violation++;

		if (fid != MV88E6XXX_FID_STANDALONE && chip->ports[spid].mab) {
			err = mv88e6xxx_handle_miss_violation(chip, spid,
							      &entry, fid);
			if (err)
				goto out;
		}
	}

	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
@@ -449,13 +459,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
						   fid);
		chip->ports[spid].atu_full_violation++;
	}
	mv88e6xxx_reg_unlock(chip);

	return IRQ_HANDLED;

out:
out_unlock:
	mv88e6xxx_reg_unlock(chip);

out:
	dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
		err);
	return IRQ_HANDLED;
+83 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * switchdev.c
 *
 *	Authors:
 *	Hans J. Schultz		<netdev@kapio-technology.com>
 *
 */

#include <net/switchdev.h>
#include "chip.h"
#include "global1.h"
#include "switchdev.h"

struct mv88e6xxx_fid_search_ctx {
	u16 fid_search;
	u16 vid_found;
};

static int __mv88e6xxx_find_vid(struct mv88e6xxx_chip *chip,
				const struct mv88e6xxx_vtu_entry *entry,
				void *priv)
{
	struct mv88e6xxx_fid_search_ctx *ctx = priv;

	if (ctx->fid_search == entry->fid) {
		ctx->vid_found = entry->vid;
		return 1;
	}

	return 0;
}

static int mv88e6xxx_find_vid(struct mv88e6xxx_chip *chip, u16 fid, u16 *vid)
{
	struct mv88e6xxx_fid_search_ctx ctx;
	int err;

	ctx.fid_search = fid;
	mv88e6xxx_reg_lock(chip);
	err = mv88e6xxx_vtu_walk(chip, __mv88e6xxx_find_vid, &ctx);
	mv88e6xxx_reg_unlock(chip);
	if (err < 0)
		return err;
	if (err == 1)
		*vid = ctx.vid_found;
	else
		return -ENOENT;

	return 0;
}

int mv88e6xxx_handle_miss_violation(struct mv88e6xxx_chip *chip, int port,
				    struct mv88e6xxx_atu_entry *entry, u16 fid)
{
	struct switchdev_notifier_fdb_info info = {
		.addr = entry->mac,
		.locked = true,
	};
	struct net_device *brport;
	struct dsa_port *dp;
	u16 vid;
	int err;

	err = mv88e6xxx_find_vid(chip, fid, &vid);
	if (err)
		return err;

	info.vid = vid;
	dp = dsa_to_port(chip->ds, port);

	rtnl_lock();
	brport = dsa_port_to_bridge_port(dp);
	if (!brport) {
		rtnl_unlock();
		return -ENODEV;
	}
	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
				       brport, &info.info, NULL);
	rtnl_unlock();

	return err;
}
Loading