net: congestion notifications are not dropped packets
[safe/jmp/linux-2.6] / drivers / net / phy / phy.c
index e3b8932..64be466 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
-#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -254,12 +253,12 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
        if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
                return -EINVAL;
 
-       if (cmd->autoneg == AUTONEG_DISABLE
-                       && ((cmd->speed != SPEED_1000
-                                       && cmd->speed != SPEED_100
-                                       && cmd->speed != SPEED_10)
-                               || (cmd->duplex != DUPLEX_HALF
-                                       && cmd->duplex != DUPLEX_FULL)))
+       if (cmd->autoneg == AUTONEG_DISABLE &&
+           ((cmd->speed != SPEED_1000 &&
+             cmd->speed != SPEED_100 &&
+             cmd->speed != SPEED_10) ||
+            (cmd->duplex != DUPLEX_HALF &&
+             cmd->duplex != DUPLEX_FULL)))
                return -EINVAL;
 
        phydev->autoneg = cmd->autoneg;
@@ -324,9 +323,6 @@ int phy_mii_ioctl(struct phy_device *phydev,
                break;
 
        case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-
                if (mii_data->phy_id == phydev->addr) {
                        switch(mii_data->reg_num) {
                        case MII_BMCR:
@@ -356,9 +352,9 @@ int phy_mii_ioctl(struct phy_device *phydev,
 
                phy_write(phydev, mii_data->reg_num, val);
                
-               if (mii_data->reg_num == MII_BMCR 
-                               && val & BMCR_RESET
-                               && phydev->drv->config_init) {
+               if (mii_data->reg_num == MII_BMCR &&
+                   val & BMCR_RESET &&
+                   phydev->drv->config_init) {
                        phy_scan_fixups(phydev);
                        phydev->drv->config_init(phydev);
                }
@@ -413,7 +409,6 @@ EXPORT_SYMBOL(phy_start_aneg);
 
 
 static void phy_change(struct work_struct *work);
-static void phy_state_machine(struct work_struct *work);
 
 /**
  * phy_start_machine - start PHY state machine tracking
@@ -433,8 +428,7 @@ void phy_start_machine(struct phy_device *phydev,
 {
        phydev->adjust_state = handler;
 
-       INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
-       schedule_delayed_work(&phydev->state_queue, jiffies + HZ);
+       schedule_delayed_work(&phydev->state_queue, HZ);
 }
 
 /**
@@ -764,7 +758,7 @@ EXPORT_SYMBOL(phy_start);
  * phy_state_machine - Handle the state machine
  * @work: work_struct that describes the work to be done
  */
-static void phy_state_machine(struct work_struct *work)
+void phy_state_machine(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
        struct phy_device *phydev =
@@ -928,13 +922,32 @@ static void phy_state_machine(struct work_struct *work)
                                 * Otherwise, it's 0, and we're
                                 * still waiting for AN */
                                if (err > 0) {
-                                       phydev->state = PHY_RUNNING;
+                                       err = phy_read_status(phydev);
+                                       if (err)
+                                               break;
+
+                                       if (phydev->link) {
+                                               phydev->state = PHY_RUNNING;
+                                               netif_carrier_on(phydev->attached_dev);
+                                       } else
+                                               phydev->state = PHY_NOLINK;
+                                       phydev->adjust_link(phydev->attached_dev);
                                } else {
                                        phydev->state = PHY_AN;
                                        phydev->link_timeout = PHY_AN_TIMEOUT;
                                }
-                       } else
-                               phydev->state = PHY_RUNNING;
+                       } else {
+                               err = phy_read_status(phydev);
+                               if (err)
+                                       break;
+
+                               if (phydev->link) {
+                                       phydev->state = PHY_RUNNING;
+                                       netif_carrier_on(phydev->attached_dev);
+                               } else
+                                       phydev->state = PHY_NOLINK;
+                               phydev->adjust_link(phydev->attached_dev);
+                       }
                        break;
        }
 
@@ -946,6 +959,5 @@ static void phy_state_machine(struct work_struct *work)
        if (err < 0)
                phy_error(phydev);
 
-       schedule_delayed_work(&phydev->state_queue,
-                               jiffies + PHY_STATE_TIME * HZ);
+       schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
 }