ar71xx: detect link on LAN ports
authorMatteo Croce <rootkit85@yahoo.it>
Tue, 17 May 2011 11:12:56 +0000 (11:12 +0000)
committerMatteo Croce <rootkit85@yahoo.it>
Tue, 17 May 2011 11:12:56 +0000 (11:12 +0000)
SVN-Revision: 26922

target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_phy.c

index 342d121860bb3c969061b2890da9685e91fb9471..30caaff027d94dedc72f03b96ea17b5e9a714843 100644 (file)
@@ -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
index 1bc7f58c17617783b8a3a232a47befc1613969c3..d84cc81aec04f24a9719bdf72020d45cdf5de0c0 100644 (file)
@@ -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;
 }
 
index d0bae03b13b57644f59f5b7dbefa0903bc1bd2e9..75500277f4cda0bcd65935960c3e7542b65b08ae 100644 (file)
@@ -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);
        }