Commit 6505b680 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

net: mscc: ocelot: add MAC Merge layer support for VSC9959



Felix (VSC9959) has a DEV_GMII:MM_CONFIG block composed of 2 registers
(ENABLE_CONFIG and VERIF_CONFIG). Because the MAC Merge statistics and
pMAC statistics are already in the Ocelot switch lib even if just Felix
supports them, I'm adding support for the whole MAC Merge layer in the
common Ocelot library too.

There is an interrupt (shared with the PTP interrupt) which signals
changes to the MM verification state. This is done because the
preemptible traffic classes should be committed to hardware only once
the verification procedure has declared the link partner of being
capable of receiving preemptible frames.

We implement ethtool getters and setters for the MAC Merge layer state.
The "TX enabled" and "verify status" are taken from the IRQ handler,
using a mutex to ensure serialized access.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab3f97a9
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -2024,6 +2024,23 @@ static int felix_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
	return ocelot_port_del_dscp_prio(ocelot, port, dscp, prio);
}

static int felix_get_mm(struct dsa_switch *ds, int port,
			struct ethtool_mm_state *state)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_port_get_mm(ocelot, port, state);
}

static int felix_set_mm(struct dsa_switch *ds, int port,
			struct ethtool_mm_cfg *cfg,
			struct netlink_ext_ack *extack)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_port_set_mm(ocelot, port, cfg, extack);
}

static void felix_get_mm_stats(struct dsa_switch *ds, int port,
			       struct ethtool_mm_stats *stats)
{
@@ -2039,6 +2056,8 @@ const struct dsa_switch_ops felix_switch_ops = {
	.setup				= felix_setup,
	.teardown			= felix_teardown,
	.set_ageing_time		= felix_set_ageing_time,
	.get_mm				= felix_get_mm,
	.set_mm				= felix_set_mm,
	.get_mm_stats			= felix_get_mm_stats,
	.get_stats64			= felix_get_stats64,
	.get_pause_stats		= felix_get_pause_stats,
+11 −8
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include <soc/mscc/ocelot_qsys.h>
#include <soc/mscc/ocelot_vcap.h>
#include <soc/mscc/ocelot_ana.h>
#include <soc/mscc/ocelot_dev.h>
#include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot_sys.h>
#include <net/tc_act/tc_gate.h>
@@ -476,6 +477,9 @@ static const u32 vsc9959_dev_gmii_regmap[] = {
	REG(DEV_MAC_FC_MAC_LOW_CFG,		0x3c),
	REG(DEV_MAC_FC_MAC_HIGH_CFG,		0x40),
	REG(DEV_MAC_STICKY,			0x44),
	REG(DEV_MM_ENABLE_CONFIG,		0x48),
	REG(DEV_MM_VERIF_CONFIG,		0x4C),
	REG(DEV_MM_STATUS,			0x50),
	REG_RESERVED(PCS1G_CFG),
	REG_RESERVED(PCS1G_MODE_CFG),
	REG_RESERVED(PCS1G_SD_CFG),
@@ -2599,20 +2603,19 @@ static const struct felix_info felix_info_vsc9959 = {
	.tas_guard_bands_update	= vsc9959_tas_guard_bands_update,
};

/* The INTB interrupt is shared between for PTP TX timestamp availability
 * notification and MAC Merge status change on each port.
 */
static irqreturn_t felix_irq_handler(int irq, void *data)
{
	struct ocelot *ocelot = (struct ocelot *)data;

	/* The INTB interrupt is used for both PTP TX timestamp interrupt
	 * and preemption status change interrupt on each port.
	 *
	 * - Get txtstamp if have
	 * - TODO: handle preemption. Without handling it, driver may get
	 *   interrupt storm.
	 */
	int port;

	ocelot_get_txtstamp(ocelot);

	for (port = 0; port < ocelot->num_phys_ports; port++)
		ocelot_port_mm_irq(ocelot, port);

	return IRQ_HANDLED;
}

+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ mscc_ocelot_switch_lib-y := \
	ocelot_devlink.o \
	ocelot_flower.o \
	ocelot_io.o \
	ocelot_mm.o \
	ocelot_police.o \
	ocelot_ptp.o \
	ocelot_stats.o \
+14 −4
Original line number Diff line number Diff line
@@ -2738,10 +2738,8 @@ int ocelot_init(struct ocelot *ocelot)
		return -ENOMEM;

	ret = ocelot_stats_init(ocelot);
	if (ret) {
		destroy_workqueue(ocelot->owq);
		return ret;
	}
	if (ret)
		goto err_stats_init;

	INIT_LIST_HEAD(&ocelot->multicast);
	INIT_LIST_HEAD(&ocelot->pgids);
@@ -2756,6 +2754,12 @@ int ocelot_init(struct ocelot *ocelot)
	if (ocelot->ops->psfp_init)
		ocelot->ops->psfp_init(ocelot);

	if (ocelot->mm_supported) {
		ret = ocelot_mm_init(ocelot);
		if (ret)
			goto err_mm_init;
	}

	for (port = 0; port < ocelot->num_phys_ports; port++) {
		/* Clear all counters (5 groups) */
		ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port) |
@@ -2853,6 +2857,12 @@ int ocelot_init(struct ocelot *ocelot)
				 ANA_CPUQ_8021_CFG, i);

	return 0;

err_mm_init:
	ocelot_stats_deinit(ocelot);
err_stats_init:
	destroy_workqueue(ocelot->owq);
	return ret;
}
EXPORT_SYMBOL(ocelot_init);

+2 −0
Original line number Diff line number Diff line
@@ -109,6 +109,8 @@ void ocelot_mirror_put(struct ocelot *ocelot);
int ocelot_stats_init(struct ocelot *ocelot);
void ocelot_stats_deinit(struct ocelot *ocelot);

int ocelot_mm_init(struct ocelot *ocelot);

extern struct notifier_block ocelot_netdevice_nb;
extern struct notifier_block ocelot_switchdev_nb;
extern struct notifier_block ocelot_switchdev_blocking_nb;
Loading