diff options
author | Andrew Lunn <andrew@lunn.ch> | 2015-05-05 19:09:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-09 16:05:53 -0400 |
commit | 3898c148589752687524ff552a498a8fb4c80667 (patch) | |
tree | 296718b00127e33e5e5c71c2b6523f63c998ffa5 /drivers/net/dsa | |
parent | 1441f4e59695682909bbbb7d5740c3fff326a4c3 (diff) |
net: dsa: mv88e6xxx: Replace PHY mutex by SMI mutex
The SMI bus is the bottleneck in all switch operations, not the
granularity of locks. Replace the PHY mutex by the SMI mutex to make
the locking concept simpler.
The REG_READ/REG_WRITE macros cannot be used while holding the SMI
mutex, since they try to acquire it. Replace with calls to the
appropriate function which does not try to get the mutex.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 121 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.h | 1 |
2 files changed, 63 insertions, 59 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index f38d8dfa934a..e974d26c1a03 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c | |||
@@ -199,20 +199,20 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) | |||
199 | return 0; | 199 | return 0; |
200 | } | 200 | } |
201 | 201 | ||
202 | /* Must be called with phy mutex held */ | 202 | /* Must be called with SMI mutex held */ |
203 | static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) | 203 | static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) |
204 | { | 204 | { |
205 | if (addr >= 0) | 205 | if (addr >= 0) |
206 | return mv88e6xxx_reg_read(ds, addr, regnum); | 206 | return _mv88e6xxx_reg_read(ds, addr, regnum); |
207 | return 0xffff; | 207 | return 0xffff; |
208 | } | 208 | } |
209 | 209 | ||
210 | /* Must be called with phy mutex held */ | 210 | /* Must be called with SMI mutex held */ |
211 | static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, | 211 | static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, |
212 | u16 val) | 212 | u16 val) |
213 | { | 213 | { |
214 | if (addr >= 0) | 214 | if (addr >= 0) |
215 | return mv88e6xxx_reg_write(ds, addr, regnum, val); | 215 | return _mv88e6xxx_reg_write(ds, addr, regnum, val); |
216 | return 0; | 216 | return 0; |
217 | } | 217 | } |
218 | 218 | ||
@@ -762,7 +762,7 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) | |||
762 | 762 | ||
763 | *temp = 0; | 763 | *temp = 0; |
764 | 764 | ||
765 | mutex_lock(&ps->phy_mutex); | 765 | mutex_lock(&ps->smi_mutex); |
766 | 766 | ||
767 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); | 767 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); |
768 | if (ret < 0) | 768 | if (ret < 0) |
@@ -795,19 +795,23 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) | |||
795 | 795 | ||
796 | error: | 796 | error: |
797 | _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); | 797 | _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); |
798 | mutex_unlock(&ps->phy_mutex); | 798 | mutex_unlock(&ps->smi_mutex); |
799 | return ret; | 799 | return ret; |
800 | } | 800 | } |
801 | #endif /* CONFIG_NET_DSA_HWMON */ | 801 | #endif /* CONFIG_NET_DSA_HWMON */ |
802 | 802 | ||
803 | static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) | 803 | /* Must be called with SMI lock held */ |
804 | static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, | ||
805 | u16 mask) | ||
804 | { | 806 | { |
805 | unsigned long timeout = jiffies + HZ / 10; | 807 | unsigned long timeout = jiffies + HZ / 10; |
806 | 808 | ||
807 | while (time_before(jiffies, timeout)) { | 809 | while (time_before(jiffies, timeout)) { |
808 | int ret; | 810 | int ret; |
809 | 811 | ||
810 | ret = REG_READ(reg, offset); | 812 | ret = _mv88e6xxx_reg_read(ds, reg, offset); |
813 | if (ret < 0) | ||
814 | return ret; | ||
811 | if (!(ret & mask)) | 815 | if (!(ret & mask)) |
812 | return 0; | 816 | return 0; |
813 | 817 | ||
@@ -816,10 +820,22 @@ static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) | |||
816 | return -ETIMEDOUT; | 820 | return -ETIMEDOUT; |
817 | } | 821 | } |
818 | 822 | ||
819 | int mv88e6xxx_phy_wait(struct dsa_switch *ds) | 823 | static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) |
824 | { | ||
825 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
826 | int ret; | ||
827 | |||
828 | mutex_lock(&ps->smi_mutex); | ||
829 | ret = _mv88e6xxx_wait(ds, reg, offset, mask); | ||
830 | mutex_unlock(&ps->smi_mutex); | ||
831 | |||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | static int _mv88e6xxx_phy_wait(struct dsa_switch *ds) | ||
820 | { | 836 | { |
821 | return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, | 837 | return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, |
822 | GLOBAL2_SMI_OP_BUSY); | 838 | GLOBAL2_SMI_OP_BUSY); |
823 | } | 839 | } |
824 | 840 | ||
825 | int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) | 841 | int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) |
@@ -835,56 +851,46 @@ int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds) | |||
835 | } | 851 | } |
836 | 852 | ||
837 | /* Must be called with SMI lock held */ | 853 | /* Must be called with SMI lock held */ |
838 | static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) | ||
839 | { | ||
840 | unsigned long timeout = jiffies + HZ / 10; | ||
841 | |||
842 | while (time_before(jiffies, timeout)) { | ||
843 | int ret; | ||
844 | |||
845 | ret = _mv88e6xxx_reg_read(ds, reg, offset); | ||
846 | if (ret < 0) | ||
847 | return ret; | ||
848 | if (!(ret & mask)) | ||
849 | return 0; | ||
850 | |||
851 | usleep_range(1000, 2000); | ||
852 | } | ||
853 | return -ETIMEDOUT; | ||
854 | } | ||
855 | |||
856 | /* Must be called with SMI lock held */ | ||
857 | static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) | 854 | static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) |
858 | { | 855 | { |
859 | return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP, | 856 | return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP, |
860 | GLOBAL_ATU_OP_BUSY); | 857 | GLOBAL_ATU_OP_BUSY); |
861 | } | 858 | } |
862 | 859 | ||
863 | /* Must be called with phy mutex held */ | 860 | /* Must be called with SMI mutex held */ |
864 | static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, | 861 | static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, |
865 | int regnum) | 862 | int regnum) |
866 | { | 863 | { |
867 | int ret; | 864 | int ret; |
868 | 865 | ||
869 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, | 866 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, |
870 | GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum); | 867 | GLOBAL2_SMI_OP_22_READ | (addr << 5) | |
868 | regnum); | ||
869 | if (ret < 0) | ||
870 | return ret; | ||
871 | 871 | ||
872 | ret = mv88e6xxx_phy_wait(ds); | 872 | ret = _mv88e6xxx_phy_wait(ds); |
873 | if (ret < 0) | 873 | if (ret < 0) |
874 | return ret; | 874 | return ret; |
875 | 875 | ||
876 | return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA); | 876 | return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA); |
877 | } | 877 | } |
878 | 878 | ||
879 | /* Must be called with phy mutex held */ | 879 | /* Must be called with SMI mutex held */ |
880 | static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, | 880 | static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, |
881 | int regnum, u16 val) | 881 | int regnum, u16 val) |
882 | { | 882 | { |
883 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val); | 883 | int ret; |
884 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, | 884 | |
885 | GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum); | 885 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val); |
886 | if (ret < 0) | ||
887 | return ret; | ||
886 | 888 | ||
887 | return mv88e6xxx_phy_wait(ds); | 889 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, |
890 | GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | | ||
891 | regnum); | ||
892 | |||
893 | return _mv88e6xxx_phy_wait(ds); | ||
888 | } | 894 | } |
889 | 895 | ||
890 | int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) | 896 | int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) |
@@ -892,7 +898,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) | |||
892 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 898 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
893 | int reg; | 899 | int reg; |
894 | 900 | ||
895 | mutex_lock(&ps->phy_mutex); | 901 | mutex_lock(&ps->smi_mutex); |
896 | 902 | ||
897 | reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); | 903 | reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); |
898 | if (reg < 0) | 904 | if (reg < 0) |
@@ -901,7 +907,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) | |||
901 | e->eee_enabled = !!(reg & 0x0200); | 907 | e->eee_enabled = !!(reg & 0x0200); |
902 | e->tx_lpi_enabled = !!(reg & 0x0100); | 908 | e->tx_lpi_enabled = !!(reg & 0x0100); |
903 | 909 | ||
904 | reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS); | 910 | reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS); |
905 | if (reg < 0) | 911 | if (reg < 0) |
906 | goto out; | 912 | goto out; |
907 | 913 | ||
@@ -909,7 +915,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) | |||
909 | reg = 0; | 915 | reg = 0; |
910 | 916 | ||
911 | out: | 917 | out: |
912 | mutex_unlock(&ps->phy_mutex); | 918 | mutex_unlock(&ps->smi_mutex); |
913 | return reg; | 919 | return reg; |
914 | } | 920 | } |
915 | 921 | ||
@@ -920,7 +926,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, | |||
920 | int reg; | 926 | int reg; |
921 | int ret; | 927 | int ret; |
922 | 928 | ||
923 | mutex_lock(&ps->phy_mutex); | 929 | mutex_lock(&ps->smi_mutex); |
924 | 930 | ||
925 | ret = _mv88e6xxx_phy_read_indirect(ds, port, 16); | 931 | ret = _mv88e6xxx_phy_read_indirect(ds, port, 16); |
926 | if (ret < 0) | 932 | if (ret < 0) |
@@ -934,7 +940,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, | |||
934 | 940 | ||
935 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg); | 941 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg); |
936 | out: | 942 | out: |
937 | mutex_unlock(&ps->phy_mutex); | 943 | mutex_unlock(&ps->smi_mutex); |
938 | 944 | ||
939 | return ret; | 945 | return ret; |
940 | } | 946 | } |
@@ -1568,7 +1574,6 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) | |||
1568 | 1574 | ||
1569 | mutex_init(&ps->smi_mutex); | 1575 | mutex_init(&ps->smi_mutex); |
1570 | mutex_init(&ps->stats_mutex); | 1576 | mutex_init(&ps->stats_mutex); |
1571 | mutex_init(&ps->phy_mutex); | ||
1572 | 1577 | ||
1573 | ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; | 1578 | ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; |
1574 | 1579 | ||
@@ -1722,14 +1727,14 @@ int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg) | |||
1722 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1727 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
1723 | int ret; | 1728 | int ret; |
1724 | 1729 | ||
1725 | mutex_lock(&ps->phy_mutex); | 1730 | mutex_lock(&ps->smi_mutex); |
1726 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); | 1731 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); |
1727 | if (ret < 0) | 1732 | if (ret < 0) |
1728 | goto error; | 1733 | goto error; |
1729 | ret = _mv88e6xxx_phy_read_indirect(ds, port, reg); | 1734 | ret = _mv88e6xxx_phy_read_indirect(ds, port, reg); |
1730 | error: | 1735 | error: |
1731 | _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); | 1736 | _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); |
1732 | mutex_unlock(&ps->phy_mutex); | 1737 | mutex_unlock(&ps->smi_mutex); |
1733 | return ret; | 1738 | return ret; |
1734 | } | 1739 | } |
1735 | 1740 | ||
@@ -1739,7 +1744,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, | |||
1739 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1744 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
1740 | int ret; | 1745 | int ret; |
1741 | 1746 | ||
1742 | mutex_lock(&ps->phy_mutex); | 1747 | mutex_lock(&ps->smi_mutex); |
1743 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); | 1748 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); |
1744 | if (ret < 0) | 1749 | if (ret < 0) |
1745 | goto error; | 1750 | goto error; |
@@ -1747,7 +1752,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, | |||
1747 | ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val); | 1752 | ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val); |
1748 | error: | 1753 | error: |
1749 | _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); | 1754 | _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); |
1750 | mutex_unlock(&ps->phy_mutex); | 1755 | mutex_unlock(&ps->smi_mutex); |
1751 | return ret; | 1756 | return ret; |
1752 | } | 1757 | } |
1753 | 1758 | ||
@@ -1770,9 +1775,9 @@ mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum) | |||
1770 | if (addr < 0) | 1775 | if (addr < 0) |
1771 | return addr; | 1776 | return addr; |
1772 | 1777 | ||
1773 | mutex_lock(&ps->phy_mutex); | 1778 | mutex_lock(&ps->smi_mutex); |
1774 | ret = _mv88e6xxx_phy_read(ds, addr, regnum); | 1779 | ret = _mv88e6xxx_phy_read(ds, addr, regnum); |
1775 | mutex_unlock(&ps->phy_mutex); | 1780 | mutex_unlock(&ps->smi_mutex); |
1776 | return ret; | 1781 | return ret; |
1777 | } | 1782 | } |
1778 | 1783 | ||
@@ -1786,9 +1791,9 @@ mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | |||
1786 | if (addr < 0) | 1791 | if (addr < 0) |
1787 | return addr; | 1792 | return addr; |
1788 | 1793 | ||
1789 | mutex_lock(&ps->phy_mutex); | 1794 | mutex_lock(&ps->smi_mutex); |
1790 | ret = _mv88e6xxx_phy_write(ds, addr, regnum, val); | 1795 | ret = _mv88e6xxx_phy_write(ds, addr, regnum, val); |
1791 | mutex_unlock(&ps->phy_mutex); | 1796 | mutex_unlock(&ps->smi_mutex); |
1792 | return ret; | 1797 | return ret; |
1793 | } | 1798 | } |
1794 | 1799 | ||
@@ -1802,9 +1807,9 @@ mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum) | |||
1802 | if (addr < 0) | 1807 | if (addr < 0) |
1803 | return addr; | 1808 | return addr; |
1804 | 1809 | ||
1805 | mutex_lock(&ps->phy_mutex); | 1810 | mutex_lock(&ps->smi_mutex); |
1806 | ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum); | 1811 | ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum); |
1807 | mutex_unlock(&ps->phy_mutex); | 1812 | mutex_unlock(&ps->smi_mutex); |
1808 | return ret; | 1813 | return ret; |
1809 | } | 1814 | } |
1810 | 1815 | ||
@@ -1819,9 +1824,9 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, | |||
1819 | if (addr < 0) | 1824 | if (addr < 0) |
1820 | return addr; | 1825 | return addr; |
1821 | 1826 | ||
1822 | mutex_lock(&ps->phy_mutex); | 1827 | mutex_lock(&ps->smi_mutex); |
1823 | ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); | 1828 | ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); |
1824 | mutex_unlock(&ps->phy_mutex); | 1829 | mutex_unlock(&ps->smi_mutex); |
1825 | return ret; | 1830 | return ret; |
1826 | } | 1831 | } |
1827 | 1832 | ||
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index aafcb1a0a616..e10ccdb4ffbc 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h | |||
@@ -377,7 +377,6 @@ int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); | |||
377 | void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, | 377 | void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, |
378 | struct ethtool_regs *regs, void *_p); | 378 | struct ethtool_regs *regs, void *_p); |
379 | int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp); | 379 | int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp); |
380 | int mv88e6xxx_phy_wait(struct dsa_switch *ds); | ||
381 | int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds); | 380 | int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds); |
382 | int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds); | 381 | int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds); |
383 | int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum); | 382 | int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum); |