-static irqreturn_t phy_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupt */
- mii_clear_phy_interrupt(ugeth->mii_info);
-
- /* Disable PHY interrupts */
- mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
-
- /* Schedule the phy change */
- schedule_work(&ugeth->tq);
-
- return IRQ_HANDLED;
-}
-
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(struct work_struct *work)
-{
- struct ucc_geth_private *ugeth =
- container_of(work, struct ucc_geth_private, tq);
- struct net_device *dev = ugeth->dev;
- struct ucc_geth *ug_regs;
- int result = 0;
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
-
- ug_regs = ugeth->ug_regs;
-
- /* Delay to give the PHY a chance to change the
- * register state */
- msleep(1);
-
- /* Update the link, speed, duplex */
- result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
-
- /* Adjust the known status as long as the link
- * isn't still coming up */
- if ((0 == result) || (ugeth->mii_info->link == 0))
- adjust_link(dev);
-
- /* Reenable interrupts, if needed */
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void ugeth_phy_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- schedule_work(&ugeth->tq);
-
- mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using ugeth_phy_timer to check status */
-static void ugeth_phy_startup_timer(unsigned long data)
-{
- struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
- struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
- static int secondary = UGETH_AN_TIMEOUT;
- int result;
-
- /* Configure the Auto-negotiation */
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* If autonegotiation failed to start, and
- * we haven't timed out, reset the timer, and return */
- if (result && secondary--) {
- mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
- return;
- } else if (result) {
- /* Couldn't start autonegotiation.
- * Try switching to forced */
- mii_info->autoneg = 0;
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* Forcing failed! Give up */
- if (result) {
- ugeth_err("%s: Forcing failed!", mii_info->dev->name);
- return;
- }
- }
-
- /* Kill the timer so it can be restarted */
- del_timer_sync(&ugeth->phy_info_timer);
-
- /* Grab the PHY interrupt, if necessary/possible */
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- if (request_irq(ugeth->ug_info->phy_interrupt,
- phy_interrupt, IRQF_SHARED,
- "phy_interrupt", mii_info->dev) < 0) {
- ugeth_err("%s: Can't get IRQ %d (PHY)",
- mii_info->dev->name,
- ugeth->ug_info->phy_interrupt);
- } else {
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_ENABLED);
- return;
- }
- }
-
- /* Start the timer again, this time in order to
- * handle a change in status */
- init_timer(&ugeth->phy_info_timer);
- ugeth->phy_info_timer.function = &ugeth_phy_timer;
- ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
- mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-