aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2008-07-14 08:29:40 -0400
committerLennert Buytenhek <buytenh@marvell.com>2008-07-24 00:22:59 -0400
commit81600eea98789da09a32de69ca9d3be8b9503c54 (patch)
treeba607eed9bfff70d4f40c3b25baf1bc83ea90024
parent7dde154d3d0d9701ecfb5533017a8f1a20bb4214 (diff)
mv643xx_eth: use auto phy polling for configuring (R)(G)MII interface
The mv643xx_eth hardware has a provision for polling the PHY's MII management registers to obtain the (R)(G)MII interface speed (10/100/1000) and duplex (half/full) and pause (off/symmetric) settings to use to talk to the PHY. The driver currently does not make use of this feature. Instead, whenever there is a link status change event, it reads the current link parameters from the PHY, and programs those parameters into the mv643xx_eth MAC by hand. This patch switches the mv643xx_eth driver to letting the MAC auto-determine the (R)(G)MII link parameters by PHY polling, if there is a PHY present. For PHYless ports (when e.g. the (R)(G)MII interface is connected to a hardware switch), we keep hardcoding the MII interface parameters. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
-rw-r--r--arch/arm/mach-kirkwood/rd88f6281-setup.c3
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c3
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c3
-rw-r--r--arch/arm/mach-orion5x/wnr854t-setup.c3
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c3
-rw-r--r--drivers/net/mv643xx_eth.c140
6 files changed, 81 insertions, 74 deletions
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index e1f8de2c74a2..b6437f47a77f 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -18,6 +18,7 @@
18#include <linux/timer.h> 18#include <linux/timer.h>
19#include <linux/ata_platform.h> 19#include <linux/ata_platform.h>
20#include <linux/mv643xx_eth.h> 20#include <linux/mv643xx_eth.h>
21#include <linux/ethtool.h>
21#include <asm/mach-types.h> 22#include <asm/mach-types.h>
22#include <asm/mach/arch.h> 23#include <asm/mach/arch.h>
23#include <asm/mach/pci.h> 24#include <asm/mach/pci.h>
@@ -69,6 +70,8 @@ static struct platform_device rd88f6281_nand_flash = {
69 70
70static struct mv643xx_eth_platform_data rd88f6281_ge00_data = { 71static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
71 .phy_addr = -1, 72 .phy_addr = -1,
73 .speed = SPEED_1000,
74 .duplex = DUPLEX_FULL,
72}; 75};
73 76
74static struct mv_sata_platform_data rd88f6281_sata_data = { 77static struct mv_sata_platform_data rd88f6281_sata_data = {
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index d50e3650a09e..73e9242da7ad 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -15,6 +15,7 @@
15#include <linux/irq.h> 15#include <linux/irq.h>
16#include <linux/mtd/physmap.h> 16#include <linux/mtd/physmap.h>
17#include <linux/mv643xx_eth.h> 17#include <linux/mv643xx_eth.h>
18#include <linux/ethtool.h>
18#include <asm/mach-types.h> 19#include <asm/mach-types.h>
19#include <asm/gpio.h> 20#include <asm/gpio.h>
20#include <asm/leds.h> 21#include <asm/leds.h>
@@ -88,6 +89,8 @@ static struct orion5x_mpp_mode rd88f5181l_fxo_mpp_modes[] __initdata = {
88 89
89static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = { 90static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
90 .phy_addr = -1, 91 .phy_addr = -1,
92 .speed = SPEED_1000,
93 .duplex = DUPLEX_FULL,
91}; 94};
92 95
93static void __init rd88f5181l_fxo_init(void) 96static void __init rd88f5181l_fxo_init(void)
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index b56447d32e17..ac482019abbf 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -15,6 +15,7 @@
15#include <linux/irq.h> 15#include <linux/irq.h>
16#include <linux/mtd/physmap.h> 16#include <linux/mtd/physmap.h>
17#include <linux/mv643xx_eth.h> 17#include <linux/mv643xx_eth.h>
18#include <linux/ethtool.h>
18#include <linux/i2c.h> 19#include <linux/i2c.h>
19#include <asm/mach-types.h> 20#include <asm/mach-types.h>
20#include <asm/gpio.h> 21#include <asm/gpio.h>
@@ -89,6 +90,8 @@ static struct orion5x_mpp_mode rd88f5181l_ge_mpp_modes[] __initdata = {
89 90
90static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = { 91static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
91 .phy_addr = -1, 92 .phy_addr = -1,
93 .speed = SPEED_1000,
94 .duplex = DUPLEX_FULL,
92}; 95};
93 96
94static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = { 97static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = {
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 1af093ff8cf3..25568c2a3d29 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -14,6 +14,7 @@
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <linux/mtd/physmap.h> 15#include <linux/mtd/physmap.h>
16#include <linux/mv643xx_eth.h> 16#include <linux/mv643xx_eth.h>
17#include <linux/ethtool.h>
17#include <asm/mach-types.h> 18#include <asm/mach-types.h>
18#include <asm/gpio.h> 19#include <asm/gpio.h>
19#include <asm/mach/arch.h> 20#include <asm/mach/arch.h>
@@ -92,6 +93,8 @@ static struct platform_device wnr854t_nor_flash = {
92 93
93static struct mv643xx_eth_platform_data wnr854t_eth_data = { 94static struct mv643xx_eth_platform_data wnr854t_eth_data = {
94 .phy_addr = -1, 95 .phy_addr = -1,
96 .speed = SPEED_1000,
97 .duplex = DUPLEX_FULL,
95}; 98};
96 99
97static void __init wnr854t_init(void) 100static void __init wnr854t_init(void)
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index aeab55c6a82d..9b8ee8c48bf0 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -14,6 +14,7 @@
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <linux/mtd/physmap.h> 15#include <linux/mtd/physmap.h>
16#include <linux/mv643xx_eth.h> 16#include <linux/mv643xx_eth.h>
17#include <linux/ethtool.h>
17#include <asm/mach-types.h> 18#include <asm/mach-types.h>
18#include <asm/gpio.h> 19#include <asm/gpio.h>
19#include <asm/mach/arch.h> 20#include <asm/mach/arch.h>
@@ -100,6 +101,8 @@ static struct platform_device wrt350n_v2_nor_flash = {
100 101
101static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = { 102static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
102 .phy_addr = -1, 103 .phy_addr = -1,
104 .speed = SPEED_1000,
105 .duplex = DUPLEX_FULL,
103}; 106};
104 107
105static void __init wrt350n_v2_init(void) 108static void __init wrt350n_v2_init(void)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 006ad45ddb84..29d4fe37cd50 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -91,6 +91,7 @@ static char mv643xx_eth_driver_version[] = "1.1";
91#define PORT_STATUS(p) (0x0444 + ((p) << 10)) 91#define PORT_STATUS(p) (0x0444 + ((p) << 10))
92#define TX_FIFO_EMPTY 0x00000400 92#define TX_FIFO_EMPTY 0x00000400
93#define TX_IN_PROGRESS 0x00000080 93#define TX_IN_PROGRESS 0x00000080
94#define LINK_UP 0x00000002
94#define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) 95#define TXQ_COMMAND(p) (0x0448 + ((p) << 10))
95#define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) 96#define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10))
96#define TX_BW_RATE(p) (0x0450 + ((p) << 10)) 97#define TX_BW_RATE(p) (0x0450 + ((p) << 10))
@@ -156,7 +157,6 @@ static char mv643xx_eth_driver_version[] = "1.1";
156#define SET_GMII_SPEED_TO_1000 (1 << 23) 157#define SET_GMII_SPEED_TO_1000 (1 << 23)
157#define SET_FULL_DUPLEX_MODE (1 << 21) 158#define SET_FULL_DUPLEX_MODE (1 << 21)
158#define MAX_RX_PACKET_9700BYTE (5 << 17) 159#define MAX_RX_PACKET_9700BYTE (5 << 17)
159#define MAX_RX_PACKET_MASK (7 << 17)
160#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) 160#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13)
161#define DO_NOT_FORCE_LINK_FAIL (1 << 10) 161#define DO_NOT_FORCE_LINK_FAIL (1 << 10)
162#define SERIAL_PORT_CONTROL_RESERVED (1 << 9) 162#define SERIAL_PORT_CONTROL_RESERVED (1 << 9)
@@ -1135,10 +1135,28 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *
1135 1135
1136static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) 1136static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd)
1137{ 1137{
1138 struct mv643xx_eth_private *mp = netdev_priv(dev);
1139 u32 port_status;
1140
1141 port_status = rdl(mp, PORT_STATUS(mp->port_num));
1142
1138 cmd->supported = SUPPORTED_MII; 1143 cmd->supported = SUPPORTED_MII;
1139 cmd->advertising = ADVERTISED_MII; 1144 cmd->advertising = ADVERTISED_MII;
1140 cmd->speed = SPEED_1000; 1145 switch (port_status & PORT_SPEED_MASK) {
1141 cmd->duplex = DUPLEX_FULL; 1146 case PORT_SPEED_10:
1147 cmd->speed = SPEED_10;
1148 break;
1149 case PORT_SPEED_100:
1150 cmd->speed = SPEED_100;
1151 break;
1152 case PORT_SPEED_1000:
1153 cmd->speed = SPEED_1000;
1154 break;
1155 default:
1156 cmd->speed = -1;
1157 break;
1158 }
1159 cmd->duplex = (port_status & FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
1142 cmd->port = PORT_MII; 1160 cmd->port = PORT_MII;
1143 cmd->phy_address = 0; 1161 cmd->phy_address = 0;
1144 cmd->transceiver = XCVR_INTERNAL; 1162 cmd->transceiver = XCVR_INTERNAL;
@@ -1661,51 +1679,6 @@ static void txq_deinit(struct tx_queue *txq)
1661 1679
1662 1680
1663/* netdev ops and related ***************************************************/ 1681/* netdev ops and related ***************************************************/
1664static void update_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)
1665{
1666 u32 pscr_o;
1667 u32 pscr_n;
1668
1669 pscr_o = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
1670
1671 /* clear speed, duplex and rx buffer size fields */
1672 pscr_n = pscr_o & ~(SET_MII_SPEED_TO_100 |
1673 SET_GMII_SPEED_TO_1000 |
1674 SET_FULL_DUPLEX_MODE |
1675 MAX_RX_PACKET_MASK);
1676
1677 pscr_n |= MAX_RX_PACKET_9700BYTE;
1678
1679 if (speed == SPEED_1000)
1680 pscr_n |= SET_GMII_SPEED_TO_1000;
1681 else if (speed == SPEED_100)
1682 pscr_n |= SET_MII_SPEED_TO_100;
1683
1684 if (duplex == DUPLEX_FULL)
1685 pscr_n |= SET_FULL_DUPLEX_MODE;
1686
1687 if (pscr_n != pscr_o) {
1688 if ((pscr_o & SERIAL_PORT_ENABLE) == 0)
1689 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n);
1690 else {
1691 int i;
1692
1693 for (i = 0; i < 8; i++)
1694 if (mp->txq_mask & (1 << i))
1695 txq_disable(mp->txq + i);
1696
1697 pscr_o &= ~SERIAL_PORT_ENABLE;
1698 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_o);
1699 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n);
1700 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n);
1701
1702 for (i = 0; i < 8; i++)
1703 if (mp->txq_mask & (1 << i))
1704 txq_enable(mp->txq + i);
1705 }
1706 }
1707}
1708
1709static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) 1682static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
1710{ 1683{
1711 struct net_device *dev = (struct net_device *)dev_id; 1684 struct net_device *dev = (struct net_device *)dev_id;
@@ -1726,14 +1699,7 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
1726 } 1699 }
1727 1700
1728 if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { 1701 if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) {
1729 if (mp->phy_addr == -1 || mii_link_ok(&mp->mii)) { 1702 if (rdl(mp, PORT_STATUS(mp->port_num)) & LINK_UP) {
1730 if (mp->phy_addr != -1) {
1731 struct ethtool_cmd cmd;
1732
1733 mii_ethtool_gset(&mp->mii, &cmd);
1734 update_pscr(mp, cmd.speed, cmd.duplex);
1735 }
1736
1737 if (!netif_carrier_ok(dev)) { 1703 if (!netif_carrier_ok(dev)) {
1738 netif_carrier_on(dev); 1704 netif_carrier_on(dev);
1739 netif_wake_queue(dev); 1705 netif_wake_queue(dev);
@@ -1847,23 +1813,6 @@ static void port_start(struct mv643xx_eth_private *mp)
1847 int i; 1813 int i;
1848 1814
1849 /* 1815 /*
1850 * Configure basic link parameters.
1851 */
1852 pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
1853 pscr &= ~(SERIAL_PORT_ENABLE | FORCE_LINK_PASS);
1854 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
1855 pscr |= DISABLE_AUTO_NEG_FOR_FLOW_CTRL |
1856 DISABLE_AUTO_NEG_SPEED_GMII |
1857 DISABLE_AUTO_NEG_FOR_DUPLEX |
1858 DO_NOT_FORCE_LINK_FAIL |
1859 SERIAL_PORT_CONTROL_RESERVED;
1860 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
1861 pscr |= SERIAL_PORT_ENABLE;
1862 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
1863
1864 wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE);
1865
1866 /*
1867 * Perform PHY reset, if there is a PHY. 1816 * Perform PHY reset, if there is a PHY.
1868 */ 1817 */
1869 if (mp->phy_addr != -1) { 1818 if (mp->phy_addr != -1) {
@@ -1875,6 +1824,21 @@ static void port_start(struct mv643xx_eth_private *mp)
1875 } 1824 }
1876 1825
1877 /* 1826 /*
1827 * Configure basic link parameters.
1828 */
1829 pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
1830
1831 pscr |= SERIAL_PORT_ENABLE;
1832 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
1833
1834 pscr |= DO_NOT_FORCE_LINK_FAIL;
1835 if (mp->phy_addr == -1)
1836 pscr |= FORCE_LINK_PASS;
1837 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
1838
1839 wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE);
1840
1841 /*
1878 * Configure TX path and queues. 1842 * Configure TX path and queues.
1879 */ 1843 */
1880 tx_set_rate(mp, 1000000000, 16777216); 1844 tx_set_rate(mp, 1000000000, 16777216);
@@ -2441,12 +2405,39 @@ static int phy_init(struct mv643xx_eth_private *mp,
2441 cmd.duplex = pd->duplex; 2405 cmd.duplex = pd->duplex;
2442 } 2406 }
2443 2407
2444 update_pscr(mp, cmd.speed, cmd.duplex);
2445 mv643xx_eth_set_settings(mp->dev, &cmd); 2408 mv643xx_eth_set_settings(mp->dev, &cmd);
2446 2409
2447 return 0; 2410 return 0;
2448} 2411}
2449 2412
2413static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)
2414{
2415 u32 pscr;
2416
2417 pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
2418 if (pscr & SERIAL_PORT_ENABLE) {
2419 pscr &= ~SERIAL_PORT_ENABLE;
2420 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
2421 }
2422
2423 pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED;
2424 if (mp->phy_addr == -1) {
2425 pscr |= DISABLE_AUTO_NEG_SPEED_GMII;
2426 if (speed == SPEED_1000)
2427 pscr |= SET_GMII_SPEED_TO_1000;
2428 else if (speed == SPEED_100)
2429 pscr |= SET_MII_SPEED_TO_100;
2430
2431 pscr |= DISABLE_AUTO_NEG_FOR_FLOW_CTRL;
2432
2433 pscr |= DISABLE_AUTO_NEG_FOR_DUPLEX;
2434 if (duplex == DUPLEX_FULL)
2435 pscr |= SET_FULL_DUPLEX_MODE;
2436 }
2437
2438 wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
2439}
2440
2450static int mv643xx_eth_probe(struct platform_device *pdev) 2441static int mv643xx_eth_probe(struct platform_device *pdev)
2451{ 2442{
2452 struct mv643xx_eth_platform_data *pd; 2443 struct mv643xx_eth_platform_data *pd;
@@ -2500,6 +2491,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
2500 } else { 2491 } else {
2501 SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless); 2492 SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless);
2502 } 2493 }
2494 init_pscr(mp, pd->speed, pd->duplex);
2503 2495
2504 2496
2505 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 2497 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);