Hi guys,

Normally, when you access an Ethernet PHY through an MDIO bus, you specify a
5-bit PHY address that selects one of the PHYs attached to the bus, and a 5-bit
register address that addresses a register inside that PHY.

The ADM6996FC and ADM6996M switch chips occupy this full address space: there
are 1024 register addresses spanning this whole space.

But the Linux PHY layer is built on the assumption that the 32 PHY addresses
address distinct, independent devices. It will try to enumerate all attached
PHYs, and is happy to attach a Generic PHY driver inside the address space of
the ADM6996 chip, for instance.

So I'm wondering what is the best way to handle this odd case elegantly, and
prevent corruption of the ADM6996 registers. I can see several ways to handle
stuff, but I'm not sure what is the best way that will work for everybody, or a
least the great majority.

The hardware I'm developing on is based on the TI TNETD7300AZDW, an AR7 device
with two Ethernet MACs. I think they share the MDIO bus. On my device, the
second Ethernet MAC appears not to be connected to anything.

Using the original ADM6996 driver as it is in backfire, this is the kernel log
output:

cpmac-mii: probed
eth%d: ADM6996 PHY driver attached.
cpmac: device eth0 (regs: 08612800, irq: 41, phy: 1:00, mac: 00:17:9a:d6:00:00)
eth%d: ADM6996 PHY driver attached.
cpmac: device eth1 (regs: 08610000, irq: 27, phy: 1:1f, mac: 00:17:9a:d6:00:00)
PHY: 1:00 - Link is Up - 100/Full

(It seems the eth* device is not yet fully initialised when the PHY is
initialised. This might explain the %d.)

The problem here is that both MACs are now attached to the switch chip. But it's
the same switch chip. I simply do not touch eth1 as it is not connected anyway.
But you can get the switch chip in some pretty strange states if you start
mucking about with both eth0 and eth1.

To fix it, the ADM6996 driver could simply only provide config_aneg() and
read_status() to any request for a PHY with address 1 through 31. This is how I
currently chose to handle it.

Alternatively, if you change the _fixup routine of the ADM6996 driver to only
match PHY address 0, which initially seems a good way to fix it, you get a
different problem:

adm6996_fixup(struct phy_device *dev)
{
        if (dev->addr != 0)
                return 0;
...

Now the log reads:

cpmac-mii: probed
eth%d: ADM6996 PHY driver attached.
cpmac: device eth0 (regs: 08612800, irq: 41, phy: 1:00, mac: 00:17:9a:d6:00:00)
cpmac: device eth1 (regs: 08610000, irq: 27, phy: 1:1f, mac: 00:17:9a:d6:00:00)
PHY: 1:00 - Link is Up - 100/Full

Note how it still says phy: 1:1f for eth1. And after adding some debugging
statements to the cpmac driver, it turns out it has attached a Generic PHY to
1:1f. This generic driver will happily poke around in standardised registers on
the PHY bus which map to non-standard registers in the ADM6996 and have the
potential to really screw stuff up.

I couldn't find a way to have _fixup() properly prevent the kernel from binding
a Generic PHY driver to other PHY addresses.

I noticed the phy_map array in struct mii_bus, and how it is used in
phy_device_register(). This led me to write the following in adm6996_probe:

adm6996_probe(struct phy_device *pdev)
{
        int i;
        if (pdev->addr == 0) {
                // Place us on addresses 1-31 as well
                for (i = 1; i < 32; i++) {
                        if (pdev->bus->phy_map[i] == NULL)
                                pdev->bus->phy_map[i] = pdev;
                        else
                                pr_warning ("ADM6996: other PHY found on "
                                        "conflicting address %d!\n", i);
                }
        }
...

Now the log reads:

cpmac-mii: probed
eth%d: ADM6996 PHY driver attached.
cpmac: device eth0 (regs: 08612800, irq: 41, phy: 1:00, mac: 00:17:9a:d6:00:00)
PHY 1:1f not found
eth%d: Could not attach to PHY
PHY: 1:00 - Link is Up - 100/Full


eth1 is never initialised. This is fine for me: it is not connected anyway.

But on other hardware, it might make more sense to offer something akin to a
fixed PHY to the Ethernet MAC, simulating a PHY. Unfortunately fixed.c
implements a Fixed MDIO bus rather than a single PHY. I'm not sure how to
interface to that.

So, do you have any ideas on the best way to properly handle this PHY that looks
like 32 PHYs?

Thanks,

Peter.

-- 
I use the GNU Privacy Guard (GnuPG) in combination with Enigmail.
You can send me encrypted mail if you want some privacy.
My key is available at http://wwwhome.cs.utwente.nl/~lebbing/pubkey.txt
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to