diff options
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 345 |
1 files changed, 238 insertions, 107 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 47fc58657890..75991eb761cf 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -1115,6 +1115,130 @@ static int link_status_10g_serdes(struct niu *np, int *link_up_p) | |||
1115 | return 0; | 1115 | return 0; |
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | static int link_status_mii(struct niu *np, int *link_up_p) | ||
1119 | { | ||
1120 | struct niu_link_config *lp = &np->link_config; | ||
1121 | int err; | ||
1122 | int bmsr, advert, ctrl1000, stat1000, lpa, bmcr, estatus; | ||
1123 | int supported, advertising, active_speed, active_duplex; | ||
1124 | |||
1125 | err = mii_read(np, np->phy_addr, MII_BMCR); | ||
1126 | if (unlikely(err < 0)) | ||
1127 | return err; | ||
1128 | bmcr = err; | ||
1129 | |||
1130 | err = mii_read(np, np->phy_addr, MII_BMSR); | ||
1131 | if (unlikely(err < 0)) | ||
1132 | return err; | ||
1133 | bmsr = err; | ||
1134 | |||
1135 | err = mii_read(np, np->phy_addr, MII_ADVERTISE); | ||
1136 | if (unlikely(err < 0)) | ||
1137 | return err; | ||
1138 | advert = err; | ||
1139 | |||
1140 | err = mii_read(np, np->phy_addr, MII_LPA); | ||
1141 | if (unlikely(err < 0)) | ||
1142 | return err; | ||
1143 | lpa = err; | ||
1144 | |||
1145 | if (likely(bmsr & BMSR_ESTATEN)) { | ||
1146 | err = mii_read(np, np->phy_addr, MII_ESTATUS); | ||
1147 | if (unlikely(err < 0)) | ||
1148 | return err; | ||
1149 | estatus = err; | ||
1150 | |||
1151 | err = mii_read(np, np->phy_addr, MII_CTRL1000); | ||
1152 | if (unlikely(err < 0)) | ||
1153 | return err; | ||
1154 | ctrl1000 = err; | ||
1155 | |||
1156 | err = mii_read(np, np->phy_addr, MII_STAT1000); | ||
1157 | if (unlikely(err < 0)) | ||
1158 | return err; | ||
1159 | stat1000 = err; | ||
1160 | } else | ||
1161 | estatus = ctrl1000 = stat1000 = 0; | ||
1162 | |||
1163 | supported = 0; | ||
1164 | if (bmsr & BMSR_ANEGCAPABLE) | ||
1165 | supported |= SUPPORTED_Autoneg; | ||
1166 | if (bmsr & BMSR_10HALF) | ||
1167 | supported |= SUPPORTED_10baseT_Half; | ||
1168 | if (bmsr & BMSR_10FULL) | ||
1169 | supported |= SUPPORTED_10baseT_Full; | ||
1170 | if (bmsr & BMSR_100HALF) | ||
1171 | supported |= SUPPORTED_100baseT_Half; | ||
1172 | if (bmsr & BMSR_100FULL) | ||
1173 | supported |= SUPPORTED_100baseT_Full; | ||
1174 | if (estatus & ESTATUS_1000_THALF) | ||
1175 | supported |= SUPPORTED_1000baseT_Half; | ||
1176 | if (estatus & ESTATUS_1000_TFULL) | ||
1177 | supported |= SUPPORTED_1000baseT_Full; | ||
1178 | lp->supported = supported; | ||
1179 | |||
1180 | advertising = 0; | ||
1181 | if (advert & ADVERTISE_10HALF) | ||
1182 | advertising |= ADVERTISED_10baseT_Half; | ||
1183 | if (advert & ADVERTISE_10FULL) | ||
1184 | advertising |= ADVERTISED_10baseT_Full; | ||
1185 | if (advert & ADVERTISE_100HALF) | ||
1186 | advertising |= ADVERTISED_100baseT_Half; | ||
1187 | if (advert & ADVERTISE_100FULL) | ||
1188 | advertising |= ADVERTISED_100baseT_Full; | ||
1189 | if (ctrl1000 & ADVERTISE_1000HALF) | ||
1190 | advertising |= ADVERTISED_1000baseT_Half; | ||
1191 | if (ctrl1000 & ADVERTISE_1000FULL) | ||
1192 | advertising |= ADVERTISED_1000baseT_Full; | ||
1193 | |||
1194 | if (bmcr & BMCR_ANENABLE) { | ||
1195 | int neg, neg1000; | ||
1196 | |||
1197 | lp->active_autoneg = 1; | ||
1198 | advertising |= ADVERTISED_Autoneg; | ||
1199 | |||
1200 | neg = advert & lpa; | ||
1201 | neg1000 = (ctrl1000 << 2) & stat1000; | ||
1202 | |||
1203 | if (neg1000 & (LPA_1000FULL | LPA_1000HALF)) | ||
1204 | active_speed = SPEED_1000; | ||
1205 | else if (neg & LPA_100) | ||
1206 | active_speed = SPEED_100; | ||
1207 | else if (neg & (LPA_10HALF | LPA_10FULL)) | ||
1208 | active_speed = SPEED_10; | ||
1209 | else | ||
1210 | active_speed = SPEED_INVALID; | ||
1211 | |||
1212 | if ((neg1000 & LPA_1000FULL) || (neg & LPA_DUPLEX)) | ||
1213 | active_duplex = DUPLEX_FULL; | ||
1214 | else if (active_speed != SPEED_INVALID) | ||
1215 | active_duplex = DUPLEX_HALF; | ||
1216 | else | ||
1217 | active_duplex = DUPLEX_INVALID; | ||
1218 | } else { | ||
1219 | lp->active_autoneg = 0; | ||
1220 | |||
1221 | if ((bmcr & BMCR_SPEED1000) && !(bmcr & BMCR_SPEED100)) | ||
1222 | active_speed = SPEED_1000; | ||
1223 | else if (bmcr & BMCR_SPEED100) | ||
1224 | active_speed = SPEED_100; | ||
1225 | else | ||
1226 | active_speed = SPEED_10; | ||
1227 | |||
1228 | if (bmcr & BMCR_FULLDPLX) | ||
1229 | active_duplex = DUPLEX_FULL; | ||
1230 | else | ||
1231 | active_duplex = DUPLEX_HALF; | ||
1232 | } | ||
1233 | |||
1234 | lp->active_advertising = advertising; | ||
1235 | lp->active_speed = active_speed; | ||
1236 | lp->active_duplex = active_duplex; | ||
1237 | *link_up_p = !!(bmsr & BMSR_LSTATUS); | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1118 | static int link_status_1g_rgmii(struct niu *np, int *link_up_p) | 1242 | static int link_status_1g_rgmii(struct niu *np, int *link_up_p) |
1119 | { | 1243 | { |
1120 | struct niu_link_config *lp = &np->link_config; | 1244 | struct niu_link_config *lp = &np->link_config; |
@@ -1171,6 +1295,22 @@ out: | |||
1171 | return err; | 1295 | return err; |
1172 | } | 1296 | } |
1173 | 1297 | ||
1298 | static int link_status_1g(struct niu *np, int *link_up_p) | ||
1299 | { | ||
1300 | struct niu_link_config *lp = &np->link_config; | ||
1301 | unsigned long flags; | ||
1302 | int err; | ||
1303 | |||
1304 | spin_lock_irqsave(&np->lock, flags); | ||
1305 | |||
1306 | err = link_status_mii(np, link_up_p); | ||
1307 | lp->supported |= SUPPORTED_TP; | ||
1308 | lp->active_advertising |= ADVERTISED_TP; | ||
1309 | |||
1310 | spin_unlock_irqrestore(&np->lock, flags); | ||
1311 | return err; | ||
1312 | } | ||
1313 | |||
1174 | static int bcm8704_reset(struct niu *np) | 1314 | static int bcm8704_reset(struct niu *np) |
1175 | { | 1315 | { |
1176 | int err, limit; | 1316 | int err, limit; |
@@ -1676,39 +1816,88 @@ static int mii_init_common(struct niu *np) | |||
1676 | return err; | 1816 | return err; |
1677 | } | 1817 | } |
1678 | 1818 | ||
1679 | /* XXX configurable XXX */ | 1819 | if (lp->autoneg) { |
1680 | /* XXX for now don't advertise half-duplex or asym pause... XXX */ | 1820 | u16 ctrl1000; |
1681 | adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; | 1821 | |
1682 | if (bmsr & BMSR_10FULL) | 1822 | adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; |
1683 | adv |= ADVERTISE_10FULL; | 1823 | if ((bmsr & BMSR_10HALF) && |
1684 | if (bmsr & BMSR_100FULL) | 1824 | (lp->advertising & ADVERTISED_10baseT_Half)) |
1685 | adv |= ADVERTISE_100FULL; | 1825 | adv |= ADVERTISE_10HALF; |
1686 | err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv); | 1826 | if ((bmsr & BMSR_10FULL) && |
1687 | if (err) | 1827 | (lp->advertising & ADVERTISED_10baseT_Full)) |
1688 | return err; | 1828 | adv |= ADVERTISE_10FULL; |
1689 | 1829 | if ((bmsr & BMSR_100HALF) && | |
1690 | if (bmsr & BMSR_ESTATEN) { | 1830 | (lp->advertising & ADVERTISED_100baseT_Half)) |
1691 | u16 ctrl1000 = 0; | 1831 | adv |= ADVERTISE_100HALF; |
1692 | 1832 | if ((bmsr & BMSR_100FULL) && | |
1693 | if (estat & ESTATUS_1000_TFULL) | 1833 | (lp->advertising & ADVERTISED_100baseT_Full)) |
1694 | ctrl1000 |= ADVERTISE_1000FULL; | 1834 | adv |= ADVERTISE_100FULL; |
1695 | err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000); | 1835 | err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv); |
1696 | if (err) | 1836 | if (err) |
1697 | return err; | 1837 | return err; |
1838 | |||
1839 | if (likely(bmsr & BMSR_ESTATEN)) { | ||
1840 | ctrl1000 = 0; | ||
1841 | if ((estat & ESTATUS_1000_THALF) && | ||
1842 | (lp->advertising & ADVERTISED_1000baseT_Half)) | ||
1843 | ctrl1000 |= ADVERTISE_1000HALF; | ||
1844 | if ((estat & ESTATUS_1000_TFULL) && | ||
1845 | (lp->advertising & ADVERTISED_1000baseT_Full)) | ||
1846 | ctrl1000 |= ADVERTISE_1000FULL; | ||
1847 | err = mii_write(np, np->phy_addr, | ||
1848 | MII_CTRL1000, ctrl1000); | ||
1849 | if (err) | ||
1850 | return err; | ||
1851 | } | ||
1852 | |||
1853 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
1854 | } else { | ||
1855 | /* !lp->autoneg */ | ||
1856 | int fulldpx; | ||
1857 | |||
1858 | if (lp->duplex == DUPLEX_FULL) { | ||
1859 | bmcr |= BMCR_FULLDPLX; | ||
1860 | fulldpx = 1; | ||
1861 | } else if (lp->duplex == DUPLEX_HALF) | ||
1862 | fulldpx = 0; | ||
1863 | else | ||
1864 | return -EINVAL; | ||
1865 | |||
1866 | if (lp->speed == SPEED_1000) { | ||
1867 | /* if X-full requested while not supported, or | ||
1868 | X-half requested while not supported... */ | ||
1869 | if ((fulldpx && !(estat & ESTATUS_1000_TFULL)) || | ||
1870 | (!fulldpx && !(estat & ESTATUS_1000_THALF))) | ||
1871 | return -EINVAL; | ||
1872 | bmcr |= BMCR_SPEED1000; | ||
1873 | } else if (lp->speed == SPEED_100) { | ||
1874 | if ((fulldpx && !(bmsr & BMSR_100FULL)) || | ||
1875 | (!fulldpx && !(bmsr & BMSR_100HALF))) | ||
1876 | return -EINVAL; | ||
1877 | bmcr |= BMCR_SPEED100; | ||
1878 | } else if (lp->speed == SPEED_10) { | ||
1879 | if ((fulldpx && !(bmsr & BMSR_10FULL)) || | ||
1880 | (!fulldpx && !(bmsr & BMSR_10HALF))) | ||
1881 | return -EINVAL; | ||
1882 | } else | ||
1883 | return -EINVAL; | ||
1698 | } | 1884 | } |
1699 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
1700 | 1885 | ||
1701 | err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); | 1886 | err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); |
1702 | if (err) | 1887 | if (err) |
1703 | return err; | 1888 | return err; |
1704 | 1889 | ||
1890 | #if 0 | ||
1705 | err = mii_read(np, np->phy_addr, MII_BMCR); | 1891 | err = mii_read(np, np->phy_addr, MII_BMCR); |
1706 | if (err < 0) | 1892 | if (err < 0) |
1707 | return err; | 1893 | return err; |
1894 | bmcr = err; | ||
1895 | |||
1708 | err = mii_read(np, np->phy_addr, MII_BMSR); | 1896 | err = mii_read(np, np->phy_addr, MII_BMSR); |
1709 | if (err < 0) | 1897 | if (err < 0) |
1710 | return err; | 1898 | return err; |
1711 | #if 0 | 1899 | bmsr = err; |
1900 | |||
1712 | pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n", | 1901 | pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n", |
1713 | np->port, bmcr, bmsr); | 1902 | np->port, bmcr, bmsr); |
1714 | #endif | 1903 | #endif |
@@ -2054,87 +2243,6 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) | |||
2054 | return err; | 2243 | return err; |
2055 | } | 2244 | } |
2056 | 2245 | ||
2057 | static int link_status_1g(struct niu *np, int *link_up_p) | ||
2058 | { | ||
2059 | struct niu_link_config *lp = &np->link_config; | ||
2060 | u16 current_speed, bmsr; | ||
2061 | unsigned long flags; | ||
2062 | u8 current_duplex; | ||
2063 | int err, link_up; | ||
2064 | |||
2065 | link_up = 0; | ||
2066 | current_speed = SPEED_INVALID; | ||
2067 | current_duplex = DUPLEX_INVALID; | ||
2068 | |||
2069 | spin_lock_irqsave(&np->lock, flags); | ||
2070 | |||
2071 | err = -EINVAL; | ||
2072 | if (np->link_config.loopback_mode != LOOPBACK_DISABLED) | ||
2073 | goto out; | ||
2074 | |||
2075 | err = mii_read(np, np->phy_addr, MII_BMSR); | ||
2076 | if (err < 0) | ||
2077 | goto out; | ||
2078 | |||
2079 | bmsr = err; | ||
2080 | if (bmsr & BMSR_LSTATUS) { | ||
2081 | u16 adv, lpa, common, estat; | ||
2082 | |||
2083 | err = mii_read(np, np->phy_addr, MII_ADVERTISE); | ||
2084 | if (err < 0) | ||
2085 | goto out; | ||
2086 | adv = err; | ||
2087 | |||
2088 | err = mii_read(np, np->phy_addr, MII_LPA); | ||
2089 | if (err < 0) | ||
2090 | goto out; | ||
2091 | lpa = err; | ||
2092 | |||
2093 | common = adv & lpa; | ||
2094 | |||
2095 | err = mii_read(np, np->phy_addr, MII_ESTATUS); | ||
2096 | if (err < 0) | ||
2097 | goto out; | ||
2098 | estat = err; | ||
2099 | |||
2100 | link_up = 1; | ||
2101 | if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) { | ||
2102 | current_speed = SPEED_1000; | ||
2103 | if (estat & ESTATUS_1000_TFULL) | ||
2104 | current_duplex = DUPLEX_FULL; | ||
2105 | else | ||
2106 | current_duplex = DUPLEX_HALF; | ||
2107 | } else { | ||
2108 | if (common & ADVERTISE_100BASE4) { | ||
2109 | current_speed = SPEED_100; | ||
2110 | current_duplex = DUPLEX_HALF; | ||
2111 | } else if (common & ADVERTISE_100FULL) { | ||
2112 | current_speed = SPEED_100; | ||
2113 | current_duplex = DUPLEX_FULL; | ||
2114 | } else if (common & ADVERTISE_100HALF) { | ||
2115 | current_speed = SPEED_100; | ||
2116 | current_duplex = DUPLEX_HALF; | ||
2117 | } else if (common & ADVERTISE_10FULL) { | ||
2118 | current_speed = SPEED_10; | ||
2119 | current_duplex = DUPLEX_FULL; | ||
2120 | } else if (common & ADVERTISE_10HALF) { | ||
2121 | current_speed = SPEED_10; | ||
2122 | current_duplex = DUPLEX_HALF; | ||
2123 | } else | ||
2124 | link_up = 0; | ||
2125 | } | ||
2126 | } | ||
2127 | lp->active_speed = current_speed; | ||
2128 | lp->active_duplex = current_duplex; | ||
2129 | err = 0; | ||
2130 | |||
2131 | out: | ||
2132 | spin_unlock_irqrestore(&np->lock, flags); | ||
2133 | |||
2134 | *link_up_p = link_up; | ||
2135 | return err; | ||
2136 | } | ||
2137 | |||
2138 | static int niu_link_status(struct niu *np, int *link_up_p) | 2246 | static int niu_link_status(struct niu *np, int *link_up_p) |
2139 | { | 2247 | { |
2140 | const struct niu_phy_ops *ops = np->phy_ops; | 2248 | const struct niu_phy_ops *ops = np->phy_ops; |
@@ -5212,10 +5320,10 @@ static void niu_init_xif_xmac(struct niu *np) | |||
5212 | if (np->flags & NIU_FLAGS_10G) { | 5320 | if (np->flags & NIU_FLAGS_10G) { |
5213 | val |= XMAC_CONFIG_MODE_XGMII; | 5321 | val |= XMAC_CONFIG_MODE_XGMII; |
5214 | } else { | 5322 | } else { |
5215 | if (lp->active_speed == SPEED_100) | 5323 | if (lp->active_speed == SPEED_1000) |
5216 | val |= XMAC_CONFIG_MODE_MII; | ||
5217 | else | ||
5218 | val |= XMAC_CONFIG_MODE_GMII; | 5324 | val |= XMAC_CONFIG_MODE_GMII; |
5325 | else | ||
5326 | val |= XMAC_CONFIG_MODE_MII; | ||
5219 | } | 5327 | } |
5220 | 5328 | ||
5221 | nw64_mac(XMAC_CONFIG, val); | 5329 | nw64_mac(XMAC_CONFIG, val); |
@@ -6703,17 +6811,27 @@ static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
6703 | memset(cmd, 0, sizeof(*cmd)); | 6811 | memset(cmd, 0, sizeof(*cmd)); |
6704 | cmd->phy_address = np->phy_addr; | 6812 | cmd->phy_address = np->phy_addr; |
6705 | cmd->supported = lp->supported; | 6813 | cmd->supported = lp->supported; |
6706 | cmd->advertising = lp->advertising; | 6814 | cmd->advertising = lp->active_advertising; |
6707 | cmd->autoneg = lp->autoneg; | 6815 | cmd->autoneg = lp->active_autoneg; |
6708 | cmd->speed = lp->active_speed; | 6816 | cmd->speed = lp->active_speed; |
6709 | cmd->duplex = lp->active_duplex; | 6817 | cmd->duplex = lp->active_duplex; |
6818 | cmd->port = (np->flags & NIU_FLAGS_FIBER) ? PORT_FIBRE : PORT_TP; | ||
6819 | cmd->transceiver = (np->flags & NIU_FLAGS_XCVR_SERDES) ? | ||
6820 | XCVR_EXTERNAL : XCVR_INTERNAL; | ||
6710 | 6821 | ||
6711 | return 0; | 6822 | return 0; |
6712 | } | 6823 | } |
6713 | 6824 | ||
6714 | static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 6825 | static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
6715 | { | 6826 | { |
6716 | return -EINVAL; | 6827 | struct niu *np = netdev_priv(dev); |
6828 | struct niu_link_config *lp = &np->link_config; | ||
6829 | |||
6830 | lp->advertising = cmd->advertising; | ||
6831 | lp->speed = cmd->speed; | ||
6832 | lp->duplex = cmd->duplex; | ||
6833 | lp->autoneg = cmd->autoneg; | ||
6834 | return niu_init_link(np); | ||
6717 | } | 6835 | } |
6718 | 6836 | ||
6719 | static u32 niu_get_msglevel(struct net_device *dev) | 6837 | static u32 niu_get_msglevel(struct net_device *dev) |
@@ -6728,6 +6846,16 @@ static void niu_set_msglevel(struct net_device *dev, u32 value) | |||
6728 | np->msg_enable = value; | 6846 | np->msg_enable = value; |
6729 | } | 6847 | } |
6730 | 6848 | ||
6849 | static int niu_nway_reset(struct net_device *dev) | ||
6850 | { | ||
6851 | struct niu *np = netdev_priv(dev); | ||
6852 | |||
6853 | if (np->link_config.autoneg) | ||
6854 | return niu_init_link(np); | ||
6855 | |||
6856 | return 0; | ||
6857 | } | ||
6858 | |||
6731 | static int niu_get_eeprom_len(struct net_device *dev) | 6859 | static int niu_get_eeprom_len(struct net_device *dev) |
6732 | { | 6860 | { |
6733 | struct niu *np = netdev_priv(dev); | 6861 | struct niu *np = netdev_priv(dev); |
@@ -7159,6 +7287,7 @@ static const struct ethtool_ops niu_ethtool_ops = { | |||
7159 | .get_link = ethtool_op_get_link, | 7287 | .get_link = ethtool_op_get_link, |
7160 | .get_msglevel = niu_get_msglevel, | 7288 | .get_msglevel = niu_get_msglevel, |
7161 | .set_msglevel = niu_set_msglevel, | 7289 | .set_msglevel = niu_set_msglevel, |
7290 | .nway_reset = niu_nway_reset, | ||
7162 | .get_eeprom_len = niu_get_eeprom_len, | 7291 | .get_eeprom_len = niu_get_eeprom_len, |
7163 | .get_eeprom = niu_get_eeprom, | 7292 | .get_eeprom = niu_get_eeprom, |
7164 | .get_settings = niu_get_settings, | 7293 | .get_settings = niu_get_settings, |
@@ -8258,7 +8387,9 @@ static void __devinit niu_link_config_init(struct niu *np) | |||
8258 | ADVERTISED_10000baseT_Full | | 8387 | ADVERTISED_10000baseT_Full | |
8259 | ADVERTISED_Autoneg); | 8388 | ADVERTISED_Autoneg); |
8260 | lp->speed = lp->active_speed = SPEED_INVALID; | 8389 | lp->speed = lp->active_speed = SPEED_INVALID; |
8261 | lp->duplex = lp->active_duplex = DUPLEX_INVALID; | 8390 | lp->duplex = DUPLEX_FULL; |
8391 | lp->active_duplex = DUPLEX_INVALID; | ||
8392 | lp->autoneg = 1; | ||
8262 | #if 0 | 8393 | #if 0 |
8263 | lp->loopback_mode = LOOPBACK_MAC; | 8394 | lp->loopback_mode = LOOPBACK_MAC; |
8264 | lp->active_speed = SPEED_10000; | 8395 | lp->active_speed = SPEED_10000; |