Commit 93c5d741 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sja1105-fixes'



Vladimir Oltean says:

====================
Fixes for SJA1105 DSA driver

This series contains some minor fixes in the sja1105 driver:
- improved error handling in the probe path
- rejecting an invalid phy-mode specified in the device tree
- register access fix for SJA1105P/Q/R/S for the virtual links through
  the dynamic reconfiguration interface
- handling 2 bridge VLANs where the second is supposed to overwrite the
  first
- making sure that the lack of a pvid results in the actual dropping of
  untagged traffic
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a6e9a9c b38e659d
Loading
Loading
Loading
Loading
+19 −4
Original line number Diff line number Diff line
@@ -167,8 +167,9 @@ enum sja1105_hostcmd {
	SJA1105_HOSTCMD_INVALIDATE = 4,
};

/* Command and entry overlap */
static void
sja1105_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
sja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	const int size = SJA1105_SIZE_DYN_CMD;
@@ -179,6 +180,20 @@ sja1105_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(buf, &cmd->index,    9,  0, size, op);
}

/* Command and entry are separate */
static void
sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
	sja1105_packing(p, &cmd->index,    9,  0, size, op);
}

static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
						enum packing_op op)
{
@@ -641,7 +656,7 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_VL_LOOKUP] = {
		.entry_packing = sja1105et_vl_lookup_entry_packing,
		.cmd_packing = sja1105_vl_lookup_cmd_packing,
		.cmd_packing = sja1105et_vl_lookup_cmd_packing,
		.access = OP_WRITE,
		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
		.packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
@@ -725,7 +740,7 @@ const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_VL_LOOKUP] = {
		.entry_packing = sja1105_vl_lookup_entry_packing,
		.cmd_packing = sja1105_vl_lookup_cmd_packing,
		.cmd_packing = sja1105pqrs_vl_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE),
		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
+51 −23
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "sja1105_tas.h"

#define SJA1105_UNKNOWN_MULTICAST	0x010000000000ull
#define SJA1105_DEFAULT_VLAN		(VLAN_N_VID - 1)

static const struct dsa_switch_ops sja1105_switch_ops;

@@ -207,6 +208,7 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
		default:
			dev_err(dev, "Unsupported PHY mode %s!\n",
				phy_modes(ports[i].phy_mode));
			return -EINVAL;
		}

		/* Even though the SerDes port is able to drive SGMII autoneg
@@ -321,6 +323,13 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
	return 0;
}

/* Set up a default VLAN for untagged traffic injected from the CPU
 * using management routes (e.g. STP, PTP) as opposed to tag_8021q.
 * All DT-defined ports are members of this VLAN, and there are no
 * restrictions on forwarding (since the CPU selects the destination).
 * Frames from this VLAN will always be transmitted as untagged, and
 * neither the bridge nor the 8021q module cannot create this VLAN ID.
 */
static int sja1105_init_static_vlan(struct sja1105_private *priv)
{
	struct sja1105_table *table;
@@ -330,17 +339,13 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
		.vmemb_port = 0,
		.vlan_bc = 0,
		.tag_port = 0,
		.vlanid = 1,
		.vlanid = SJA1105_DEFAULT_VLAN,
	};
	struct dsa_switch *ds = priv->ds;
	int port;

	table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP];

	/* The static VLAN table will only contain the initial pvid of 1.
	 * All other VLANs are to be configured through dynamic entries,
	 * and kept in the static configuration table as backing memory.
	 */
	if (table->entry_count) {
		kfree(table->entries);
		table->entry_count = 0;
@@ -353,9 +358,6 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)

	table->entry_count = 1;

	/* VLAN 1: all DT-defined ports are members; no restrictions on
	 * forwarding; always transmit as untagged.
	 */
	for (port = 0; port < ds->num_ports; port++) {
		struct sja1105_bridge_vlan *v;

@@ -366,15 +368,12 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
		pvid.vlan_bc |= BIT(port);
		pvid.tag_port &= ~BIT(port);

		/* Let traffic that don't need dsa_8021q (e.g. STP, PTP) be
		 * transmitted as untagged.
		 */
		v = kzalloc(sizeof(*v), GFP_KERNEL);
		if (!v)
			return -ENOMEM;

		v->port = port;
		v->vid = 1;
		v->vid = SJA1105_DEFAULT_VLAN;
		v->untagged = true;
		if (dsa_is_cpu_port(ds, port))
			v->pvid = true;
@@ -2817,12 +2816,23 @@ static int sja1105_vlan_add_one(struct dsa_switch *ds, int port, u16 vid,
	bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
	struct sja1105_bridge_vlan *v;

	list_for_each_entry(v, vlan_list, list)
		if (v->port == port && v->vid == vid &&
		    v->untagged == untagged && v->pvid == pvid)
	list_for_each_entry(v, vlan_list, list) {
		if (v->port == port && v->vid == vid) {
			/* Already added */
			if (v->untagged == untagged && v->pvid == pvid)
				/* Nothing changed */
				return 0;

			/* It's the same VLAN, but some of the flags changed
			 * and the user did not bother to delete it first.
			 * Update it and trigger sja1105_build_vlan_table.
			 */
			v->untagged = untagged;
			v->pvid = pvid;
			return 1;
		}
	}

	v = kzalloc(sizeof(*v), GFP_KERNEL);
	if (!v) {
		dev_err(ds->dev, "Out of memory while storing VLAN\n");
@@ -2976,13 +2986,13 @@ static int sja1105_setup(struct dsa_switch *ds)
	rc = sja1105_static_config_load(priv, ports);
	if (rc < 0) {
		dev_err(ds->dev, "Failed to load static config: %d\n", rc);
		return rc;
		goto out_ptp_clock_unregister;
	}
	/* Configure the CGU (PHY link modes and speeds) */
	rc = sja1105_clocking_setup(priv);
	if (rc < 0) {
		dev_err(ds->dev, "Failed to configure MII clocking: %d\n", rc);
		return rc;
		goto out_static_config_free;
	}
	/* On SJA1105, VLAN filtering per se is always enabled in hardware.
	 * The only thing we can do to disable it is lie about what the 802.1Q
@@ -3003,7 +3013,7 @@ static int sja1105_setup(struct dsa_switch *ds)

	rc = sja1105_devlink_setup(ds);
	if (rc < 0)
		return rc;
		goto out_static_config_free;

	/* The DSA/switchdev model brings up switch ports in standalone mode by
	 * default, and that means vlan_filtering is 0 since they're not under
@@ -3012,6 +3022,17 @@ static int sja1105_setup(struct dsa_switch *ds)
	rtnl_lock();
	rc = sja1105_setup_8021q_tagging(ds, true);
	rtnl_unlock();
	if (rc)
		goto out_devlink_teardown;

	return 0;

out_devlink_teardown:
	sja1105_devlink_teardown(ds);
out_ptp_clock_unregister:
	sja1105_ptp_clock_unregister(ds);
out_static_config_free:
	sja1105_static_config_free(&priv->static_config);

	return rc;
}
@@ -3646,8 +3667,10 @@ static int sja1105_probe(struct spi_device *spi)
		priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
					 sizeof(struct sja1105_cbs_entry),
					 GFP_KERNEL);
		if (!priv->cbs)
			return -ENOMEM;
		if (!priv->cbs) {
			rc = -ENOMEM;
			goto out_unregister_switch;
		}
	}

	/* Connections between dsa_port and sja1105_port */
@@ -3672,7 +3695,7 @@ static int sja1105_probe(struct spi_device *spi)
			dev_err(ds->dev,
				"failed to create deferred xmit thread: %d\n",
				rc);
			goto out;
			goto out_destroy_workers;
		}
		skb_queue_head_init(&sp->xmit_queue);
		sp->xmit_tpid = ETH_P_SJA1105;
@@ -3682,7 +3705,8 @@ static int sja1105_probe(struct spi_device *spi)
	}

	return 0;
out:

out_destroy_workers:
	while (port-- > 0) {
		struct sja1105_port *sp = &priv->ports[port];

@@ -3691,6 +3715,10 @@ static int sja1105_probe(struct spi_device *spi)

		kthread_destroy_worker(sp->xmit_worker);
	}

out_unregister_switch:
	dsa_unregister_switch(ds);

	return rc;
}