Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b1bf3f6 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'FDB-VLAN-and-PTP-fixes-for-SJA1105-DSA'



Vladimir Oltean says:

====================
FDB, VLAN and PTP fixes for SJA1105 DSA

This patchset is an assortment of fixes for the net-next version of the
sja1105 DSA driver:
- Avoid a kernel panic when the driver fails to probe or unregisters
- Finish Arnd Bermann's idea of compiling PTP support as part of the
  main DSA driver and not separately
- Better handling of initial port-based VLAN as well as VLANs for
  dsa_8021q FDB entries
- Fix address learning for the SJA1105 P/Q/R/S family
- Make static FDB entries persistent across switch resets
- Fix reporting of statically-added FDB entries in 'bridge fdb show'
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c881e10e d7637782
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10,5 +10,5 @@ sja1105-objs := \
    sja1105_dynamic_config.o \

ifdef CONFIG_NET_DSA_SJA1105_PTP
obj-$(CONFIG_NET_DSA_SJA1105) += sja1105_ptp.o
sja1105-objs += sja1105_ptp.o
endif
+151 −3
Original line number Diff line number Diff line
@@ -3,6 +3,98 @@
 */
#include "sja1105.h"

/* In the dynamic configuration interface, the switch exposes a register-like
 * view of some of the static configuration tables.
 * Many times the field organization of the dynamic tables is abbreviated (not
 * all fields are dynamically reconfigurable) and different from the static
 * ones, but the key reason for having it is that we can spare a switch reset
 * for settings that can be changed dynamically.
 *
 * This file creates a per-switch-family abstraction called
 * struct sja1105_dynamic_table_ops and two operations that work with it:
 * - sja1105_dynamic_config_write
 * - sja1105_dynamic_config_read
 *
 * Compared to the struct sja1105_table_ops from sja1105_static_config.c,
 * the dynamic accessors work with a compound buffer:
 *
 * packed_buf
 *
 * |
 * V
 * +-----------------------------------------+------------------+
 * |              ENTRY BUFFER               |  COMMAND BUFFER  |
 * +-----------------------------------------+------------------+
 *
 * <----------------------- packed_size ------------------------>
 *
 * The ENTRY BUFFER may or may not have the same layout, or size, as its static
 * configuration table entry counterpart. When it does, the same packing
 * function is reused (bar exceptional cases - see
 * sja1105pqrs_dyn_l2_lookup_entry_packing).
 *
 * The reason for the COMMAND BUFFER being at the end is to be able to send
 * a dynamic write command through a single SPI burst. By the time the switch
 * reacts to the command, the ENTRY BUFFER is already populated with the data
 * sent by the core.
 *
 * The COMMAND BUFFER is always SJA1105_SIZE_DYN_CMD bytes (one 32-bit word) in
 * size.
 *
 * Sometimes the ENTRY BUFFER does not really exist (when the number of fields
 * that can be reconfigured is small), then the switch repurposes some of the
 * unused 32 bits of the COMMAND BUFFER to hold ENTRY data.
 *
 * The key members of struct sja1105_dynamic_table_ops are:
 * - .entry_packing: A function that deals with packing an ENTRY structure
 *		     into an SPI buffer, or retrieving an ENTRY structure
 *		     from one.
 *		     The @packed_buf pointer it's given does always point to
 *		     the ENTRY portion of the buffer.
 * - .cmd_packing: A function that deals with packing/unpacking the COMMAND
 *		   structure to/from the SPI buffer.
 *		   It is given the same @packed_buf pointer as .entry_packing,
 *		   so most of the time, the @packed_buf points *behind* the
 *		   COMMAND offset inside the buffer.
 *		   To access the COMMAND portion of the buffer, the function
 *		   knows its correct offset.
 *		   Giving both functions the same pointer is handy because in
 *		   extreme cases (see sja1105pqrs_dyn_l2_lookup_entry_packing)
 *		   the .entry_packing is able to jump to the COMMAND portion,
 *		   or vice-versa (sja1105pqrs_l2_lookup_cmd_packing).
 * - .access: A bitmap of:
 *	OP_READ: Set if the hardware manual marks the ENTRY portion of the
 *		 dynamic configuration table buffer as R (readable) after
 *		 an SPI read command (the switch will populate the buffer).
 *	OP_WRITE: Set if the manual marks the ENTRY portion of the dynamic
 *		  table buffer as W (writable) after an SPI write command
 *		  (the switch will read the fields provided in the buffer).
 *	OP_DEL: Set if the manual says the VALIDENT bit is supported in the
 *		COMMAND portion of this dynamic config buffer (i.e. the
 *		specified entry can be invalidated through a SPI write
 *		command).
 *	OP_SEARCH: Set if the manual says that the index of an entry can
 *		   be retrieved in the COMMAND portion of the buffer based
 *		   on its ENTRY portion, as a result of a SPI write command.
 *		   Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
 *		   this.
 * - .max_entry_count: The number of entries, counting from zero, that can be
 *		       reconfigured through the dynamic interface. If a static
 *		       table can be reconfigured at all dynamically, this
 *		       number always matches the maximum number of supported
 *		       static entries.
 * - .packed_size: The length in bytes of the compound ENTRY + COMMAND BUFFER.
 *		   Note that sometimes the compound buffer may contain holes in
 *		   it (see sja1105_vlan_lookup_cmd_packing). The @packed_buf is
 *		   contiguous however, so @packed_size includes any unused
 *		   bytes.
 * - .addr: The base SPI address at which the buffer must be written to the
 *	    switch's memory. When looking at the hardware manual, this must
 *	    always match the lowest documented address for the ENTRY, and not
 *	    that of the COMMAND, since the other 32-bit words will follow along
 *	    at the correct addresses.
 */

#define SJA1105_SIZE_DYN_CMD					4

#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
@@ -57,13 +149,11 @@ sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
{
	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;
	u64 lockeds = 0;
	u64 hostcmd;

	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
	sja1105_packing(p, &lockeds,       28, 28, size, op);
	sja1105_packing(p, &cmd->valident, 27, 27, size, op);

	/* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
@@ -113,6 +203,64 @@ sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
}

/* The switch is so retarded that it makes our command/entry abstraction
 * crumble apart.
 *
 * On P/Q/R/S, the switch tries to say whether a FDB entry
 * is statically programmed or dynamically learned via a flag called LOCKEDS.
 * The hardware manual says about this fiels:
 *
 *   On write will specify the format of ENTRY.
 *   On read the flag will be found cleared at times the VALID flag is found
 *   set.  The flag will also be found cleared in response to a read having the
 *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
 *   cleared, the flag be set if the most recent access operated on an entry
 *   that was either loaded by configuration or through dynamic reconfiguration
 *   (as opposed to automatically learned entries).
 *
 * The trouble with this flag is that it's part of the *command* to access the
 * dynamic interface, and not part of the *entry* retrieved from it.
 * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
 * an output from the switch into the command buffer, and for a
 * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
 * (hence we can write either static, or automatically learned entries, from
 * the core).
 * But the manual contradicts itself in the last phrase where it says that on
 * read, LOCKEDS will be set to 1 for all FDB entries written through the
 * dynamic interface (therefore, the value of LOCKEDS from the
 * sja1105_dynamic_config_write is not really used for anything, it'll store a
 * 1 anyway).
 * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
 * learned) into the switch, which kind of makes sense.
 * As for reading through the dynamic interface, it doesn't make too much sense
 * to put LOCKEDS into the command, since the switch will inevitably have to
 * ignore it (otherwise a command would be like "read the FDB entry 123, but
 * only if it's dynamically learned" <- well how am I supposed to know?) and
 * just use it as an output buffer for its findings. But guess what... that's
 * what the entry buffer is for!
 * Unfortunately, what really breaks this abstraction is the fact that it
 * wasn't designed having the fact in mind that the switch can output
 * entry-related data as writeback through the command buffer.
 * However, whether a FDB entry is statically or dynamically learned *is* part
 * of the entry and not the command data, no matter what the switch thinks.
 * In order to do that, we'll need to wrap around the
 * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
 * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
 * command buffer.
 */
static size_t
sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
					enum packing_op op)
{
	struct sja1105_l2_lookup_entry *entry = entry_ptr;
	u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);

	return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
}

static void
sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
@@ -393,7 +541,7 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
/* SJA1105P/Q/R/S: Second generation */
struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_L2_LOOKUP] = {
		.entry_packing = sja1105pqrs_l2_lookup_entry_packing,
		.entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
+179 −48
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
		.maxage = 0xFF,
		/* Internal VLAN (pvid) to apply to untagged ingress */
		.vlanprio = 0,
		.vlanid = 0,
		.vlanid = 1,
		.ing_mirr = false,
		.egr_mirr = false,
		/* Don't drop traffic with other EtherType than ETH_P_IP */
@@ -203,6 +203,7 @@ static int sja1105_init_static_fdb(struct sja1105_private *priv)
static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
{
	struct sja1105_table *table;
	u64 max_fdb_entries = SJA1105_MAX_L2_LOOKUP_COUNT / SJA1105_NUM_PORTS;
	struct sja1105_l2_lookup_params_entry default_l2_lookup_params = {
		/* Learned FDB entries are forgotten after 300 seconds */
		.maxage = SJA1105_AGEING_TIME_MS(300000),
@@ -210,6 +211,8 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
		.dyn_tbsz = SJA1105ET_FDB_BIN_SIZE,
		/* And the P/Q/R/S equivalent setting: */
		.start_dynspc = 0,
		.maxaddrp = {max_fdb_entries, max_fdb_entries, max_fdb_entries,
			     max_fdb_entries, max_fdb_entries, },
		/* 2^8 + 2^5 + 2^3 + 2^2 + 2^1 + 1 in Koopman notation */
		.poly = 0x97,
		/* This selects between Independent VLAN Learning (IVL) and
@@ -264,20 +267,15 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
		.vmemb_port = 0,
		.vlan_bc = 0,
		.tag_port = 0,
		.vlanid = 0,
		.vlanid = 1,
	};
	int i;

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

	/* The static VLAN table will only contain the initial pvid of 0.
	/* 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.
	 * The pvid of 0 is sufficient to pass traffic while the ports are
	 * standalone and when vlan_filtering is disabled. When filtering
	 * gets enabled, the switchdev core sets up the VLAN ID 1 and sets
	 * it as the new pvid. Actually 'pvid 1' still comes up in 'bridge
	 * vlan' even when vlan_filtering is off, but it has no effect.
	 */
	if (table->entry_count) {
		kfree(table->entries);
@@ -291,7 +289,7 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)

	table->entry_count = 1;

	/* VLAN ID 0: all DT-defined ports are members; no restrictions on
	/* VLAN 1: all DT-defined ports are members; no restrictions on
	 * forwarding; always transmit priority-tagged frames as untagged.
	 */
	for (i = 0; i < SJA1105_NUM_PORTS; i++) {
@@ -818,6 +816,77 @@ static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
		   __ETHTOOL_LINK_MODE_MASK_NBITS);
}

static int
sja1105_find_static_fdb_entry(struct sja1105_private *priv, int port,
			      const struct sja1105_l2_lookup_entry *requested)
{
	struct sja1105_l2_lookup_entry *l2_lookup;
	struct sja1105_table *table;
	int i;

	table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP];
	l2_lookup = table->entries;

	for (i = 0; i < table->entry_count; i++)
		if (l2_lookup[i].macaddr == requested->macaddr &&
		    l2_lookup[i].vlanid == requested->vlanid &&
		    l2_lookup[i].destports & BIT(port))
			return i;

	return -1;
}

/* We want FDB entries added statically through the bridge command to persist
 * across switch resets, which are a common thing during normal SJA1105
 * operation. So we have to back them up in the static configuration tables
 * and hence apply them on next static config upload... yay!
 */
static int
sja1105_static_fdb_change(struct sja1105_private *priv, int port,
			  const struct sja1105_l2_lookup_entry *requested,
			  bool keep)
{
	struct sja1105_l2_lookup_entry *l2_lookup;
	struct sja1105_table *table;
	int rc, match;

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

	match = sja1105_find_static_fdb_entry(priv, port, requested);
	if (match < 0) {
		/* Can't delete a missing entry. */
		if (!keep)
			return 0;

		/* No match => new entry */
		rc = sja1105_table_resize(table, table->entry_count + 1);
		if (rc)
			return rc;

		match = table->entry_count - 1;
	}

	/* Assign pointer after the resize (it may be new memory) */
	l2_lookup = table->entries;

	/* We have a match.
	 * If the job was to add this FDB entry, it's already done (mostly
	 * anyway, since the port forwarding mask may have changed, case in
	 * which we update it).
	 * Otherwise we have to delete it.
	 */
	if (keep) {
		l2_lookup[match] = *requested;
		return 0;
	}

	/* To remove, the strategy is to overwrite the element with
	 * the last one, and then reduce the array size by 1
	 */
	l2_lookup[match] = l2_lookup[table->entry_count - 1];
	return sja1105_table_resize(table, table->entry_count - 1);
}

/* First-generation switches have a 4-way set associative TCAM that
 * holds the FDB entries. An FDB index spans from 0 to 1023 and is comprised of
 * a "bin" (grouping of 4 entries) and a "way" (an entry within a bin).
@@ -868,7 +937,7 @@ int sja1105et_fdb_add(struct dsa_switch *ds, int port,
	struct sja1105_private *priv = ds->priv;
	struct device *dev = ds->dev;
	int last_unused = -1;
	int bin, way;
	int bin, way, rc;

	bin = sja1105et_fdb_hash(priv, addr, vid);

@@ -912,9 +981,13 @@ int sja1105et_fdb_add(struct dsa_switch *ds, int port,
	}
	l2_lookup.index = sja1105et_fdb_index(bin, way);

	return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
	rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
					  l2_lookup.index, &l2_lookup,
					  true);
	if (rc < 0)
		return rc;

	return sja1105_static_fdb_change(priv, port, &l2_lookup, true);
}

int sja1105et_fdb_del(struct dsa_switch *ds, int port,
@@ -922,7 +995,7 @@ int sja1105et_fdb_del(struct dsa_switch *ds, int port,
{
	struct sja1105_l2_lookup_entry l2_lookup = {0};
	struct sja1105_private *priv = ds->priv;
	int index, bin, way;
	int index, bin, way, rc;
	bool keep;

	bin = sja1105et_fdb_hash(priv, addr, vid);
@@ -944,8 +1017,12 @@ int sja1105et_fdb_del(struct dsa_switch *ds, int port,
	else
		keep = false;

	return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
	rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
					  index, &l2_lookup, keep);
	if (rc < 0)
		return rc;

	return sja1105_static_fdb_change(priv, port, &l2_lookup, keep);
}

int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
@@ -993,12 +1070,17 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
		dev_err(ds->dev, "FDB is full, cannot add entry.\n");
		return -EINVAL;
	}
	l2_lookup.lockeds = true;
	l2_lookup.index = i;

skip_finding_an_index:
	return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
	rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
					  l2_lookup.index, &l2_lookup,
					  true);
	if (rc < 0)
		return rc;

	return sja1105_static_fdb_change(priv, port, &l2_lookup, true);
}

int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
@@ -1032,52 +1114,72 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
	else
		keep = false;

	return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
	rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
					  l2_lookup.index, &l2_lookup, keep);
	if (rc < 0)
		return rc;

	return sja1105_static_fdb_change(priv, port, &l2_lookup, keep);
}

static int sja1105_fdb_add(struct dsa_switch *ds, int port,
			   const unsigned char *addr, u16 vid)
{
	struct sja1105_private *priv = ds->priv;
	int rc;
	u16 rx_vid, tx_vid;
	int rc, i;

	if (dsa_port_is_vlan_filtering(&ds->ports[port]))
		return priv->info->fdb_add_cmd(ds, port, addr, vid);

	/* Since we make use of VLANs even when the bridge core doesn't tell us
	 * to, translate these FDB entries into the correct dsa_8021q ones.
	 * The basic idea (also repeats for removal below) is:
	 * - Each of the other front-panel ports needs to be able to forward a
	 *   pvid-tagged (aka tagged with their rx_vid) frame that matches this
	 *   DMAC.
	 * - The CPU port (aka the tx_vid of this port) needs to be able to
	 *   send a frame matching this DMAC to the specified port.
	 * For a better picture see net/dsa/tag_8021q.c.
	 */
	if (!dsa_port_is_vlan_filtering(&ds->ports[port])) {
		unsigned int upstream = dsa_upstream_port(priv->ds, port);
		u16 tx_vid = dsa_8021q_tx_vid(ds, port);
		u16 rx_vid = dsa_8021q_rx_vid(ds, port);
	for (i = 0; i < SJA1105_NUM_PORTS; i++) {
		if (i == port)
			continue;
		if (i == dsa_upstream_port(priv->ds, port))
			continue;

		rc = priv->info->fdb_add_cmd(ds, port, addr, tx_vid);
		rx_vid = dsa_8021q_rx_vid(ds, i);
		rc = priv->info->fdb_add_cmd(ds, port, addr, rx_vid);
		if (rc < 0)
			return rc;
		return priv->info->fdb_add_cmd(ds, upstream, addr, rx_vid);
	}
	return priv->info->fdb_add_cmd(ds, port, addr, vid);
	tx_vid = dsa_8021q_tx_vid(ds, port);
	return priv->info->fdb_add_cmd(ds, port, addr, tx_vid);
}

static int sja1105_fdb_del(struct dsa_switch *ds, int port,
			   const unsigned char *addr, u16 vid)
{
	struct sja1105_private *priv = ds->priv;
	int rc;
	u16 rx_vid, tx_vid;
	int rc, i;

	/* Since we make use of VLANs even when the bridge core doesn't tell us
	 * to, translate these FDB entries into the correct dsa_8021q ones.
	 */
	if (!dsa_port_is_vlan_filtering(&ds->ports[port])) {
		unsigned int upstream = dsa_upstream_port(priv->ds, port);
		u16 tx_vid = dsa_8021q_tx_vid(ds, port);
		u16 rx_vid = dsa_8021q_rx_vid(ds, port);
	if (dsa_port_is_vlan_filtering(&ds->ports[port]))
		return priv->info->fdb_del_cmd(ds, port, addr, vid);

		rc = priv->info->fdb_del_cmd(ds, port, addr, tx_vid);
	for (i = 0; i < SJA1105_NUM_PORTS; i++) {
		if (i == port)
			continue;
		if (i == dsa_upstream_port(priv->ds, port))
			continue;

		rx_vid = dsa_8021q_rx_vid(ds, i);
		rc = priv->info->fdb_del_cmd(ds, port, addr, rx_vid);
		if (rc < 0)
			return rc;
		return priv->info->fdb_del_cmd(ds, upstream, addr, rx_vid);
	}
	return priv->info->fdb_del_cmd(ds, port, addr, vid);
	tx_vid = dsa_8021q_tx_vid(ds, port);
	return priv->info->fdb_del_cmd(ds, port, addr, tx_vid);
}

static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
@@ -1085,8 +1187,12 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
{
	struct sja1105_private *priv = ds->priv;
	struct device *dev = ds->dev;
	u16 rx_vid, tx_vid;
	int i;

	rx_vid = dsa_8021q_rx_vid(ds, port);
	tx_vid = dsa_8021q_tx_vid(ds, port);

	for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
		struct sja1105_l2_lookup_entry l2_lookup = {0};
		u8 macaddr[ETH_ALEN];
@@ -1112,15 +1218,40 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
			continue;
		u64_to_ether_addr(l2_lookup.macaddr, macaddr);

		/* We need to hide the dsa_8021q VLAN from the user.
		 * Convert the TX VID into the pvid that is active in
		 * standalone and non-vlan_filtering modes, aka 1.
		 * The RX VID is applied on the CPU port, which is not seen by
		 * the bridge core anyway, so there's nothing to hide.
		/* On SJA1105 E/T, the switch doesn't implement the LOCKEDS
		 * bit, so it doesn't tell us whether a FDB entry is static
		 * or not.
		 * But, of course, we can find out - we're the ones who added
		 * it in the first place.
		 */
		if (priv->info->device_id == SJA1105E_DEVICE_ID ||
		    priv->info->device_id == SJA1105T_DEVICE_ID) {
			int match;

			match = sja1105_find_static_fdb_entry(priv, port,
							      &l2_lookup);
			l2_lookup.lockeds = (match >= 0);
		}

		/* We need to hide the dsa_8021q VLANs from the user. This
		 * basically means hiding the duplicates and only showing
		 * the pvid that is supposed to be active in standalone and
		 * non-vlan_filtering modes (aka 1).
		 * - For statically added FDB entries (bridge fdb add), we
		 *   can convert the TX VID (coming from the CPU port) into the
		 *   pvid and ignore the RX VIDs of the other ports.
		 * - For dynamically learned FDB entries, a single entry with
		 *   no duplicates is learned - that which has the real port's
		 *   pvid, aka RX VID.
		 */
		if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
		if (!dsa_port_is_vlan_filtering(&ds->ports[port])) {
			if (l2_lookup.vlanid == tx_vid ||
			    l2_lookup.vlanid == rx_vid)
				l2_lookup.vlanid = 1;
		cb(macaddr, l2_lookup.vlanid, false, data);
			else
				continue;
		}
		cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
	}
	return 0;
}
+1 −12
Original line number Diff line number Diff line
@@ -77,7 +77,6 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port,
	info->phc_index = ptp_clock_index(priv->clock);
	return 0;
}
EXPORT_SYMBOL_GPL(sja1105_get_ts_info);

int sja1105et_ptp_cmd(const void *ctx, const void *data)
{
@@ -95,7 +94,6 @@ int sja1105et_ptp_cmd(const void *ctx, const void *data)
	return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control,
					   buf, SJA1105_SIZE_PTP_CMD);
}
EXPORT_SYMBOL_GPL(sja1105et_ptp_cmd);

int sja1105pqrs_ptp_cmd(const void *ctx, const void *data)
{
@@ -113,7 +111,6 @@ int sja1105pqrs_ptp_cmd(const void *ctx, const void *data)
	return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control,
					   buf, SJA1105_SIZE_PTP_CMD);
}
EXPORT_SYMBOL_GPL(sja1105pqrs_ptp_cmd);

/* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap
 * around in 0.135 seconds, and 32 bits for P/Q/R/S, wrapping around in 34.35
@@ -146,7 +143,6 @@ u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now,

	return ts_reconstructed;
}
EXPORT_SYMBOL_GPL(sja1105_tstamp_reconstruct);

/* Reads the SPI interface for an egress timestamp generated by the switch
 * for frames sent using management routes.
@@ -219,7 +215,6 @@ int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts)

	return 0;
}
EXPORT_SYMBOL_GPL(sja1105_ptpegr_ts_poll);

int sja1105_ptp_reset(struct sja1105_private *priv)
{
@@ -240,7 +235,6 @@ int sja1105_ptp_reset(struct sja1105_private *priv)

	return rc;
}
EXPORT_SYMBOL_GPL(sja1105_ptp_reset);

static int sja1105_ptp_gettime(struct ptp_clock_info *ptp,
			       struct timespec64 *ts)
@@ -387,18 +381,13 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv)

	return sja1105_ptp_reset(priv);
}
EXPORT_SYMBOL_GPL(sja1105_ptp_clock_register);

void sja1105_ptp_clock_unregister(struct sja1105_private *priv)
{
	if (IS_ERR_OR_NULL(priv->clock))
		return;

	cancel_delayed_work_sync(&priv->refresh_work);
	ptp_clock_unregister(priv->clock);
	priv->clock = NULL;
}
EXPORT_SYMBOL_GPL(sja1105_ptp_clock_unregister);

MODULE_AUTHOR("Vladimir Oltean <olteanv@gmail.com>");
MODULE_DESCRIPTION("SJA1105 PHC Driver");
MODULE_LICENSE("GPL v2");
+0 −2
Original line number Diff line number Diff line
@@ -100,7 +100,6 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv,

	return 0;
}
EXPORT_SYMBOL_GPL(sja1105_spi_send_packed_buf);

/* If @rw is:
 * - SPI_WRITE: creates and sends an SPI write message at absolute
@@ -136,7 +135,6 @@ int sja1105_spi_send_int(const struct sja1105_private *priv,

	return rc;
}
EXPORT_SYMBOL_GPL(sja1105_spi_send_int);

/* Should be used if a @packed_buf larger than SJA1105_SIZE_SPI_MSG_MAXLEN
 * must be sent/received. Splitting the buffer into chunks and assembling
Loading