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

Commit 2e8d243e authored by Egil Hjelmeland's avatar Egil Hjelmeland Committed by David S. Miller
Browse files

net: dsa: lan9303: Protect ALR operations with mutex



ALR table operations are a sequence of related register operations which
should be protected from concurrent access. The alr_cache should also be
protected. Add alr_mutex doing that.

Signed-off-by: default avatarEgil Hjelmeland <privat@egil-hjelmeland.no>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent df45bf84
Loading
Loading
Loading
Loading
+12 −2
Original line number Original line Diff line number Diff line
@@ -583,6 +583,7 @@ static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
{
{
	int i;
	int i;


	mutex_lock(&chip->alr_mutex);
	lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
	lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
				 LAN9303_ALR_CMD_GET_FIRST);
				 LAN9303_ALR_CMD_GET_FIRST);
	lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
	lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
@@ -606,6 +607,7 @@ static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
					 LAN9303_ALR_CMD_GET_NEXT);
					 LAN9303_ALR_CMD_GET_NEXT);
		lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
		lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
	}
	}
	mutex_unlock(&chip->alr_mutex);
}
}


static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6])
static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6])
@@ -694,16 +696,20 @@ static int lan9303_alr_add_port(struct lan9303 *chip, const u8 *mac, int port,
{
{
	struct lan9303_alr_cache_entry *entr;
	struct lan9303_alr_cache_entry *entr;


	mutex_lock(&chip->alr_mutex);
	entr = lan9303_alr_cache_find_mac(chip, mac);
	entr = lan9303_alr_cache_find_mac(chip, mac);
	if (!entr) { /*New entry */
	if (!entr) { /*New entry */
		entr = lan9303_alr_cache_find_free(chip);
		entr = lan9303_alr_cache_find_free(chip);
		if (!entr)
		if (!entr) {
			mutex_unlock(&chip->alr_mutex);
			return -ENOSPC;
			return -ENOSPC;
		}
		ether_addr_copy(entr->mac_addr, mac);
		ether_addr_copy(entr->mac_addr, mac);
	}
	}
	entr->port_map |= BIT(port);
	entr->port_map |= BIT(port);
	entr->stp_override = stp_override;
	entr->stp_override = stp_override;
	lan9303_alr_set_entry(chip, mac, entr->port_map, stp_override);
	lan9303_alr_set_entry(chip, mac, entr->port_map, stp_override);
	mutex_unlock(&chip->alr_mutex);


	return 0;
	return 0;
}
}
@@ -713,15 +719,18 @@ static int lan9303_alr_del_port(struct lan9303 *chip, const u8 *mac, int port)
{
{
	struct lan9303_alr_cache_entry *entr;
	struct lan9303_alr_cache_entry *entr;


	mutex_lock(&chip->alr_mutex);
	entr = lan9303_alr_cache_find_mac(chip, mac);
	entr = lan9303_alr_cache_find_mac(chip, mac);
	if (!entr)
	if (!entr)
		return 0;  /* no static entry found */
		goto out;  /* no static entry found */


	entr->port_map &= ~BIT(port);
	entr->port_map &= ~BIT(port);
	if (entr->port_map == 0) /* zero means its free again */
	if (entr->port_map == 0) /* zero means its free again */
		eth_zero_addr(entr->mac_addr);
		eth_zero_addr(entr->mac_addr);
	lan9303_alr_set_entry(chip, mac, entr->port_map, entr->stp_override);
	lan9303_alr_set_entry(chip, mac, entr->port_map, entr->stp_override);


out:
	mutex_unlock(&chip->alr_mutex);
	return 0;
	return 0;
}
}


@@ -1323,6 +1332,7 @@ int lan9303_probe(struct lan9303 *chip, struct device_node *np)
	int ret;
	int ret;


	mutex_init(&chip->indirect_mutex);
	mutex_init(&chip->indirect_mutex);
	mutex_init(&chip->alr_mutex);


	lan9303_probe_reset_gpio(chip, np);
	lan9303_probe_reset_gpio(chip, np);


+1 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ struct lan9303 {
	bool phy_addr_sel_strap;
	bool phy_addr_sel_strap;
	struct dsa_switch *ds;
	struct dsa_switch *ds;
	struct mutex indirect_mutex; /* protect indexed register access */
	struct mutex indirect_mutex; /* protect indexed register access */
	struct mutex alr_mutex; /* protect ALR access */
	const struct lan9303_phy_ops *ops;
	const struct lan9303_phy_ops *ops;
	bool is_bridged; /* true if port 1 and 2 are bridged */
	bool is_bridged; /* true if port 1 and 2 are bridged */