|
@@ -260,6 +260,41 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
|
|
|
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * phy_supported_speeds - return all speeds currently supported by a phy device
|
|
|
+ * @phy: The phy device to return supported speeds of.
|
|
|
+ * @speeds: buffer to store supported speeds in.
|
|
|
+ * @size: size of speeds buffer.
|
|
|
+ *
|
|
|
+ * Description: Returns the number of supported speeds, and fills the speeds
|
|
|
+ * buffer with the supported speeds. If speeds buffer is too small to contain
|
|
|
+ * all currently supported speeds, will return as many speeds as can fit.
|
|
|
+ */
|
|
|
+unsigned int phy_supported_speeds(struct phy_device *phy,
|
|
|
+ unsigned int *speeds,
|
|
|
+ unsigned int size)
|
|
|
+{
|
|
|
+ unsigned int count = 0;
|
|
|
+ unsigned int idx = 0;
|
|
|
+
|
|
|
+ while (idx < MAX_NUM_SETTINGS && count < size) {
|
|
|
+ idx = phy_find_valid(idx, phy->supported);
|
|
|
+
|
|
|
+ if (!(settings[idx].setting & phy->supported))
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* Assumes settings are grouped by speed */
|
|
|
+ if ((count == 0) ||
|
|
|
+ (speeds[count - 1] != settings[idx].speed)) {
|
|
|
+ speeds[count] = settings[idx].speed;
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* phy_check_valid - check if there is a valid PHY setting which matches
|
|
|
* speed, duplex, and feature mask
|
|
@@ -908,6 +943,12 @@ void phy_start(struct phy_device *phydev)
|
|
|
}
|
|
|
EXPORT_SYMBOL(phy_start);
|
|
|
|
|
|
+static void phy_adjust_link(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_led_trigger_change_speed(phydev);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* phy_state_machine - Handle the state machine
|
|
|
* @work: work_struct that describes the work to be done
|
|
@@ -950,7 +991,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
if (!phydev->link) {
|
|
|
phydev->state = PHY_NOLINK;
|
|
|
netif_carrier_off(phydev->attached_dev);
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -963,7 +1004,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
if (err > 0) {
|
|
|
phydev->state = PHY_RUNNING;
|
|
|
netif_carrier_on(phydev->attached_dev);
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
|
|
|
} else if (0 == phydev->link_timeout--)
|
|
|
needs_aneg = true;
|
|
@@ -990,7 +1031,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
}
|
|
|
phydev->state = PHY_RUNNING;
|
|
|
netif_carrier_on(phydev->attached_dev);
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
}
|
|
|
break;
|
|
|
case PHY_FORCING:
|
|
@@ -1006,7 +1047,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
needs_aneg = true;
|
|
|
}
|
|
|
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
break;
|
|
|
case PHY_RUNNING:
|
|
|
/* Only register a CHANGE if we are polling and link changed
|
|
@@ -1035,7 +1076,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
netif_carrier_off(phydev->attached_dev);
|
|
|
}
|
|
|
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
|
|
|
if (phy_interrupt_is_valid(phydev))
|
|
|
err = phy_config_interrupt(phydev,
|
|
@@ -1045,7 +1086,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
if (phydev->link) {
|
|
|
phydev->link = 0;
|
|
|
netif_carrier_off(phydev->attached_dev);
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
do_suspend = true;
|
|
|
}
|
|
|
break;
|
|
@@ -1069,7 +1110,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
} else {
|
|
|
phydev->state = PHY_NOLINK;
|
|
|
}
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
} else {
|
|
|
phydev->state = PHY_AN;
|
|
|
phydev->link_timeout = PHY_AN_TIMEOUT;
|
|
@@ -1085,7 +1126,7 @@ void phy_state_machine(struct work_struct *work)
|
|
|
} else {
|
|
|
phydev->state = PHY_NOLINK;
|
|
|
}
|
|
|
- phydev->adjust_link(phydev->attached_dev);
|
|
|
+ phy_adjust_link(phydev);
|
|
|
}
|
|
|
break;
|
|
|
}
|