Fix numerous minor problems with new phy subsystem.
authorJeff Garzik <jgarzik@pobox.com>
Thu, 11 Aug 2005 06:07:25 +0000 (02:07 -0400)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 11 Aug 2005 06:07:25 +0000 (02:07 -0400)
Includes fixes for problems noted by Adrian Bunk, Andrew Morton,
and one other person lost in the annals of history (and email folders).

drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/phy/phy.c.orig [deleted file]
drivers/net/phy/phy_device.c
include/linux/phy.h

index 8b5db23..c2f1bf1 100644 (file)
@@ -5,7 +5,7 @@
 menu "PHY device support"
 
 config PHYLIB
-       bool "PHY Device support and infrastructure"
+       tristate "PHY Device support and infrastructure"
        depends on NET_ETHERNET
        help
          Ethernet controllers are usually attached to PHY
@@ -24,31 +24,31 @@ comment "MII PHY device drivers"
        depends on PHYLIB
 
 config MARVELL_PHY
-       bool "Drivers for Marvell PHYs"
+       tristate "Drivers for Marvell PHYs"
        depends on PHYLIB
        ---help---
          Currently has a driver for the 88E1011S
        
 config DAVICOM_PHY
-       bool "Drivers for Davicom PHYs"
+       tristate "Drivers for Davicom PHYs"
        depends on PHYLIB
        ---help---
          Currently supports dm9161e and dm9131
 
 config QSEMI_PHY
-       bool "Drivers for Quality Semiconductor PHYs"
+       tristate "Drivers for Quality Semiconductor PHYs"
        depends on PHYLIB
        ---help---
          Currently supports the qs6612
 
 config LXT_PHY
-       bool "Drivers for the Intel LXT PHYs"
+       tristate "Drivers for the Intel LXT PHYs"
        depends on PHYLIB
        ---help---
          Currently supports the lxt970, lxt971
 
 config CICADA_PHY
-       bool "Drivers for the Cicada PHYs"
+       tristate "Drivers for the Cicada PHYs"
        depends on PHYLIB
        ---help---
          Currently supports the cis8204
index 1af05de..fb7cb38 100644 (file)
@@ -1,9 +1,9 @@
 # Makefile for Linux PHY drivers
 
-obj-$(CONFIG_PHYLIB) += phy.o phy_device.o mdio_bus.o
+libphy-objs                    := phy.o phy_device.o mdio_bus.o
 
-obj-$(CONFIG_MARVELL_PHY) += marvell.o
-obj-$(CONFIG_DAVICOM_PHY) += davicom.o
-obj-$(CONFIG_CICADA_PHY) += cicada.o
-obj-$(CONFIG_LXT_PHY) += lxt.o
-obj-$(CONFIG_QSEMI_PHY) += qsemi.o
+obj-$(CONFIG_MARVELL_PHY)      += libphy.o marvell.o
+obj-$(CONFIG_DAVICOM_PHY)      += libphy.o davicom.o
+obj-$(CONFIG_CICADA_PHY)       += libphy.o cicada.o
+obj-$(CONFIG_LXT_PHY)          += libphy.o lxt.o
+obj-$(CONFIG_QSEMI_PHY)                += libphy.o qsemi.o
index e75103b..5fbea6a 100644 (file)
@@ -165,9 +165,9 @@ struct bus_type mdio_bus_type = {
        .resume         = mdio_bus_resume,
 };
 
-static int __init mdio_bus_init(void)
+int __init mdio_bus_init(void)
 {
        return bus_register(&mdio_bus_type);
 }
 
-subsys_initcall(mdio_bus_init);
+
index e2c6896..934065d 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-static void phy_change(void *data);
 static void phy_timer(unsigned long data);
 
 /* Convenience function to print out the current phy status
@@ -464,7 +463,6 @@ void phy_stop_machine(struct phy_device *phydev)
        phydev->adjust_state = NULL;
 }
 
-#ifdef CONFIG_PHYCONTROL
 /* phy_error:
  *
  * Moves the PHY to the HALTED state in response to a read
@@ -479,6 +477,10 @@ void phy_error(struct phy_device *phydev)
        spin_unlock(&phydev->lock);
 }
 
+#ifdef CONFIG_PHYCONTROL
+
+static void phy_change(void *data);
+
 /* phy_interrupt
  *
  * description: When a PHY interrupt occurs, the handler disables
@@ -672,6 +674,8 @@ void phy_start(struct phy_device *phydev)
 EXPORT_SYMBOL(phy_stop);
 EXPORT_SYMBOL(phy_start);
 
+#endif /* CONFIG_PHYCONTROL */
+
 /* PHY timer which handles the state machine */
 static void phy_timer(unsigned long data)
 {
@@ -859,4 +863,3 @@ static void phy_timer(unsigned long data)
        mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
 }
 
-#endif /* CONFIG_PHYCONTROL */
diff --git a/drivers/net/phy/phy.c.orig b/drivers/net/phy/phy.c.orig
deleted file mode 100644 (file)
index 6af17ce..0000000
+++ /dev/null
@@ -1,860 +0,0 @@
-/*
- * drivers/net/phy/phy.c
- *
- * Framework for configuring and reading PHY devices
- * Based on code in sungem_phy.c and gianfar_phy.c
- *
- * Author: Andy Fleming
- *
- * Copyright (c) 2004 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#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>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/phy.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-static void phy_change(void *data);
-static void phy_timer(unsigned long data);
-
-/* Convenience function to print out the current phy status
- */
-void phy_print_status(struct phy_device *phydev)
-{
-       pr_info("%s: Link is %s", phydev->dev.bus_id,
-                       phydev->link ? "Up" : "Down");
-       if (phydev->link)
-               printk(" - %d/%s", phydev->speed,
-                               DUPLEX_FULL == phydev->duplex ?
-                               "Full" : "Half");
-
-       printk("\n");
-}
-EXPORT_SYMBOL(phy_print_status);
-
-
-/* Convenience functions for reading/writing a given PHY
- * register. They MUST NOT be called from interrupt context,
- * because the bus read/write functions may wait for an interrupt
- * to conclude the operation. */
-int phy_read(struct phy_device *phydev, u16 regnum)
-{
-       int retval;
-       struct mii_bus *bus = phydev->bus;
-
-       spin_lock_bh(&bus->mdio_lock);
-       retval = bus->read(bus, phydev->addr, regnum);
-       spin_unlock_bh(&bus->mdio_lock);
-
-       return retval;
-}
-EXPORT_SYMBOL(phy_read);
-
-int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
-{
-       int err;
-       struct mii_bus *bus = phydev->bus;
-
-       spin_lock_bh(&bus->mdio_lock);
-       err = bus->write(bus, phydev->addr, regnum, val);
-       spin_unlock_bh(&bus->mdio_lock);
-
-       return err;
-}
-EXPORT_SYMBOL(phy_write);
-
-
-int phy_clear_interrupt(struct phy_device *phydev)
-{
-       int err = 0;
-
-       if (phydev->drv->ack_interrupt)
-               err = phydev->drv->ack_interrupt(phydev);
-
-       return err;
-}
-
-
-int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
-{
-       int err = 0;
-
-       phydev->interrupts = interrupts;
-       if (phydev->drv->config_intr)
-               err = phydev->drv->config_intr(phydev);
-
-       return err;
-}
-
-
-/* phy_aneg_done
- *
- * description: Reads the status register and returns 0 either if
- *   auto-negotiation is incomplete, or if there was an error.
- *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
- */
-static inline int phy_aneg_done(struct phy_device *phydev)
-{
-       int retval;
-
-       retval = phy_read(phydev, MII_BMSR);
-
-       return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
-}
-
-/* phy_start_aneg
- *
- * description: Calls the PHY driver's config_aneg, and then
- *   sets the PHY state to PHY_AN if auto-negotiation is enabled,
- *   and to PHY_FORCING if auto-negotiation is disabled. Unless
- *   the PHY is currently HALTED.
- */
-int phy_start_aneg(struct phy_device *phydev)
-{
-       int err;
-
-       spin_lock(&phydev->lock);
-
-       if (AUTONEG_DISABLE == phydev->autoneg)
-               phy_sanitize_settings(phydev);
-
-       err = phydev->drv->config_aneg(phydev);
-
-       if (err < 0)
-               goto out_unlock;
-
-       if (phydev->state != PHY_HALTED) {
-               if (AUTONEG_ENABLE == phydev->autoneg) {
-                       phydev->state = PHY_AN;
-                       phydev->link_timeout = PHY_AN_TIMEOUT;
-               } else {
-                       phydev->state = PHY_FORCING;
-                       phydev->link_timeout = PHY_FORCE_TIMEOUT;
-               }
-       }
-
-out_unlock:
-       spin_unlock(&phydev->lock);
-       return err;
-}
-EXPORT_SYMBOL(phy_start_aneg);
-
-
-/* A structure for mapping a particular speed and duplex
- * combination to a particular SUPPORTED and ADVERTISED value */
-struct phy_setting {
-       int speed;
-       int duplex;
-       u32 setting;
-};
-
-/* A mapping of all SUPPORTED settings to speed/duplex */
-static struct phy_setting settings[] = {
-       {
-               .speed = 10000,
-               .duplex = DUPLEX_FULL,
-               .setting = SUPPORTED_10000baseT_Full,
-       },
-       {
-               .speed = SPEED_1000,
-               .duplex = DUPLEX_FULL,
-               .setting = SUPPORTED_1000baseT_Full,
-       },
-       {
-               .speed = SPEED_1000,
-               .duplex = DUPLEX_HALF,
-               .setting = SUPPORTED_1000baseT_Half,
-       },
-       {
-               .speed = SPEED_100,
-               .duplex = DUPLEX_FULL,
-               .setting = SUPPORTED_100baseT_Full,
-       },
-       {
-               .speed = SPEED_100,
-               .duplex = DUPLEX_HALF,
-               .setting = SUPPORTED_100baseT_Half,
-       },
-       {
-               .speed = SPEED_10,
-               .duplex = DUPLEX_FULL,
-               .setting = SUPPORTED_10baseT_Full,
-       },
-       {
-               .speed = SPEED_10,
-               .duplex = DUPLEX_HALF,
-               .setting = SUPPORTED_10baseT_Half,
-       },
-};
-
-#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
-
-/* phy_find_setting
- *
- * description: Searches the settings array for the setting which
- *   matches the desired speed and duplex, and returns the index
- *   of that setting.  Returns the index of the last setting if
- *   none of the others match.
- */
-static inline int phy_find_setting(int speed, int duplex)
-{
-       int idx = 0;
-
-       while (idx < ARRAY_SIZE(settings) &&
-                       (settings[idx].speed != speed ||
-                       settings[idx].duplex != duplex))
-               idx++;
-
-       return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
-}
-
-/* phy_find_valid
- * idx: The first index in settings[] to search
- * features: A mask of the valid settings
- *
- * description: Returns the index of the first valid setting less
- *   than or equal to the one pointed to by idx, as determined by
- *   the mask in features.  Returns the index of the last setting
- *   if nothing else matches.
- */
-static inline int phy_find_valid(int idx, u32 features)
-{
-       while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
-               idx++;
-
-       return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
-}
-
-/* phy_sanitize_settings
- *
- * description: Make sure the PHY is set to supported speeds and
- *   duplexes.  Drop down by one in this order:  1000/FULL,
- *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
- */
-void phy_sanitize_settings(struct phy_device *phydev)
-{
-       u32 features = phydev->supported;
-       int idx;
-
-       /* Sanitize settings based on PHY capabilities */
-       if ((features & SUPPORTED_Autoneg) == 0)
-               phydev->autoneg = 0;
-
-       idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
-                       features);
-
-       phydev->speed = settings[idx].speed;
-       phydev->duplex = settings[idx].duplex;
-}
-EXPORT_SYMBOL(phy_sanitize_settings);
-
-/* phy_force_reduction
- *
- * description: Reduces the speed/duplex settings by
- *   one notch.  The order is so:
- *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
- *   10/FULL, 10/HALF.  The function bottoms out at 10/HALF.
- */
-static void phy_force_reduction(struct phy_device *phydev)
-{
-       int idx;
-
-       idx = phy_find_setting(phydev->speed, phydev->duplex);
-       
-       idx++;
-
-       idx = phy_find_valid(idx, phydev->supported);
-
-       phydev->speed = settings[idx].speed;
-       phydev->duplex = settings[idx].duplex;
-
-       pr_info("Trying %d/%s\n", phydev->speed,
-                       DUPLEX_FULL == phydev->duplex ?
-                       "FULL" : "HALF");
-}
-
-/* phy_ethtool_sset:
- * A generic ethtool sset function.  Handles all the details
- *
- * A few notes about parameter checking:
- * - We don't set port or transceiver, so we don't care what they
- *   were set to.
- * - phy_start_aneg() will make sure forced settings are sane, and
- *   choose the next best ones from the ones selected, so we don't
- *   care if ethtool tries to give us bad values
- */
-int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
-{
-       if (cmd->phy_address != phydev->addr)
-               return -EINVAL;
-
-       /* We make sure that we don't pass unsupported
-        * values in to the PHY */
-       cmd->advertising &= phydev->supported;
-
-       /* Verify the settings we care about. */
-       if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
-               return -EINVAL;
-
-       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)))
-               return -EINVAL;
-
-       phydev->autoneg = cmd->autoneg;
-
-       phydev->speed = cmd->speed;
-
-       phydev->advertising = cmd->advertising;
-
-       if (AUTONEG_ENABLE == cmd->autoneg)
-               phydev->advertising |= ADVERTISED_Autoneg;
-       else
-               phydev->advertising &= ~ADVERTISED_Autoneg;
-
-       phydev->duplex = cmd->duplex;
-
-       /* Restart the PHY */
-       phy_start_aneg(phydev);
-
-       return 0;
-}
-
-int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
-{
-       cmd->supported = phydev->supported;
-
-       cmd->advertising = phydev->advertising;
-
-       cmd->speed = phydev->speed;
-       cmd->duplex = phydev->duplex;
-       cmd->port = PORT_MII;
-       cmd->phy_address = phydev->addr;
-       cmd->transceiver = XCVR_EXTERNAL;
-       cmd->autoneg = phydev->autoneg;
-
-       return 0;
-}
-
-
-/* Note that this function is currently incompatible with the
- * PHYCONTROL layer.  It changes registers without regard to
- * current state.  Use at own risk
- */
-int phy_mii_ioctl(struct phy_device *phydev,
-               struct mii_ioctl_data *mii_data, int cmd)
-{
-       u16 val = mii_data->val_in;
-
-       switch (cmd) {
-       case SIOCGMIIPHY:
-               mii_data->phy_id = phydev->addr;
-               break;
-       case SIOCGMIIREG:
-               mii_data->val_out = phy_read(phydev, mii_data->reg_num);
-               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:
-                               if (val & (BMCR_RESET|BMCR_ANENABLE))
-                                       phydev->autoneg = AUTONEG_DISABLE;
-                               else
-                                       phydev->autoneg = AUTONEG_ENABLE;
-                               if ((!phydev->autoneg) && (val & BMCR_FULLDPLX))
-                                       phydev->duplex = DUPLEX_FULL;
-                               else
-                                       phydev->duplex = DUPLEX_HALF;
-                               break;
-                       case MII_ADVERTISE:
-                               phydev->advertising = val;
-                               break;
-                       default:
-                               /* do nothing */
-                               break;
-                       }
-               }
-
-               phy_write(phydev, mii_data->reg_num, val);
-               
-               if (mii_data->reg_num == MII_BMCR 
-                               && val & BMCR_RESET
-                               && phydev->drv->config_init)
-                       phydev->drv->config_init(phydev);
-               break;
-       }
-
-       return 0;
-}
-
-/* phy_start_machine:
- *
- * description: The PHY infrastructure can run a state machine
- *   which tracks whether the PHY is starting up, negotiating,
- *   etc.  This function starts the timer which tracks the state
- *   of the PHY.  If you want to be notified when the state
- *   changes, pass in the callback, otherwise, pass NULL.  If you
- *   want to maintain your own state machine, do not call this
- *   function. */
-void phy_start_machine(struct phy_device *phydev,
-               void (*handler)(struct net_device *))
-{
-       phydev->adjust_state = handler;
-
-       init_timer(&phydev->phy_timer);
-       phydev->phy_timer.function = &phy_timer;
-       phydev->phy_timer.data = (unsigned long) phydev;
-       mod_timer(&phydev->phy_timer, jiffies + HZ);
-}
-
-/* phy_stop_machine
- *
- * description: Stops the state machine timer, sets the state to
- *   UP (unless it wasn't up yet), and then frees the interrupt,
- *   if it is in use. This function must be called BEFORE
- *   phy_detach.
- */
-void phy_stop_machine(struct phy_device *phydev)
-{
-       del_timer_sync(&phydev->phy_timer);
-
-       spin_lock(&phydev->lock);
-       if (phydev->state > PHY_UP)
-               phydev->state = PHY_UP;
-       spin_unlock(&phydev->lock);
-
-       if (phydev->irq != PHY_POLL)
-               phy_stop_interrupts(phydev);
-
-       phydev->adjust_state = NULL;
-}
-
-#ifdef CONFIG_PHYCONTROL
-/* phy_error:
- *
- * Moves the PHY to the HALTED state in response to a read
- * or write error, and tells the controller the link is down.
- * Must not be called from interrupt context, or while the
- * phydev->lock is held.
- */
-void phy_error(struct phy_device *phydev)
-{
-       spin_lock(&phydev->lock);
-       phydev->state = PHY_HALTED;
-       spin_unlock(&phydev->lock);
-}
-
-/* phy_interrupt
- *
- * description: When a PHY interrupt occurs, the handler disables
- * interrupts, and schedules a work task to clear the interrupt.
- */
-static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs)
-{
-       struct phy_device *phydev = phy_dat;
-
-       /* The MDIO bus is not allowed to be written in interrupt
-        * context, so we need to disable the irq here.  A work
-        * queue will write the PHY to disable and clear the
-        * interrupt, and then reenable the irq line. */
-       disable_irq_nosync(irq);
-
-       schedule_work(&phydev->phy_queue);
-
-       return IRQ_HANDLED;
-}
-
-/* Enable the interrupts from the PHY side */
-int phy_enable_interrupts(struct phy_device *phydev)
-{
-       int err;
-
-       err = phy_clear_interrupt(phydev);
-
-       if (err < 0)
-               return err;
-
-       err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
-
-       return err;
-}
-
-/* Disable the PHY interrupts from the PHY side */
-int phy_disable_interrupts(struct phy_device *phydev)
-{
-       int err;
-
-       /* Disable PHY interrupts */
-       err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
-
-       if (err)
-               goto phy_err;
-
-       /* Clear the interrupt */
-       err = phy_clear_interrupt(phydev);
-
-       if (err)
-               goto phy_err;
-
-       return 0;
-
-phy_err:
-       phy_error(phydev);
-
-       return err;
-}
-
-/* phy_start_interrupts
- *
- * description: Request the interrupt for the given PHY.  If
- *   this fails, then we set irq to PHY_POLL.
- *   Otherwise, we enable the interrupts in the PHY.
- *   Returns 0 on success.
- *   This should only be called with a valid IRQ number.
- */
-int phy_start_interrupts(struct phy_device *phydev)
-{
-       int err = 0;
-
-       INIT_WORK(&phydev->phy_queue, phy_change, phydev);
-
-       if (request_irq(phydev->irq, phy_interrupt,
-                               SA_SHIRQ,
-                               "phy_interrupt",
-                               phydev) < 0) {
-               printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
-                               phydev->bus->name,
-                               phydev->irq);
-               phydev->irq = PHY_POLL;
-               return 0;
-       }
-
-       err = phy_enable_interrupts(phydev);
-
-       return err;
-}
-EXPORT_SYMBOL(phy_start_interrupts);
-
-int phy_stop_interrupts(struct phy_device *phydev)
-{
-       int err;
-
-       err = phy_disable_interrupts(phydev);
-
-       if (err)
-               phy_error(phydev);
-
-       free_irq(phydev->irq, phydev);
-
-       return err;
-}
-EXPORT_SYMBOL(phy_stop_interrupts);
-
-
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void phy_change(void *data)
-{
-       int err;
-       struct phy_device *phydev = data;
-
-       err = phy_disable_interrupts(phydev);
-
-       if (err)
-               goto phy_err;
-
-       spin_lock(&phydev->lock);
-       if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
-               phydev->state = PHY_CHANGELINK;
-       spin_unlock(&phydev->lock);
-
-       enable_irq(phydev->irq);
-
-       /* Reenable interrupts */
-       err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
-
-       if (err)
-               goto irq_enable_err;
-
-       return;
-
-irq_enable_err:
-       disable_irq(phydev->irq);
-phy_err:
-       phy_error(phydev);
-}
-
-/* Bring down the PHY link, and stop checking the status. */
-void phy_stop(struct phy_device *phydev)
-{
-       spin_lock(&phydev->lock);
-
-       if (PHY_HALTED == phydev->state)
-               goto out_unlock;
-
-       if (phydev->irq != PHY_POLL) {
-               /* Clear any pending interrupts */
-               phy_clear_interrupt(phydev);
-
-               /* Disable PHY Interrupts */
-               phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
-       }
-
-       phydev->state = PHY_HALTED;
-
-out_unlock:
-       spin_unlock(&phydev->lock);
-}
-
-
-/* phy_start
- *
- * description: Indicates the attached device's readiness to
- *   handle PHY-related work.  Used during startup to start the
- *   PHY, and after a call to phy_stop() to resume operation.
- *   Also used to indicate the MDIO bus has cleared an error
- *   condition.
- */
-void phy_start(struct phy_device *phydev)
-{
-       spin_lock(&phydev->lock);
-
-       switch (phydev->state) {
-               case PHY_STARTING:
-                       phydev->state = PHY_PENDING;
-                       break;
-               case PHY_READY:
-                       phydev->state = PHY_UP;
-                       break;
-               case PHY_HALTED:
-                       phydev->state = PHY_RESUMING;
-               default:
-                       break;
-       }
-       spin_unlock(&phydev->lock);
-}
-EXPORT_SYMBOL(phy_stop);
-EXPORT_SYMBOL(phy_start);
-
-/* PHY timer which handles the state machine */
-static void phy_timer(unsigned long data)
-{
-       struct phy_device *phydev = (struct phy_device *)data;
-       int needs_aneg = 0;
-       int err = 0;
-
-       spin_lock(&phydev->lock);
-
-       if (phydev->adjust_state)
-               phydev->adjust_state(phydev->attached_dev);
-
-       switch(phydev->state) {
-               case PHY_DOWN:
-               case PHY_STARTING:
-               case PHY_READY:
-               case PHY_PENDING:
-                       break;
-               case PHY_UP:
-                       needs_aneg = 1;
-
-                       phydev->link_timeout = PHY_AN_TIMEOUT;
-
-                       break;
-               case PHY_AN:
-                       /* Check if negotiation is done.  Break
-                        * if there's an error */
-                       err = phy_aneg_done(phydev);
-                       if (err < 0)
-                               break;
-
-                       /* If auto-negotiation is done, we change to
-                        * either RUNNING, or NOLINK */
-                       if (err > 0) {
-                               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;
-                                       netif_carrier_off(phydev->attached_dev);
-                               }
-
-                               phydev->adjust_link(phydev->attached_dev);
-
-                       } else if (0 == phydev->link_timeout--) {
-                               /* The counter expired, so either we
-                                * switch to forced mode, or the
-                                * magic_aneg bit exists, and we try aneg
-                                * again */
-                               if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) {
-                                       int idx;
-
-                                       /* We'll start from the
-                                        * fastest speed, and work
-                                        * our way down */
-                                       idx = phy_find_valid(0,
-                                                       phydev->supported);
-
-                                       phydev->speed = settings[idx].speed;
-                                       phydev->duplex = settings[idx].duplex;
-                                       
-                                       phydev->autoneg = AUTONEG_DISABLE;
-                                       phydev->state = PHY_FORCING;
-                                       phydev->link_timeout =
-                                               PHY_FORCE_TIMEOUT;
-
-                                       pr_info("Trying %d/%s\n",
-                                                       phydev->speed,
-                                                       DUPLEX_FULL ==
-                                                       phydev->duplex ?
-                                                       "FULL" : "HALF");
-                               }
-
-                               needs_aneg = 1;
-                       }
-                       break;
-               case PHY_NOLINK:
-                       err = phy_read_status(phydev);
-
-                       if (err)
-                               break;
-
-                       if (phydev->link) {
-                               phydev->state = PHY_RUNNING;
-                               netif_carrier_on(phydev->attached_dev);
-                               phydev->adjust_link(phydev->attached_dev);
-                       }
-                       break;
-               case PHY_FORCING:
-                       err = phy_read_status(phydev);
-
-                       if (err)
-                               break;
-
-                       if (phydev->link) {
-                               phydev->state = PHY_RUNNING;
-                               netif_carrier_on(phydev->attached_dev);
-                       } else {
-                               if (0 == phydev->link_timeout--) {
-                                       phy_force_reduction(phydev);
-                                       needs_aneg = 1;
-                               }
-                       }
-
-                       phydev->adjust_link(phydev->attached_dev);
-                       break;
-               case PHY_RUNNING:
-                       /* Only register a CHANGE if we are
-                        * polling */
-                       if (PHY_POLL == phydev->irq)
-                               phydev->state = PHY_CHANGELINK;
-                       break;
-               case PHY_CHANGELINK:
-                       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;
-                               netif_carrier_off(phydev->attached_dev);
-                       }
-
-                       phydev->adjust_link(phydev->attached_dev);
-
-                       if (PHY_POLL != phydev->irq)
-                               err = phy_config_interrupt(phydev,
-                                               PHY_INTERRUPT_ENABLED);
-                       break;
-               case PHY_HALTED:
-                       if (phydev->link) {
-                               phydev->link = 0;
-                               netif_carrier_off(phydev->attached_dev);
-                               phydev->adjust_link(phydev->attached_dev);
-                       }
-                       break;
-               case PHY_RESUMING:
-
-                       err = phy_clear_interrupt(phydev);
-
-                       if (err)
-                               break;
-
-                       err = phy_config_interrupt(phydev,
-                                       PHY_INTERRUPT_ENABLED);
-
-                       if (err)
-                               break;
-
-                       if (AUTONEG_ENABLE == phydev->autoneg) {
-                               err = phy_aneg_done(phydev);
-                               if (err < 0)
-                                       break;
-
-                               /* err > 0 if AN is done.
-                                * Otherwise, it's 0, and we're
-                                * still waiting for AN */
-                               if (err > 0) {
-                                       phydev->state = PHY_RUNNING;
-                               } else {
-                                       phydev->state = PHY_AN;
-                                       phydev->link_timeout = PHY_AN_TIMEOUT;
-                               }
-                       } else
-                               phydev->state = PHY_RUNNING;
-                       break;
-       }
-
-       spin_unlock(&phydev->lock);
-
-       if (needs_aneg)
-               err = phy_start_aneg(phydev);
-
-       if (err < 0)
-               phy_error(phydev);
-
-       mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
-}
-
-#endif /* CONFIG_PHYCONTROL */
index f0595af..c111383 100644 (file)
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+static int genphy_config_init(struct phy_device *phydev);
+
+static struct phy_driver genphy_driver = {
+       .phy_id         = 0xffffffff,
+       .phy_id_mask    = 0xffffffff,
+       .name           = "Generic PHY",
+       .config_init    = genphy_config_init,
+       .features       = 0,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .driver =       {.owner = THIS_MODULE, },
+};
+
 /* get_phy_device
  *
  * description: Reads the ID registers of the PHY at addr on the
@@ -656,27 +669,32 @@ void phy_driver_unregister(struct phy_driver *drv)
 }
 EXPORT_SYMBOL(phy_driver_unregister);
 
-static struct phy_driver genphy_driver = {
-       .phy_id         = 0xffffffff,
-       .phy_id_mask    = 0xffffffff,
-       .name           = "Generic PHY",
-       .config_init    = genphy_config_init,
-       .features       = 0,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .driver =       {.owner = THIS_MODULE, },
-};
 
-static int __init genphy_init(void)
+static int __init phy_init(void)
 {
-       return phy_driver_register(&genphy_driver);
+       int rc;
+       extern int mdio_bus_init(void);
+
+       rc = phy_driver_register(&genphy_driver);
+       if (rc)
+               goto out;
+
+       rc = mdio_bus_init();
+       if (rc)
+               goto out_unreg;
 
+       return 0;
+
+out_unreg:
+       phy_driver_unregister(&genphy_driver);
+out:
+       return rc;
 }
 
-static void __exit genphy_exit(void)
+static void __exit phy_exit(void)
 {
        phy_driver_unregister(&genphy_driver);
 }
 
-module_init(genphy_init);
-module_exit(genphy_exit);
+module_init(phy_init);
+module_exit(phy_exit);
index 3404804..72cb67b 100644 (file)
@@ -374,5 +374,4 @@ int phy_start_interrupts(struct phy_device *phydev);
 void phy_print_status(struct phy_device *phydev);
 
 extern struct bus_type mdio_bus_type;
-extern struct phy_driver genphy_driver;
 #endif /* __PHY_H */