diff options
| author | Egil Hjelmeland <privat@egil-hjelmeland.no> | 2017-12-07 13:56:04 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-12-08 14:12:33 -0500 |
| commit | 2e8d243e887c8802b373338ddff684aa0578be3b (patch) | |
| tree | a954e778e154c3c6fe325cc51c54e4c5c8cd96c0 | |
| parent | df45bf84e4f5a48f23d4b1a07d21d566e8b587b2 (diff) | |
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: Egil Hjelmeland <privat@egil-hjelmeland.no>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/dsa/lan9303-core.c | 14 | ||||
| -rw-r--r-- | include/linux/dsa/lan9303.h | 1 |
2 files changed, 13 insertions, 2 deletions
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index ea59dadefb33..c1b004fa64d9 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c | |||
| @@ -583,6 +583,7 @@ static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx) | |||
| 583 | { | 583 | { |
| 584 | int i; | 584 | int i; |
| 585 | 585 | ||
| 586 | mutex_lock(&chip->alr_mutex); | ||
| 586 | lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, | 587 | lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, |
| 587 | LAN9303_ALR_CMD_GET_FIRST); | 588 | LAN9303_ALR_CMD_GET_FIRST); |
| 588 | lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0); | 589 | 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 | LAN9303_ALR_CMD_GET_NEXT); | 607 | LAN9303_ALR_CMD_GET_NEXT); |
| 607 | lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0); | 608 | lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0); |
| 608 | } | 609 | } |
| 610 | mutex_unlock(&chip->alr_mutex); | ||
| 609 | } | 611 | } |
| 610 | 612 | ||
| 611 | static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6]) | 613 | 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 | { | 696 | { |
| 695 | struct lan9303_alr_cache_entry *entr; | 697 | struct lan9303_alr_cache_entry *entr; |
| 696 | 698 | ||
| 699 | mutex_lock(&chip->alr_mutex); | ||
| 697 | entr = lan9303_alr_cache_find_mac(chip, mac); | 700 | entr = lan9303_alr_cache_find_mac(chip, mac); |
| 698 | if (!entr) { /*New entry */ | 701 | if (!entr) { /*New entry */ |
| 699 | entr = lan9303_alr_cache_find_free(chip); | 702 | entr = lan9303_alr_cache_find_free(chip); |
| 700 | if (!entr) | 703 | if (!entr) { |
| 704 | mutex_unlock(&chip->alr_mutex); | ||
| 701 | return -ENOSPC; | 705 | return -ENOSPC; |
| 706 | } | ||
| 702 | ether_addr_copy(entr->mac_addr, mac); | 707 | ether_addr_copy(entr->mac_addr, mac); |
| 703 | } | 708 | } |
| 704 | entr->port_map |= BIT(port); | 709 | entr->port_map |= BIT(port); |
| 705 | entr->stp_override = stp_override; | 710 | entr->stp_override = stp_override; |
| 706 | lan9303_alr_set_entry(chip, mac, entr->port_map, stp_override); | 711 | lan9303_alr_set_entry(chip, mac, entr->port_map, stp_override); |
| 712 | mutex_unlock(&chip->alr_mutex); | ||
| 707 | 713 | ||
| 708 | return 0; | 714 | return 0; |
| 709 | } | 715 | } |
| @@ -713,15 +719,18 @@ static int lan9303_alr_del_port(struct lan9303 *chip, const u8 *mac, int port) | |||
| 713 | { | 719 | { |
| 714 | struct lan9303_alr_cache_entry *entr; | 720 | struct lan9303_alr_cache_entry *entr; |
| 715 | 721 | ||
| 722 | mutex_lock(&chip->alr_mutex); | ||
| 716 | entr = lan9303_alr_cache_find_mac(chip, mac); | 723 | entr = lan9303_alr_cache_find_mac(chip, mac); |
| 717 | if (!entr) | 724 | if (!entr) |
| 718 | return 0; /* no static entry found */ | 725 | goto out; /* no static entry found */ |
| 719 | 726 | ||
| 720 | entr->port_map &= ~BIT(port); | 727 | entr->port_map &= ~BIT(port); |
| 721 | if (entr->port_map == 0) /* zero means its free again */ | 728 | if (entr->port_map == 0) /* zero means its free again */ |
| 722 | eth_zero_addr(entr->mac_addr); | 729 | eth_zero_addr(entr->mac_addr); |
| 723 | lan9303_alr_set_entry(chip, mac, entr->port_map, entr->stp_override); | 730 | lan9303_alr_set_entry(chip, mac, entr->port_map, entr->stp_override); |
| 724 | 731 | ||
| 732 | out: | ||
| 733 | mutex_unlock(&chip->alr_mutex); | ||
| 725 | return 0; | 734 | return 0; |
| 726 | } | 735 | } |
| 727 | 736 | ||
| @@ -1323,6 +1332,7 @@ int lan9303_probe(struct lan9303 *chip, struct device_node *np) | |||
| 1323 | int ret; | 1332 | int ret; |
| 1324 | 1333 | ||
| 1325 | mutex_init(&chip->indirect_mutex); | 1334 | mutex_init(&chip->indirect_mutex); |
| 1335 | mutex_init(&chip->alr_mutex); | ||
| 1326 | 1336 | ||
| 1327 | lan9303_probe_reset_gpio(chip, np); | 1337 | lan9303_probe_reset_gpio(chip, np); |
| 1328 | 1338 | ||
diff --git a/include/linux/dsa/lan9303.h b/include/linux/dsa/lan9303.h index f48a85c377de..b6514c29563f 100644 --- a/include/linux/dsa/lan9303.h +++ b/include/linux/dsa/lan9303.h | |||
| @@ -26,6 +26,7 @@ struct lan9303 { | |||
| 26 | bool phy_addr_sel_strap; | 26 | bool phy_addr_sel_strap; |
| 27 | struct dsa_switch *ds; | 27 | struct dsa_switch *ds; |
| 28 | struct mutex indirect_mutex; /* protect indexed register access */ | 28 | struct mutex indirect_mutex; /* protect indexed register access */ |
| 29 | struct mutex alr_mutex; /* protect ALR access */ | ||
| 29 | const struct lan9303_phy_ops *ops; | 30 | const struct lan9303_phy_ops *ops; |
| 30 | bool is_bridged; /* true if port 1 and 2 are bridged */ | 31 | bool is_bridged; /* true if port 1 and 2 are bridged */ |
| 31 | 32 | ||
