diff options
author | matteo <matteo@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2011-05-17 11:12:56 +0000 |
---|---|---|
committer | matteo <matteo@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2011-05-17 11:12:56 +0000 |
commit | 483991c363ddf316b758ce87ef7d837a6eeeceea (patch) | |
tree | b77a7b7e7fc4239fafcf4cb6d7eed9924a305a86 /target/linux | |
parent | 0ab2415c3de7c3e7c6c662d37507afdeb21dcb3d (diff) |
ar71xx: detect link on LAN ports
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@26922 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux')
3 files changed, 32 insertions, 3 deletions
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h index 342d12186..30caaff02 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h @@ -162,6 +162,7 @@ struct ag71xx { int duplex; struct work_struct restart_work; + struct delayed_work link_work; struct timer_list oom_timer; #ifdef CONFIG_AG71XX_DEBUG_FS diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c index 1bc7f58c1..d84cc81ae 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c @@ -828,6 +828,30 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) return as; } +static void link_function(struct work_struct *work) { + struct ag71xx *ag = container_of(work, struct ag71xx, link_work.work); + unsigned long flags; + int i; + int status = 0; + + for (i = 0; i < 4; i++) { + int link = ar7240sw_phy_read(ag->mii_bus, i, MII_BMSR); + if(link & BMSR_LSTATUS) { + status = 1; + break; + } + } + + spin_lock_irqsave(&ag->lock, flags); + if(status != ag->link) { + ag->link = status; + ag71xx_link_adjust(ag); + } + spin_unlock_irqrestore(&ag->lock, flags); + + schedule_delayed_work(&ag->link_work, HZ / 2); +} + void ag71xx_ar7240_start(struct ag71xx *ag) { struct ar7240sw *as = ag->phy_priv; @@ -836,15 +860,17 @@ void ag71xx_ar7240_start(struct ag71xx *ag) ar7240sw_setup(as); ag->speed = SPEED_1000; - ag->link = 1; ag->duplex = 1; ar7240_set_addr(as, ag->dev->dev_addr); ar7240_hw_apply(&as->swdev); + + schedule_delayed_work(&ag->link_work, HZ / 10); } void ag71xx_ar7240_stop(struct ag71xx *ag) { + cancel_delayed_work_sync(&ag->link_work); } int __devinit ag71xx_ar7240_init(struct ag71xx *ag) @@ -858,6 +884,8 @@ int __devinit ag71xx_ar7240_init(struct ag71xx *ag) ag->phy_priv = as; ar7240sw_reset(as); + INIT_DELAYED_WORK(&ag->link_work, link_function); + return 0; } diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_phy.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_phy.c index d0bae03b1..75500277f 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_phy.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_phy.c @@ -48,9 +48,9 @@ void ag71xx_phy_start(struct ag71xx *ag) if (ag->phy_dev) { phy_start(ag->phy_dev); + } else if (pdata->has_ar7240_switch) { + ag71xx_ar7240_start(ag); } else { - if (pdata->has_ar7240_switch) - ag71xx_ar7240_start(ag); ag->link = 1; ag71xx_link_adjust(ag); } |