Andy Fleming <afleming at freescale.com> :
> This patch contains the PHY layer itself, no phy drivers
[...]
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> new file mode 100644
> --- /dev/null
> +++ b/drivers/net/phy/Kconfig
[...]
> +config MARVELL_PHY
> +     bool "Drivers for Marvell PHYs"
> +     depends on PHYLIB
> +     ---help---
> +       Currently has a driver for the 88E1011S
> +     
> +config DAVICOM_PHY
> +     bool "Drivers for Davicom PHYs"
> +     depends on PHYLIB
> +     ---help---
> +       Currently supports dm9161e and dm9131
[snip]

They try to escape...

[...]
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> new file mode 100644
> --- /dev/null
> +++ b/drivers/net/phy/Makefile
> @@ -0,0 +1,9 @@
> +# Makefile for Linux PHY drivers
> +
> +obj-$(CONFIG_PHYLIB) += 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

...and they are not alone. :o)

> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/net/phy/mdio_bus.c
> @@ -0,0 +1,175 @@
[...]
> +int mdiobus_register(struct mii_bus *bus)
> +{
> +     int i;
> +     int err = 0;
> +
> +     spin_lock_init(&bus->mdio_lock);
> +
> +     if (NULL == bus || NULL == bus->name ||
> +                     NULL == bus->read ||
> +                     NULL == bus->write)

Be spartan:
        if (!bus || !bus->name || !bus->read || !bus->write)

> +             return -EINVAL;
> +
> +     if (bus->reset)
> +             bus->reset(bus);
> +
> +     for (i=0; i < PHY_MAX_ADDR; i++) {

        for (i = 0; ...

> +             struct phy_device *phydev;
> +
> +             phydev = get_phy_device(bus, i);
> +
> +             /* There's a PHY at this address
> +              * We need to set:
> +              * 1) IRQ
> +              * 2) bus_id
> +              * 3) parent
> +              * 4) bus
> +              * 5) mii_bus
> +              * And, we need to register it */
> +             if (phydev) {
> +                     phydev->irq = bus->irq[i];
> +
> +                     phydev->dev.parent = bus->dev;
> +
> +                     phydev->dev.bus = &mdio_bus_type;
> +
> +                     phydev->bus = bus;
> +
> +                     sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, 

Imho you are going a bit too far with empty lines. Not a real issue.

> i);

Something decided to wrap the lines after you did the patch. It appears
several times in the patch (+ extra tabs/spaces at the end of the lines:
there are plenty of nice colorised editors around).

> +
> +                     err = device_register(&phydev->dev);
> +
> +                     if (err)
> +                             printk("phy %d did not register (%d)\n",
> +                                             i, err);

Missing KERN_SOMETHING in the printk.

> +
> +             /* If get_phy_device returned NULL, it may be
> +              * because an error occurred.  If so, we return
> +              * that error */
> +             } else if (errno)
> +                     return errno;

I'd rather use ERR_PTR/PTR_ERR/IS_ERR + goto in the first place
(then the previous printk will fit on a single line).

> +
> +             bus->phy_map[i] = phydev;
> +     }
> +
> +     pr_info("%s: probed\n", bus->name);
> +
> +     return err;
> +}
> +EXPORT_SYMBOL(mdiobus_register);
> +
> +void mdiobus_unregister(struct mii_bus *bus)
> +{
> +     int i;
> +
> +     for (i=0; i < PHY_MAX_ADDR; i++)

for( i = 0, ... + missing brace.

[...]
> +static int mdio_bus_suspend(struct device * dev, u32 state)
> +{
> +     int ret = 0;
> +
> +     if (dev->driver && dev->driver->suspend) {
> +             ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
> +             if (ret == 0)
> +                     ret = dev->driver->suspend(dev, state, 
> SUSPEND_SAVE_STATE);
> +             if (ret == 0)
> +                     ret = dev->driver->suspend(dev, state, 
> SUSPEND_POWER_DOWN);
> +     }

Copy/paste abuse:
        struct device_driver *drv = dev->driver;

(appears in several functions)

[...]
> +struct bus_type mdio_bus_type = {
> +     .name   = "mdio_bus",
> +     .match  = mdio_bus_match,
> +     .suspend= mdio_bus_suspend,
               ^^

[...]
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/net/phy/phy.c
[...]
> +int phy_read(struct phy_device *phydev, u16 regnum);
> +int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
> +void phy_change(void *data);
> +void phy_timer(unsigned long data);

phy_read and phy_write do not need to be forward-declared.
Not sure if it is possible for phy_{change/timer} as well.

> +
> +/* 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,

Missing KERN_SOMETHING in the printk.

[...]
> +static inline int phy_aneg_done(struct phy_device *phydev)
> +{
> +     int retval;
> +
> +     retval = phy_read(phydev, MII_BMSR);
> +
> +     if (retval < 0)
> +             return retval;
> +
> +     return retval & BMSR_ANEGCOMPLETE;

Please use a ternary operator.

> +}
> +
> +/* 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 = 0;

Unneeded initialization.

> +
> +     spin_lock(&phydev->lock);
> +
> +     if (AUTONEG_DISABLE == phydev->autoneg)
> +             phy_sanitize_settings(phydev);
> +
> +     err = phydev->drv->config_aneg(phydev);
> +
> +     if (err < 0)
> +             return err;

The lock should be released. Add a '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 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,
> +     },
> +};

Would you veto some macro to initialise this array ?

> +
> +#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))

The kernel provides ARRAY_SIZE

[...]
> +static inline int phy_find_setting(int speed, int duplex)
> +{
> +     int idx = 0;
> +
> +     while (idx < MAX_NUM_SETTINGS &&
> +                     (settings[idx].speed != speed ||
> +                     settings[idx].duplex != duplex))
> +             idx++;

"for" loop in disguise ?

> +
> +     return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;

Ok (dunno if "idx % MAX_NUM_SETTINGS" is more idiomatic or not).

[...]
> +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) {

Please, don't do that :o(

        err = request_irq(phydev->irq, phy_interrupt, SA_SHIRQ,
                          "phy_interrupt", phydev);
        if (err < 0)
                ...

> +             printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
> +                             phydev->bus->name,
> +                             phydev->irq);
> +             phydev->irq = PHY_POLL;
> +             return 0;

The description of the function says "Returns 0 on success".

[...]
> +/* 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) {
> +             spin_unlock(&phydev->lock);
> +             return;
> +     }

"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;
> +
> +     spin_unlock(&phydev->lock);
> +}
[...]
> +struct phy_device * get_phy_device(struct mii_bus *bus, uint addr)
> +{

uint ?

> +     int phy_reg;
> +     u32 phy_id;
> +     struct phy_device *dev = NULL;
> +
> +     errno = 0;

A bit ugly.

> +
> +     /* Grab the bits from PHYIR1, and put them
> +      * in the upper half */
> +     phy_reg = bus->read(bus, addr, MII_PHYSID1);
> +
> +     if (phy_reg < 0) {
> +             errno = phy_reg;
> +             return NULL;

                dev = ERR_PTR(phy_reg);
                goto out;
                ...
> +     }
> +
> +     phy_id = (phy_reg & 0xffff) << 16;
> +
> +     /* Grab the bits from PHYIR2, and put them in the lower half */
> +     phy_reg = bus->read(bus, addr, MII_PHYSID2);
> +
> +     if (phy_reg < 0) {
> +             errno = phy_reg;
> +             return NULL;
> +     }
> +
> +     phy_id |= (phy_reg & 0xffff);
> +
> +     /* If the phy_id is all Fs, there is no device there */
> +     if (0xffffffff == phy_id)
> +             return NULL;
> +
> +     /* Otherwise, we allocate the device, and initialize the
> +      * default values */
> +     dev = kmalloc(sizeof(*dev), GFP_KERNEL);
> +
> +     if (NULL == dev) {
> +             errno = -ENOMEM;
> +             return NULL;
> +     }
> +
> +     memset(dev, 0, sizeof(*dev));

The kernel provides kcalloc.

[...]
> +static int phy_compare_id(struct device *dev, void *data)
> +{
> +     const char *name = data;
> +
> +     if (strcmp(name, dev->bus_id) == 0)
> +             return 1;
> +     return 0;

Ternary operator ?

> +}
> +
> +struct phy_device *phy_attach(struct net_device *dev,
> +             const char *phy_id, u32 flags)
> +{
> +     struct phy_device *phydev = NULL;

Useless initialization.

> +     struct bus_type *bus = &mdio_bus_type;
> +     struct device *d;
> +
> +     /* Search the list of PHY devices on the mdio bus for the
> +      * PHY with the requested name */
> +     d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);
> +
> +     if (d) {
> +             phydev = to_phy_device(d);
> +     } else {
> +             printk(KERN_ERR "%s not found\n", phy_id);
> +             errno = -ENODEV;
> +             return NULL;
> +     }
> +
> +     /* Assume that if there is no driver, that it doesn't
> +      * exist, and we should use the genphy driver. */
> +     if (NULL == phydev->dev.driver) {
> +             int err;
> +             down_write(&phydev->dev.bus->subsys.rwsem);
> +             phydev->dev.driver = &genphy_driver.driver;
> +
> +             err = phydev->dev.driver->probe(&phydev->dev);

Would it be possible to s/phydev->dev/d/ ?

--
Ueimor

Reply via email to