diff options
Diffstat (limited to 'drivers/net/mv643xx_eth.c')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 191 |
1 files changed, 134 insertions, 57 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 2d434017a670..b41860dc5b5e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -72,6 +72,13 @@ static char mv643xx_eth_driver_version[] = "1.3"; | |||
72 | */ | 72 | */ |
73 | #define PHY_ADDR 0x0000 | 73 | #define PHY_ADDR 0x0000 |
74 | #define SMI_REG 0x0004 | 74 | #define SMI_REG 0x0004 |
75 | #define SMI_BUSY 0x10000000 | ||
76 | #define SMI_READ_VALID 0x08000000 | ||
77 | #define SMI_OPCODE_READ 0x04000000 | ||
78 | #define SMI_OPCODE_WRITE 0x00000000 | ||
79 | #define ERR_INT_CAUSE 0x0080 | ||
80 | #define ERR_INT_SMI_DONE 0x00000010 | ||
81 | #define ERR_INT_MASK 0x0084 | ||
75 | #define WINDOW_BASE(w) (0x0200 + ((w) << 3)) | 82 | #define WINDOW_BASE(w) (0x0200 + ((w) << 3)) |
76 | #define WINDOW_SIZE(w) (0x0204 + ((w) << 3)) | 83 | #define WINDOW_SIZE(w) (0x0204 + ((w) << 3)) |
77 | #define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2)) | 84 | #define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2)) |
@@ -254,6 +261,15 @@ struct mv643xx_eth_shared_private { | |||
254 | struct mutex phy_lock; | 261 | struct mutex phy_lock; |
255 | 262 | ||
256 | /* | 263 | /* |
264 | * If we have access to the error interrupt pin (which is | ||
265 | * somewhat misnamed as it not only reflects internal errors | ||
266 | * but also reflects SMI completion), use that to wait for | ||
267 | * SMI access completion instead of polling the SMI busy bit. | ||
268 | */ | ||
269 | int err_interrupt; | ||
270 | wait_queue_head_t smi_busy_wait; | ||
271 | |||
272 | /* | ||
257 | * Per-port MBUS window access register value. | 273 | * Per-port MBUS window access register value. |
258 | */ | 274 | */ |
259 | u32 win_protect; | 275 | u32 win_protect; |
@@ -979,68 +995,103 @@ static void txq_set_wrr(struct tx_queue *txq, int weight) | |||
979 | 995 | ||
980 | 996 | ||
981 | /* mii management interface *************************************************/ | 997 | /* mii management interface *************************************************/ |
982 | #define SMI_BUSY 0x10000000 | 998 | static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id) |
983 | #define SMI_READ_VALID 0x08000000 | 999 | { |
984 | #define SMI_OPCODE_READ 0x04000000 | 1000 | struct mv643xx_eth_shared_private *msp = dev_id; |
985 | #define SMI_OPCODE_WRITE 0x00000000 | ||
986 | 1001 | ||
987 | static void smi_reg_read(struct mv643xx_eth_private *mp, unsigned int addr, | 1002 | if (readl(msp->base + ERR_INT_CAUSE) & ERR_INT_SMI_DONE) { |
988 | unsigned int reg, unsigned int *value) | 1003 | writel(~ERR_INT_SMI_DONE, msp->base + ERR_INT_CAUSE); |
1004 | wake_up(&msp->smi_busy_wait); | ||
1005 | return IRQ_HANDLED; | ||
1006 | } | ||
1007 | |||
1008 | return IRQ_NONE; | ||
1009 | } | ||
1010 | |||
1011 | static int smi_is_done(struct mv643xx_eth_shared_private *msp) | ||
989 | { | 1012 | { |
990 | void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; | 1013 | return !(readl(msp->base + SMI_REG) & SMI_BUSY); |
991 | int i; | 1014 | } |
992 | 1015 | ||
993 | /* the SMI register is a shared resource */ | 1016 | static int smi_wait_ready(struct mv643xx_eth_shared_private *msp) |
994 | mutex_lock(&mp->shared_smi->phy_lock); | 1017 | { |
1018 | if (msp->err_interrupt == NO_IRQ) { | ||
1019 | int i; | ||
995 | 1020 | ||
996 | /* wait for the SMI register to become available */ | 1021 | for (i = 0; !smi_is_done(msp); i++) { |
997 | for (i = 0; readl(smi_reg) & SMI_BUSY; i++) { | 1022 | if (i == 10) |
998 | if (i == 1000) { | 1023 | return -ETIMEDOUT; |
999 | printk("%s: PHY busy timeout\n", mp->dev->name); | 1024 | msleep(10); |
1000 | goto out; | ||
1001 | } | 1025 | } |
1002 | udelay(10); | 1026 | |
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | if (!wait_event_timeout(msp->smi_busy_wait, smi_is_done(msp), | ||
1031 | msecs_to_jiffies(100))) | ||
1032 | return -ETIMEDOUT; | ||
1033 | |||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | static int smi_reg_read(struct mv643xx_eth_private *mp, | ||
1038 | unsigned int addr, unsigned int reg) | ||
1039 | { | ||
1040 | struct mv643xx_eth_shared_private *msp = mp->shared_smi; | ||
1041 | void __iomem *smi_reg = msp->base + SMI_REG; | ||
1042 | int ret; | ||
1043 | |||
1044 | mutex_lock(&msp->phy_lock); | ||
1045 | |||
1046 | if (smi_wait_ready(msp)) { | ||
1047 | printk("%s: SMI bus busy timeout\n", mp->dev->name); | ||
1048 | ret = -ETIMEDOUT; | ||
1049 | goto out; | ||
1003 | } | 1050 | } |
1004 | 1051 | ||
1005 | writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); | 1052 | writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); |
1006 | 1053 | ||
1007 | /* now wait for the data to be valid */ | 1054 | if (smi_wait_ready(msp)) { |
1008 | for (i = 0; !(readl(smi_reg) & SMI_READ_VALID); i++) { | 1055 | printk("%s: SMI bus busy timeout\n", mp->dev->name); |
1009 | if (i == 1000) { | 1056 | ret = -ETIMEDOUT; |
1010 | printk("%s: PHY read timeout\n", mp->dev->name); | 1057 | goto out; |
1011 | goto out; | ||
1012 | } | ||
1013 | udelay(10); | ||
1014 | } | 1058 | } |
1015 | 1059 | ||
1016 | *value = readl(smi_reg) & 0xffff; | 1060 | ret = readl(smi_reg); |
1061 | if (!(ret & SMI_READ_VALID)) { | ||
1062 | printk("%s: SMI bus read not valid\n", mp->dev->name); | ||
1063 | ret = -ENODEV; | ||
1064 | goto out; | ||
1065 | } | ||
1066 | |||
1067 | ret &= 0xffff; | ||
1068 | |||
1017 | out: | 1069 | out: |
1018 | mutex_unlock(&mp->shared_smi->phy_lock); | 1070 | mutex_unlock(&msp->phy_lock); |
1071 | |||
1072 | return ret; | ||
1019 | } | 1073 | } |
1020 | 1074 | ||
1021 | static void smi_reg_write(struct mv643xx_eth_private *mp, | 1075 | static int smi_reg_write(struct mv643xx_eth_private *mp, unsigned int addr, |
1022 | unsigned int addr, | 1076 | unsigned int reg, unsigned int value) |
1023 | unsigned int reg, unsigned int value) | ||
1024 | { | 1077 | { |
1025 | void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; | 1078 | struct mv643xx_eth_shared_private *msp = mp->shared_smi; |
1026 | int i; | 1079 | void __iomem *smi_reg = msp->base + SMI_REG; |
1027 | 1080 | ||
1028 | /* the SMI register is a shared resource */ | 1081 | mutex_lock(&msp->phy_lock); |
1029 | mutex_lock(&mp->shared_smi->phy_lock); | ||
1030 | 1082 | ||
1031 | /* wait for the SMI register to become available */ | 1083 | if (smi_wait_ready(msp)) { |
1032 | for (i = 0; readl(smi_reg) & SMI_BUSY; i++) { | 1084 | printk("%s: SMI bus busy timeout\n", mp->dev->name); |
1033 | if (i == 1000) { | 1085 | mutex_unlock(&msp->phy_lock); |
1034 | printk("%s: PHY busy timeout\n", mp->dev->name); | 1086 | return -ETIMEDOUT; |
1035 | goto out; | ||
1036 | } | ||
1037 | udelay(10); | ||
1038 | } | 1087 | } |
1039 | 1088 | ||
1040 | writel(SMI_OPCODE_WRITE | (reg << 21) | | 1089 | writel(SMI_OPCODE_WRITE | (reg << 21) | |
1041 | (addr << 16) | (value & 0xffff), smi_reg); | 1090 | (addr << 16) | (value & 0xffff), smi_reg); |
1042 | out: | 1091 | |
1043 | mutex_unlock(&mp->shared_smi->phy_lock); | 1092 | mutex_unlock(&msp->phy_lock); |
1093 | |||
1094 | return 0; | ||
1044 | } | 1095 | } |
1045 | 1096 | ||
1046 | 1097 | ||
@@ -1877,16 +1928,19 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) | |||
1877 | 1928 | ||
1878 | static void phy_reset(struct mv643xx_eth_private *mp) | 1929 | static void phy_reset(struct mv643xx_eth_private *mp) |
1879 | { | 1930 | { |
1880 | unsigned int data; | 1931 | int data; |
1932 | |||
1933 | data = smi_reg_read(mp, mp->phy_addr, MII_BMCR); | ||
1934 | if (data < 0) | ||
1935 | return; | ||
1881 | 1936 | ||
1882 | smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); | ||
1883 | data |= BMCR_RESET; | 1937 | data |= BMCR_RESET; |
1884 | smi_reg_write(mp, mp->phy_addr, MII_BMCR, data); | 1938 | if (smi_reg_write(mp, mp->phy_addr, MII_BMCR, data) < 0) |
1939 | return; | ||
1885 | 1940 | ||
1886 | do { | 1941 | do { |
1887 | udelay(1); | 1942 | data = smi_reg_read(mp, mp->phy_addr, MII_BMCR); |
1888 | smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); | 1943 | } while (data >= 0 && data & BMCR_RESET); |
1889 | } while (data & BMCR_RESET); | ||
1890 | } | 1944 | } |
1891 | 1945 | ||
1892 | static void port_start(struct mv643xx_eth_private *mp) | 1946 | static void port_start(struct mv643xx_eth_private *mp) |
@@ -2214,11 +2268,7 @@ static void mv643xx_eth_netpoll(struct net_device *dev) | |||
2214 | static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg) | 2268 | static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg) |
2215 | { | 2269 | { |
2216 | struct mv643xx_eth_private *mp = netdev_priv(dev); | 2270 | struct mv643xx_eth_private *mp = netdev_priv(dev); |
2217 | int val; | 2271 | return smi_reg_read(mp, addr, reg); |
2218 | |||
2219 | smi_reg_read(mp, addr, reg, &val); | ||
2220 | |||
2221 | return val; | ||
2222 | } | 2272 | } |
2223 | 2273 | ||
2224 | static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val) | 2274 | static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val) |
@@ -2317,6 +2367,24 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) | |||
2317 | 2367 | ||
2318 | mutex_init(&msp->phy_lock); | 2368 | mutex_init(&msp->phy_lock); |
2319 | 2369 | ||
2370 | msp->err_interrupt = NO_IRQ; | ||
2371 | init_waitqueue_head(&msp->smi_busy_wait); | ||
2372 | |||
2373 | /* | ||
2374 | * Check whether the error interrupt is hooked up. | ||
2375 | */ | ||
2376 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
2377 | if (res != NULL) { | ||
2378 | int err; | ||
2379 | |||
2380 | err = request_irq(res->start, mv643xx_eth_err_irq, | ||
2381 | IRQF_SHARED, "mv643xx_eth", msp); | ||
2382 | if (!err) { | ||
2383 | writel(ERR_INT_SMI_DONE, msp->base + ERR_INT_MASK); | ||
2384 | msp->err_interrupt = res->start; | ||
2385 | } | ||
2386 | } | ||
2387 | |||
2320 | /* | 2388 | /* |
2321 | * (Re-)program MBUS remapping windows if we are asked to. | 2389 | * (Re-)program MBUS remapping windows if we are asked to. |
2322 | */ | 2390 | */ |
@@ -2343,6 +2411,8 @@ static int mv643xx_eth_shared_remove(struct platform_device *pdev) | |||
2343 | { | 2411 | { |
2344 | struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); | 2412 | struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); |
2345 | 2413 | ||
2414 | if (msp->err_interrupt != NO_IRQ) | ||
2415 | free_irq(msp->err_interrupt, msp); | ||
2346 | iounmap(msp->base); | 2416 | iounmap(msp->base); |
2347 | kfree(msp); | 2417 | kfree(msp); |
2348 | 2418 | ||
@@ -2431,13 +2501,20 @@ static void set_params(struct mv643xx_eth_private *mp, | |||
2431 | 2501 | ||
2432 | static int phy_detect(struct mv643xx_eth_private *mp) | 2502 | static int phy_detect(struct mv643xx_eth_private *mp) |
2433 | { | 2503 | { |
2434 | unsigned int data; | 2504 | int data; |
2435 | unsigned int data2; | 2505 | int data2; |
2506 | |||
2507 | data = smi_reg_read(mp, mp->phy_addr, MII_BMCR); | ||
2508 | if (data < 0) | ||
2509 | return -ENODEV; | ||
2510 | |||
2511 | if (smi_reg_write(mp, mp->phy_addr, MII_BMCR, data ^ BMCR_ANENABLE) < 0) | ||
2512 | return -ENODEV; | ||
2436 | 2513 | ||
2437 | smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); | 2514 | data2 = smi_reg_read(mp, mp->phy_addr, MII_BMCR); |
2438 | smi_reg_write(mp, mp->phy_addr, MII_BMCR, data ^ BMCR_ANENABLE); | 2515 | if (data2 < 0) |
2516 | return -ENODEV; | ||
2439 | 2517 | ||
2440 | smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data2); | ||
2441 | if (((data ^ data2) & BMCR_ANENABLE) == 0) | 2518 | if (((data ^ data2) & BMCR_ANENABLE) == 0) |
2442 | return -ENODEV; | 2519 | return -ENODEV; |
2443 | 2520 | ||