[RFC PATCH 1/4] PHY Abstraction Layer III (now with more splitiness)

Andy Fleming afleming at freescale.com
Thu Jul 28 04:01:40 EST 2005


On Jul 25, 2005, at 16:06, Francois Romieu wrote:

[snip]
>
>> +config DAVICOM_PHY
>> +    bool "Drivers for Davicom PHYs"
>> +    depends on PHYLIB
>> +    ---help---
>> +      Currently supports dm9161e and dm9131
>>
> [snip]


Yeah, I resisted splitting the patch up for this reason.  Suffice it  
to say, you have to apply patch #2 to not break everything.   
Splitting the PHY driver code from the PHY layer is just for  
"convenience"


>> +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)


I think we have to agree to disagree here.  I could be convinced, but  
I'm partial to using NULL explicitly.


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


Actually, KERN_SOMETHING would muck up the line, and make it look  
like this:

phy0:0: Link is Up<3> - 1000/Full

That's why it's like that.


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


Depends on the macro.  :)  I'm not keen on writing it, but I would  
support one that:

a) works
b) Isn't uglier than the current solution.  :)


>> +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 ?


Well....  I think it falls into the gray area.  It's searching until  
it finds something, which implies "while" to me.  Really it's more of  
a while...until.  Of course, a for loop could be used, but I often  
worry about using a for loop's iterator variable outside of the  
loop.  I will change to ARRAY_SIZE, though.


>
>
>> +
>> +    return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
>>
>
> Ok (dunno if "idx % MAX_NUM_SETTINGS" is more idiomatic or not).


That would be completely different.  The current code makes sure  
that, if no valid match was found, the last value in the array is  
returned.  Using % would result in the first value being returned.  I  
was defaulting to the lowest setting.


>> +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)
>         ...


I did a cursory search, and didn't find any other drivers which use  
this method.  Which is the method preferred in Linux?


>> +        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".


Failing to request the IRQ does not result in failure of the  
function.  It falls back to polling, instead.

However, it can fail if phy_enable_interrupts() fails, which would  
happen if a hardware issue occurred.


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


I went looking for it, and found it in fs/cifs/misc.c.  I'm hesitant  
to link to a function defined in the filesystem code just to save 1  
line of code


I agree with all the other suggestions, and will implement them.



More information about the Linuxppc-embedded mailing list