aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorConstantin Baranov <baranov@mercdev.com>2009-02-18 20:53:20 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-18 20:53:20 -0500
commit38bb045d493cc166920834087acd934dedc1b5d5 (patch)
tree361c59343742e3743d40a09129a90d73581bdcb4 /drivers/net
parente0d8496a66de9eca13a88d93a5642db47e5a2b60 (diff)
niu: improve ethtool support for gigabit copper cards
Introduced support for link speed and duplex setting (ethtool -s), link advertising parameters and autonegotiation (ethtool -r): - struct niu_link_config: split advertising and autoneg fields into active and target values (similar to speed and duplex fields) - mii_init_common(): rewrite function to actually apply requested niu_link_config parameters instead of providing default initialization - link_status_1g(): move parsing of MII registers into new link_status_mii() function (link_status_1g_rgmii() could possibly use this new implementation too) - introduce simple nway_reset method - fix incorrect XMAC_CONFIG_MODE selection for 10Mbps case Signed-off-by: Constantin Baranov <baranov@mercdev.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/niu.c345
-rw-r--r--drivers/net/niu.h5
2 files changed, 242 insertions, 108 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
1118static 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
1118static int link_status_1g_rgmii(struct niu *np, int *link_up_p) 1242static 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
1298static 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
1174static int bcm8704_reset(struct niu *np) 1314static 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
2057static 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
2131out:
2132 spin_unlock_irqrestore(&np->lock, flags);
2133
2134 *link_up_p = link_up;
2135 return err;
2136}
2137
2138static int niu_link_status(struct niu *np, int *link_up_p) 2246static 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
6714static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 6825static 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
6719static u32 niu_get_msglevel(struct net_device *dev) 6837static 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
6849static 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
6731static int niu_get_eeprom_len(struct net_device *dev) 6859static 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;
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index e1a7392e8d70..5a002375b35b 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -3131,16 +3131,19 @@ struct niu_ops {
3131}; 3131};
3132 3132
3133struct niu_link_config { 3133struct niu_link_config {
3134 u32 supported;
3135
3134 /* Describes what we're trying to get. */ 3136 /* Describes what we're trying to get. */
3135 u32 advertising; 3137 u32 advertising;
3136 u32 supported;
3137 u16 speed; 3138 u16 speed;
3138 u8 duplex; 3139 u8 duplex;
3139 u8 autoneg; 3140 u8 autoneg;
3140 3141
3141 /* Describes what we actually have. */ 3142 /* Describes what we actually have. */
3143 u32 active_advertising;
3142 u16 active_speed; 3144 u16 active_speed;
3143 u8 active_duplex; 3145 u8 active_duplex;
3146 u8 active_autoneg;
3144#define SPEED_INVALID 0xffff 3147#define SPEED_INVALID 0xffff
3145#define DUPLEX_INVALID 0xff 3148#define DUPLEX_INVALID 0xff
3146#define AUTONEG_INVALID 0xff 3149#define AUTONEG_INVALID 0xff