Commit c2e72265 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by David S. Miller
Browse files

net: dsa: microchip: add support DSCP priority mapping



Microchip KSZ and LAN variants do not have per port DSCP priority
configuration. Instead there is a global DSCP mapping table.

This patch provides write access to this global DSCP map. In case entry
is "deleted", we map corresponding DSCP entry to a best effort prio,
which is expected to be the default priority for all untagged traffic.

Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5f5109af
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2360,6 +2360,7 @@ static int ksz_setup(struct dsa_switch *ds)
	ksz_init_mib_timer(dev);

	ds->configure_vlan_while_not_filtering = false;
	ds->dscp_prio_mapping_is_global = true;

	if (dev->dev_ops->setup) {
		ret = dev->dev_ops->setup(ds);
@@ -3989,6 +3990,8 @@ static const struct dsa_switch_ops ksz_switch_ops = {
	.port_get_default_prio	= ksz_port_get_default_prio,
	.port_set_default_prio	= ksz_port_set_default_prio,
	.port_get_dscp_prio	= ksz_port_get_dscp_prio,
	.port_add_dscp_prio	= ksz_port_add_dscp_prio,
	.port_del_dscp_prio	= ksz_port_del_dscp_prio,
	.port_get_apptrust	= ksz_port_get_apptrust,
	.port_set_apptrust	= ksz_port_set_apptrust,
};
+45 −15
Original line number Diff line number Diff line
@@ -310,6 +310,19 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
	return (data >> shift) & mask;
}

static int ksz_set_global_dscp_entry(struct ksz_device *dev, u8 dscp, u8 ipv)
{
	int reg, per_reg, shift;
	u8 mask;

	ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);

	shift = (dscp % per_reg) * (8 / per_reg);

	return ksz_rmw8(dev, reg + (dscp / per_reg), mask << shift,
			ipv << shift);
}

/**
 * ksz_init_global_dscp_map - Initializes the global DSCP-to-priority mapping
 * @dev: Pointer to the KSZ switch device structure
@@ -321,9 +334,7 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
 */
static int ksz_init_global_dscp_map(struct ksz_device *dev)
{
	int reg, per_reg, ret, dscp;
	u8 data = 0;
	u8 mask;
	int ret, dscp;

	/* On KSZ9xxx variants, DSCP remapping is disabled by default.
	 * Enable to have, predictable and reproducible behavior across
@@ -337,10 +348,8 @@ static int ksz_init_global_dscp_map(struct ksz_device *dev)
			return ret;
	}

	ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);

	for (dscp = 0; dscp < DSCP_MAX; dscp++) {
		int ipv, shift, tt;
		int ipv, tt;

		/* Map DSCP to Traffic Type, which is corresponding to the
		 * Internal Priority Value (IPV) in the switch.
@@ -362,19 +371,40 @@ static int ksz_init_global_dscp_map(struct ksz_device *dev)
		if (ipv < 0)
			return ipv;

		shift = (dscp % per_reg) * (8 / per_reg);
		data |= (ipv & mask) << shift;

		if (dscp % per_reg == per_reg - 1) {
			ret = ksz_write8(dev, reg + (dscp / per_reg), data);
			if (ret)
				return ret;
		ret = ksz_set_global_dscp_entry(dev, dscp, ipv);
	}

			data = 0;
	return 0;
}

int ksz_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio)
{
	struct ksz_device *dev = ds->priv;

	if (prio >= dev->info->num_ipvs)
		return -ERANGE;

	return ksz_set_global_dscp_entry(dev, dscp, prio);
}

int ksz_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio)
{
	struct ksz_device *dev = ds->priv;
	int ipv;

	if (ksz_port_get_dscp_prio(ds, port, dscp) != prio)
		return 0;

	if (is_ksz8(dev)) {
		ipv = ieee8021q_tt_to_tc(IEEE8021Q_TT_BE,
					 dev->info->num_tx_queues);
		if (ipv < 0)
			return ipv;
	} else {
		ipv = IEEE8021Q_TT_BE;
	}

	return ksz_set_global_dscp_entry(dev, dscp, ipv);
}

/**
+2 −0
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
int ksz_port_get_default_prio(struct dsa_switch *ds, int port);
int ksz_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio);
int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp);
int ksz_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio);
int ksz_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio);
int ksz_port_set_apptrust(struct dsa_switch *ds, int port,
			  const unsigned char *sel,
			  int nsel);