diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-06-01 20:13:03 -0400 |
---|---|---|
committer | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-06-12 02:40:39 -0400 |
commit | bedfe3248efd070acd97d44d8c58cf82d7ebe7c4 (patch) | |
tree | 4c5733c282c9c4b57719307cf4d3b298b980339a /drivers/net/mv643xx_eth.c | |
parent | 12e4ab79cd828563dc090d2117dc8626b344bc8f (diff) |
mv643xx_eth: add PHY-less mode
On some boards, the mv643xx_eth MAC isn't connected to a PHY but
directly (via the MII/GMII/RGMII interface) to another MAC-layer
device. This patch allows specifying ->phy_addr = -1 to skip all
PHY-related initialisation and run-time poking in that case.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Acked-by: Dale Farnsworth <dale@farnsworth.org>
Diffstat (limited to 'drivers/net/mv643xx_eth.c')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 87 |
1 files changed, 74 insertions, 13 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 481a2c4ff0cd..a2b958ddf5f0 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -1110,6 +1110,22 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd * | |||
1110 | return err; | 1110 | return err; |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) | ||
1114 | { | ||
1115 | cmd->supported = SUPPORTED_MII; | ||
1116 | cmd->advertising = ADVERTISED_MII; | ||
1117 | cmd->speed = SPEED_1000; | ||
1118 | cmd->duplex = DUPLEX_FULL; | ||
1119 | cmd->port = PORT_MII; | ||
1120 | cmd->phy_address = 0; | ||
1121 | cmd->transceiver = XCVR_INTERNAL; | ||
1122 | cmd->autoneg = AUTONEG_DISABLE; | ||
1123 | cmd->maxtxpkt = 1; | ||
1124 | cmd->maxrxpkt = 1; | ||
1125 | |||
1126 | return 0; | ||
1127 | } | ||
1128 | |||
1113 | static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 1129 | static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
1114 | { | 1130 | { |
1115 | struct mv643xx_eth_private *mp = netdev_priv(dev); | 1131 | struct mv643xx_eth_private *mp = netdev_priv(dev); |
@@ -1127,6 +1143,11 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd * | |||
1127 | return err; | 1143 | return err; |
1128 | } | 1144 | } |
1129 | 1145 | ||
1146 | static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) | ||
1147 | { | ||
1148 | return -EINVAL; | ||
1149 | } | ||
1150 | |||
1130 | static void mv643xx_eth_get_drvinfo(struct net_device *dev, | 1151 | static void mv643xx_eth_get_drvinfo(struct net_device *dev, |
1131 | struct ethtool_drvinfo *drvinfo) | 1152 | struct ethtool_drvinfo *drvinfo) |
1132 | { | 1153 | { |
@@ -1144,6 +1165,11 @@ static int mv643xx_eth_nway_reset(struct net_device *dev) | |||
1144 | return mii_nway_restart(&mp->mii); | 1165 | return mii_nway_restart(&mp->mii); |
1145 | } | 1166 | } |
1146 | 1167 | ||
1168 | static int mv643xx_eth_nway_reset_phyless(struct net_device *dev) | ||
1169 | { | ||
1170 | return -EINVAL; | ||
1171 | } | ||
1172 | |||
1147 | static u32 mv643xx_eth_get_link(struct net_device *dev) | 1173 | static u32 mv643xx_eth_get_link(struct net_device *dev) |
1148 | { | 1174 | { |
1149 | struct mv643xx_eth_private *mp = netdev_priv(dev); | 1175 | struct mv643xx_eth_private *mp = netdev_priv(dev); |
@@ -1151,6 +1177,11 @@ static u32 mv643xx_eth_get_link(struct net_device *dev) | |||
1151 | return mii_link_ok(&mp->mii); | 1177 | return mii_link_ok(&mp->mii); |
1152 | } | 1178 | } |
1153 | 1179 | ||
1180 | static u32 mv643xx_eth_get_link_phyless(struct net_device *dev) | ||
1181 | { | ||
1182 | return 1; | ||
1183 | } | ||
1184 | |||
1154 | static void mv643xx_eth_get_strings(struct net_device *dev, | 1185 | static void mv643xx_eth_get_strings(struct net_device *dev, |
1155 | uint32_t stringset, uint8_t *data) | 1186 | uint32_t stringset, uint8_t *data) |
1156 | { | 1187 | { |
@@ -1210,6 +1241,18 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { | |||
1210 | .get_sset_count = mv643xx_eth_get_sset_count, | 1241 | .get_sset_count = mv643xx_eth_get_sset_count, |
1211 | }; | 1242 | }; |
1212 | 1243 | ||
1244 | static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { | ||
1245 | .get_settings = mv643xx_eth_get_settings_phyless, | ||
1246 | .set_settings = mv643xx_eth_set_settings_phyless, | ||
1247 | .get_drvinfo = mv643xx_eth_get_drvinfo, | ||
1248 | .nway_reset = mv643xx_eth_nway_reset_phyless, | ||
1249 | .get_link = mv643xx_eth_get_link_phyless, | ||
1250 | .set_sg = ethtool_op_set_sg, | ||
1251 | .get_strings = mv643xx_eth_get_strings, | ||
1252 | .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, | ||
1253 | .get_sset_count = mv643xx_eth_get_sset_count, | ||
1254 | }; | ||
1255 | |||
1213 | 1256 | ||
1214 | /* address handling *********************************************************/ | 1257 | /* address handling *********************************************************/ |
1215 | static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) | 1258 | static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) |
@@ -1656,12 +1699,16 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) | |||
1656 | } | 1699 | } |
1657 | 1700 | ||
1658 | if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { | 1701 | if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { |
1659 | if (mii_link_ok(&mp->mii)) { | 1702 | if (mp->phy_addr == -1 || mii_link_ok(&mp->mii)) { |
1660 | struct ethtool_cmd cmd; | ||
1661 | int i; | 1703 | int i; |
1662 | 1704 | ||
1663 | mii_ethtool_gset(&mp->mii, &cmd); | 1705 | if (mp->phy_addr != -1) { |
1664 | update_pscr(mp, cmd.speed, cmd.duplex); | 1706 | struct ethtool_cmd cmd; |
1707 | |||
1708 | mii_ethtool_gset(&mp->mii, &cmd); | ||
1709 | update_pscr(mp, cmd.speed, cmd.duplex); | ||
1710 | } | ||
1711 | |||
1665 | for (i = 0; i < 8; i++) | 1712 | for (i = 0; i < 8; i++) |
1666 | if (mp->txq_mask & (1 << i)) | 1713 | if (mp->txq_mask & (1 << i)) |
1667 | txq_enable(mp->txq + i); | 1714 | txq_enable(mp->txq + i); |
@@ -1751,7 +1798,6 @@ static void phy_reset(struct mv643xx_eth_private *mp) | |||
1751 | static void port_start(struct mv643xx_eth_private *mp) | 1798 | static void port_start(struct mv643xx_eth_private *mp) |
1752 | { | 1799 | { |
1753 | u32 pscr; | 1800 | u32 pscr; |
1754 | struct ethtool_cmd ethtool_cmd; | ||
1755 | int i; | 1801 | int i; |
1756 | 1802 | ||
1757 | /* | 1803 | /* |
@@ -1771,9 +1817,16 @@ static void port_start(struct mv643xx_eth_private *mp) | |||
1771 | 1817 | ||
1772 | wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); | 1818 | wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); |
1773 | 1819 | ||
1774 | mv643xx_eth_get_settings(mp->dev, ðtool_cmd); | 1820 | /* |
1775 | phy_reset(mp); | 1821 | * Perform PHY reset, if there is a PHY. |
1776 | mv643xx_eth_set_settings(mp->dev, ðtool_cmd); | 1822 | */ |
1823 | if (mp->phy_addr != -1) { | ||
1824 | struct ethtool_cmd cmd; | ||
1825 | |||
1826 | mv643xx_eth_get_settings(mp->dev, &cmd); | ||
1827 | phy_reset(mp); | ||
1828 | mv643xx_eth_set_settings(mp->dev, &cmd); | ||
1829 | } | ||
1777 | 1830 | ||
1778 | /* | 1831 | /* |
1779 | * Configure TX path and queues. | 1832 | * Configure TX path and queues. |
@@ -1990,7 +2043,10 @@ static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1990 | { | 2043 | { |
1991 | struct mv643xx_eth_private *mp = netdev_priv(dev); | 2044 | struct mv643xx_eth_private *mp = netdev_priv(dev); |
1992 | 2045 | ||
1993 | return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); | 2046 | if (mp->phy_addr != -1) |
2047 | return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); | ||
2048 | |||
2049 | return -EOPNOTSUPP; | ||
1994 | } | 2050 | } |
1995 | 2051 | ||
1996 | static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) | 2052 | static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) |
@@ -2387,10 +2443,15 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
2387 | mib_counters_clear(mp); | 2443 | mib_counters_clear(mp); |
2388 | INIT_WORK(&mp->tx_timeout_task, tx_timeout_task); | 2444 | INIT_WORK(&mp->tx_timeout_task, tx_timeout_task); |
2389 | 2445 | ||
2390 | err = phy_init(mp, pd); | 2446 | if (mp->phy_addr != -1) { |
2391 | if (err) | 2447 | err = phy_init(mp, pd); |
2392 | goto out; | 2448 | if (err) |
2393 | SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops); | 2449 | goto out; |
2450 | |||
2451 | SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops); | ||
2452 | } else { | ||
2453 | SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless); | ||
2454 | } | ||
2394 | 2455 | ||
2395 | 2456 | ||
2396 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 2457 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |