Commit 58f9f9b5 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'configuring-congestion-watermarks-on-ocelot-switch-using-devlink-sb'

Vladimir Oltean says:

====================
Configuring congestion watermarks on ocelot switch using devlink-sb

In some applications, it is important to create resource reservations in
the Ethernet switches, to prevent background traffic, or deliberate
attacks, from inducing denial of service into the high-priority traffic.

These patches give the user some knobs to turn. The ocelot switches
support per-port and per-port-tc reservations, on ingress and on egress.
The resources that are monitored are packet buffers (in cells of 60
bytes each) and frame references.

The frames that exceed the reservations can optionally consume from
sharing watermarks which are not per-port but global across the switch.
There are 10 sharing watermarks, 8 of them are per traffic class and 2
are per drop priority.

I am configuring the hardware using the best of my knowledge, and mostly
through trial and error. Same goes for devlink-sb integration. Feedback
is welcome.
====================

Link: https://lore.kernel.org/r/20210115021120.3055988-1-olteanv@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 2d9116be f59fd9ca
Loading
Loading
Loading
Loading
+161 −44
Original line number Diff line number Diff line
@@ -299,7 +299,7 @@ static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
		       ANA_PORT_QOS_CFG,
		       port);

	for (i = 0; i < FELIX_NUM_TC * 2; i++) {
	for (i = 0; i < OCELOT_NUM_TC * 2; i++) {
		ocelot_rmw_ix(ocelot,
			      (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
@@ -422,12 +422,12 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
	ocelot->map		= felix->info->map;
	ocelot->stats_layout	= felix->info->stats_layout;
	ocelot->num_stats	= felix->info->num_stats;
	ocelot->shared_queue_sz	= felix->info->shared_queue_sz;
	ocelot->num_mact_rows	= felix->info->num_mact_rows;
	ocelot->vcap		= felix->info->vcap;
	ocelot->ops		= felix->info->ops;
	ocelot->inj_prefix	= OCELOT_TAG_PREFIX_SHORT;
	ocelot->xtr_prefix	= OCELOT_TAG_PREFIX_SHORT;
	ocelot->devlink		= felix->ds->devlink;

	port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
				 GFP_KERNEL);
@@ -589,6 +589,10 @@ static int felix_setup(struct dsa_switch *ds)
		felix_port_qos_map_init(ocelot, port);
	}

	err = ocelot_devlink_sb_register(ocelot);
	if (err)
		return err;

	/* Include the CPU port module in the forwarding mask for unknown
	 * unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST
	 * excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since
@@ -610,14 +614,15 @@ static void felix_teardown(struct dsa_switch *ds)
	struct felix *felix = ocelot_to_felix(ocelot);
	int port;

	if (felix->info->mdio_bus_free)
		felix->info->mdio_bus_free(ocelot);
	ocelot_devlink_sb_unregister(ocelot);
	ocelot_deinit_timestamp(ocelot);
	ocelot_deinit(ocelot);

	for (port = 0; port < ocelot->num_phys_ports; port++)
		ocelot_deinit_port(ocelot, port);
	ocelot_deinit_timestamp(ocelot);
	/* stop workqueue thread */
	ocelot_deinit(ocelot);

	if (felix->info->mdio_bus_free)
		felix->info->mdio_bus_free(ocelot);
}

static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
@@ -751,6 +756,108 @@ static int felix_port_setup_tc(struct dsa_switch *ds, int port,
		return -EOPNOTSUPP;
}

static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index,
			     u16 pool_index,
			     struct devlink_sb_pool_info *pool_info)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
}

static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index,
			     u16 pool_index, u32 size,
			     enum devlink_sb_threshold_type threshold_type,
			     struct netlink_ext_ack *extack)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
				  threshold_type, extack);
}

static int felix_sb_port_pool_get(struct dsa_switch *ds, int port,
				  unsigned int sb_index, u16 pool_index,
				  u32 *p_threshold)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index,
				       p_threshold);
}

static int felix_sb_port_pool_set(struct dsa_switch *ds, int port,
				  unsigned int sb_index, u16 pool_index,
				  u32 threshold, struct netlink_ext_ack *extack)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index,
				       threshold, extack);
}

static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port,
				     unsigned int sb_index, u16 tc_index,
				     enum devlink_sb_pool_type pool_type,
				     u16 *p_pool_index, u32 *p_threshold)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index,
					  pool_type, p_pool_index,
					  p_threshold);
}

static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port,
				     unsigned int sb_index, u16 tc_index,
				     enum devlink_sb_pool_type pool_type,
				     u16 pool_index, u32 threshold,
				     struct netlink_ext_ack *extack)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index,
					  pool_type, pool_index, threshold,
					  extack);
}

static int felix_sb_occ_snapshot(struct dsa_switch *ds,
				 unsigned int sb_index)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_occ_snapshot(ocelot, sb_index);
}

static int felix_sb_occ_max_clear(struct dsa_switch *ds,
				  unsigned int sb_index)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_occ_max_clear(ocelot, sb_index);
}

static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port,
				      unsigned int sb_index, u16 pool_index,
				      u32 *p_cur, u32 *p_max)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index,
					   p_cur, p_max);
}

static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port,
					 unsigned int sb_index, u16 tc_index,
					 enum devlink_sb_pool_type pool_type,
					 u32 *p_cur, u32 *p_max)
{
	struct ocelot *ocelot = ds->priv;

	return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index,
					      pool_type, p_cur, p_max);
}

const struct dsa_switch_ops felix_switch_ops = {
	.get_tag_protocol		= felix_get_tag_protocol,
	.setup				= felix_setup,
@@ -789,6 +896,16 @@ const struct dsa_switch_ops felix_switch_ops = {
	.cls_flower_del			= felix_cls_flower_del,
	.cls_flower_stats		= felix_cls_flower_stats,
	.port_setup_tc			= felix_port_setup_tc,
	.devlink_sb_pool_get		= felix_sb_pool_get,
	.devlink_sb_pool_set		= felix_sb_pool_set,
	.devlink_sb_port_pool_get	= felix_sb_port_pool_get,
	.devlink_sb_port_pool_set	= felix_sb_port_pool_set,
	.devlink_sb_tc_pool_bind_get	= felix_sb_tc_pool_bind_get,
	.devlink_sb_tc_pool_bind_set	= felix_sb_tc_pool_bind_set,
	.devlink_sb_occ_snapshot	= felix_sb_occ_snapshot,
	.devlink_sb_occ_max_clear	= felix_sb_occ_max_clear,
	.devlink_sb_occ_port_pool_get	= felix_sb_occ_port_pool_get,
	.devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get,
};

struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
+0 −2
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@
#define _MSCC_FELIX_H

#define ocelot_to_felix(o)		container_of((o), struct felix, ocelot)
#define FELIX_NUM_TC			8

/* Platform-specific information */
struct felix_info {
@@ -15,7 +14,6 @@ struct felix_info {
	const struct reg_field		*regfields;
	const u32 *const		*map;
	const struct ocelot_ops		*ops;
	int				shared_queue_sz;
	int				num_mact_rows;
	const struct ocelot_stat_layout	*stats_layout;
	unsigned int			num_stats;
+20 −3
Original line number Diff line number Diff line
@@ -1006,9 +1006,27 @@ static u16 vsc9959_wm_enc(u16 value)
	return value;
}

static u16 vsc9959_wm_dec(u16 wm)
{
	WARN_ON(wm & ~GENMASK(8, 0));

	if (wm & BIT(8))
		return (wm & GENMASK(7, 0)) * 16;

	return wm;
}

static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
{
	*inuse = (val & GENMASK(23, 12)) >> 12;
	*maxuse = val & GENMASK(11, 0);
}

static const struct ocelot_ops vsc9959_ops = {
	.reset			= vsc9959_reset,
	.wm_enc			= vsc9959_wm_enc,
	.wm_dec			= vsc9959_wm_dec,
	.wm_stat		= vsc9959_wm_stat,
	.port_to_netdev		= felix_port_to_netdev,
	.netdev_to_port		= felix_netdev_to_port,
};
@@ -1356,10 +1374,9 @@ static const struct felix_info felix_info_vsc9959 = {
	.stats_layout		= vsc9959_stats_layout,
	.num_stats		= ARRAY_SIZE(vsc9959_stats_layout),
	.vcap			= vsc9959_vcap_props,
	.shared_queue_sz	= 128 * 1024,
	.num_mact_rows		= 2048,
	.num_ports		= 6,
	.num_tx_queues		= FELIX_NUM_TC,
	.num_tx_queues		= OCELOT_NUM_TC,
	.switch_pci_bar		= 4,
	.imdio_pci_bar		= 0,
	.ptp_caps		= &vsc9959_ptp_caps,
@@ -1418,7 +1435,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
	pci_set_drvdata(pdev, felix);
	ocelot = &felix->ocelot;
	ocelot->dev = &pdev->dev;
	ocelot->num_flooding_pgids = FELIX_NUM_TC;
	ocelot->num_flooding_pgids = OCELOT_NUM_TC;
	felix->info = &felix_info_vsc9959;
	felix->switch_base = pci_resource_start(pdev,
						felix->info->switch_pci_bar);
+19 −1
Original line number Diff line number Diff line
@@ -1057,9 +1057,27 @@ static u16 vsc9953_wm_enc(u16 value)
	return value;
}

static u16 vsc9953_wm_dec(u16 wm)
{
	WARN_ON(wm & ~GENMASK(9, 0));

	if (wm & BIT(9))
		return (wm & GENMASK(8, 0)) * 16;

	return wm;
}

static void vsc9953_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
{
	*inuse = (val & GENMASK(25, 13)) >> 13;
	*maxuse = val & GENMASK(12, 0);
}

static const struct ocelot_ops vsc9953_ops = {
	.reset			= vsc9953_reset,
	.wm_enc			= vsc9953_wm_enc,
	.wm_dec			= vsc9953_wm_dec,
	.wm_stat		= vsc9953_wm_stat,
	.port_to_netdev		= felix_port_to_netdev,
	.netdev_to_port		= felix_netdev_to_port,
};
@@ -1181,9 +1199,9 @@ static const struct felix_info seville_info_vsc9953 = {
	.stats_layout		= vsc9953_stats_layout,
	.num_stats		= ARRAY_SIZE(vsc9953_stats_layout),
	.vcap			= vsc9953_vcap_props,
	.shared_queue_sz	= 256 * 1024,
	.num_mact_rows		= 2048,
	.num_ports		= 10,
	.num_tx_queues		= OCELOT_NUM_TC,
	.mdio_bus_alloc		= vsc9953_mdio_bus_alloc,
	.mdio_bus_free		= vsc9953_mdio_bus_free,
	.phylink_validate	= vsc9953_phylink_validate,
+2 −1
Original line number Diff line number Diff line
@@ -6,7 +6,8 @@ mscc_ocelot_switch_lib-y := \
	ocelot_police.o \
	ocelot_vcap.o \
	ocelot_flower.o \
	ocelot_ptp.o
	ocelot_ptp.o \
	ocelot_devlink.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
mscc_ocelot-y := \
	ocelot_vsc7514.o \
Loading