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

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
...@@ -583,6 +583,7 @@ static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -26,6 +26,7 @@ struct lan9303 { ...@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment