diff options
author | Andrew Victor <andrew@sanpeople.com> | 2006-06-20 05:50:23 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-06-22 22:56:21 -0400 |
commit | 775637df0caccc204628ebacca2b07f35c88b96b (patch) | |
tree | 837b379c417d2bd39f92ede7036642c12f47b014 /drivers | |
parent | d955d90b90db4b3ac2a3e56d271f372c41fb00d6 (diff) |
[PATCH] AT91RM9200 Ethernet #1: Link poll
For Ethernet PHYs that don't have an IRQ pin or boards that don't
connect the IRQ pin to the processor, we enable a timer to poll the
PHY's link state.
Patch originally supplied by Eric Benard and Roman Kolesnikov.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/arm/at91_ether.c | 61 |
1 files changed, 43 insertions, 18 deletions
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 5503dc8a66e4..5b5095629a93 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c | |||
@@ -45,6 +45,9 @@ | |||
45 | static struct net_device *at91_dev; | 45 | static struct net_device *at91_dev; |
46 | static struct clk *ether_clk; | 46 | static struct clk *ether_clk; |
47 | 47 | ||
48 | static struct timer_list check_timer; | ||
49 | #define LINK_POLL_INTERVAL (HZ) | ||
50 | |||
48 | /* ..................................................................... */ | 51 | /* ..................................................................... */ |
49 | 52 | ||
50 | /* | 53 | /* |
@@ -143,7 +146,7 @@ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int | |||
143 | * MAC accordingly. | 146 | * MAC accordingly. |
144 | * If no link or auto-negotiation is busy, then no changes are made. | 147 | * If no link or auto-negotiation is busy, then no changes are made. |
145 | */ | 148 | */ |
146 | static void update_linkspeed(struct net_device *dev) | 149 | static void update_linkspeed(struct net_device *dev, int silent) |
147 | { | 150 | { |
148 | struct at91_private *lp = (struct at91_private *) dev->priv; | 151 | struct at91_private *lp = (struct at91_private *) dev->priv; |
149 | unsigned int bmsr, bmcr, lpa, mac_cfg; | 152 | unsigned int bmsr, bmcr, lpa, mac_cfg; |
@@ -151,7 +154,8 @@ static void update_linkspeed(struct net_device *dev) | |||
151 | 154 | ||
152 | if (!mii_link_ok(&lp->mii)) { /* no link */ | 155 | if (!mii_link_ok(&lp->mii)) { /* no link */ |
153 | netif_carrier_off(dev); | 156 | netif_carrier_off(dev); |
154 | printk(KERN_INFO "%s: Link down.\n", dev->name); | 157 | if (!silent) |
158 | printk(KERN_INFO "%s: Link down.\n", dev->name); | ||
155 | return; | 159 | return; |
156 | } | 160 | } |
157 | 161 | ||
@@ -186,7 +190,8 @@ static void update_linkspeed(struct net_device *dev) | |||
186 | } | 190 | } |
187 | at91_emac_write(AT91_EMAC_CFG, mac_cfg); | 191 | at91_emac_write(AT91_EMAC_CFG, mac_cfg); |
188 | 192 | ||
189 | printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); | 193 | if (!silent) |
194 | printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); | ||
190 | netif_carrier_on(dev); | 195 | netif_carrier_on(dev); |
191 | } | 196 | } |
192 | 197 | ||
@@ -226,7 +231,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs | |||
226 | goto done; | 231 | goto done; |
227 | } | 232 | } |
228 | 233 | ||
229 | update_linkspeed(dev); | 234 | update_linkspeed(dev, 0); |
230 | 235 | ||
231 | done: | 236 | done: |
232 | disable_mdi(); | 237 | disable_mdi(); |
@@ -243,14 +248,17 @@ static void enable_phyirq(struct net_device *dev) | |||
243 | unsigned int dsintr, irq_number; | 248 | unsigned int dsintr, irq_number; |
244 | int status; | 249 | int status; |
245 | 250 | ||
246 | if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ | 251 | irq_number = lp->board_data.phy_irq_pin; |
247 | return; | 252 | if (!irq_number) { |
248 | if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ | 253 | /* |
249 | return; | 254 | * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), |
250 | if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ | 255 | * or board does not have it connected. |
256 | */ | ||
257 | check_timer.expires = jiffies + LINK_POLL_INTERVAL; | ||
258 | add_timer(&check_timer); | ||
251 | return; | 259 | return; |
260 | } | ||
252 | 261 | ||
253 | irq_number = lp->board_data.phy_irq_pin; | ||
254 | status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); | 262 | status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); |
255 | if (status) { | 263 | if (status) { |
256 | printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); | 264 | printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); |
@@ -292,12 +300,11 @@ static void disable_phyirq(struct net_device *dev) | |||
292 | unsigned int dsintr; | 300 | unsigned int dsintr; |
293 | unsigned int irq_number; | 301 | unsigned int irq_number; |
294 | 302 | ||
295 | if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ | 303 | irq_number = lp->board_data.phy_irq_pin; |
296 | return; | 304 | if (!irq_number) { |
297 | if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ | 305 | del_timer_sync(&check_timer); |
298 | return; | ||
299 | if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ | ||
300 | return; | 306 | return; |
307 | } | ||
301 | 308 | ||
302 | spin_lock_irq(&lp->lock); | 309 | spin_lock_irq(&lp->lock); |
303 | enable_mdi(); | 310 | enable_mdi(); |
@@ -326,7 +333,6 @@ static void disable_phyirq(struct net_device *dev) | |||
326 | disable_mdi(); | 333 | disable_mdi(); |
327 | spin_unlock_irq(&lp->lock); | 334 | spin_unlock_irq(&lp->lock); |
328 | 335 | ||
329 | irq_number = lp->board_data.phy_irq_pin; | ||
330 | free_irq(irq_number, dev); /* Free interrupt handler */ | 336 | free_irq(irq_number, dev); /* Free interrupt handler */ |
331 | } | 337 | } |
332 | 338 | ||
@@ -355,6 +361,18 @@ static void reset_phy(struct net_device *dev) | |||
355 | } | 361 | } |
356 | #endif | 362 | #endif |
357 | 363 | ||
364 | static void at91ether_check_link(unsigned long dev_id) | ||
365 | { | ||
366 | struct net_device *dev = (struct net_device *) dev_id; | ||
367 | |||
368 | enable_mdi(); | ||
369 | update_linkspeed(dev, 1); | ||
370 | disable_mdi(); | ||
371 | |||
372 | check_timer.expires = jiffies + LINK_POLL_INTERVAL; | ||
373 | add_timer(&check_timer); | ||
374 | } | ||
375 | |||
358 | /* ......................... ADDRESS MANAGEMENT ........................ */ | 376 | /* ......................... ADDRESS MANAGEMENT ........................ */ |
359 | 377 | ||
360 | /* | 378 | /* |
@@ -708,7 +726,7 @@ static int at91ether_open(struct net_device *dev) | |||
708 | /* Determine current link speed */ | 726 | /* Determine current link speed */ |
709 | spin_lock_irq(&lp->lock); | 727 | spin_lock_irq(&lp->lock); |
710 | enable_mdi(); | 728 | enable_mdi(); |
711 | update_linkspeed(dev); | 729 | update_linkspeed(dev, 0); |
712 | disable_mdi(); | 730 | disable_mdi(); |
713 | spin_unlock_irq(&lp->lock); | 731 | spin_unlock_irq(&lp->lock); |
714 | 732 | ||
@@ -992,11 +1010,18 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add | |||
992 | /* Determine current link speed */ | 1010 | /* Determine current link speed */ |
993 | spin_lock_irq(&lp->lock); | 1011 | spin_lock_irq(&lp->lock); |
994 | enable_mdi(); | 1012 | enable_mdi(); |
995 | update_linkspeed(dev); | 1013 | update_linkspeed(dev, 0); |
996 | disable_mdi(); | 1014 | disable_mdi(); |
997 | spin_unlock_irq(&lp->lock); | 1015 | spin_unlock_irq(&lp->lock); |
998 | netif_carrier_off(dev); /* will be enabled in open() */ | 1016 | netif_carrier_off(dev); /* will be enabled in open() */ |
999 | 1017 | ||
1018 | /* If board has no PHY IRQ, use a timer to poll the PHY */ | ||
1019 | if (!lp->board_data.phy_irq_pin) { | ||
1020 | init_timer(&check_timer); | ||
1021 | check_timer.data = (unsigned long)dev; | ||
1022 | check_timer.function = at91ether_check_link; | ||
1023 | } | ||
1024 | |||
1000 | /* Display ethernet banner */ | 1025 | /* Display ethernet banner */ |
1001 | printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", | 1026 | printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", |
1002 | dev->name, (uint) dev->base_addr, dev->irq, | 1027 | dev->name, (uint) dev->base_addr, dev->irq, |