• Trent Piepho's avatar
    gianfar: Fix race in TBI/SerDes configuration · c132419e
    Trent Piepho authored
    The init_phy() function attaches to the PHY, then configures the
    SerDes<->TBI link (in SGMII mode).  The TBI is on the MDIO bus with the PHY
    (sort of) and is accessed via the gianfar's MDIO registers, using the
    functions gfar_local_mdio_read/write(), which don't do any locking.
    
    The previously attached PHY will start a work-queue on a timer, and
    probably an irq handler as well, which will talk to the PHY and thus use
    the MDIO bus.  This uses phy_read/write(), which have locking, but not
    against the gfar_local_mdio versions.
    
    The result is that PHY code will try to use the MDIO bus at the same time
    as the SerDes setup code, corrupting the transfers.
    
    Setting up the SerDes before attaching to the PHY will insure that there is
    no race between the SerDes code and *our* PHY, but doesn't fix everything.
    Typically the PHYs for all gianfar devices are on the same MDIO bus, which
    is associated with the first gianfar device.  This means that the first
    gianfar's SerDes code could corrupt the MDIO transfers for a different
    gianfar's PHY.
    
    The lock used by phy_read/write() is contained in the mii_bus structure,
    which is pointed to by the PHY.  This is difficult to access from the
    gianfar drivers, as there is no link between a gianfar device and the
    mii_bus which shares the same MDIO registers.  As far as the device layer
    and drivers are concerned they are two unrelated devices (which happen to
    share registers).
    
    Generally all gianfar devices' PHYs will be on the bus associated with the
    first gianfar.  But this might not be the case, so simply locking the
    gianfar's PHY's mii bus might not lock the mii bus that the SerDes setup
    code is going to use.
    
    We solve this by having the code that creates the gianfar platform device
    look in the device tree for an mdio device that shares the gianfar's
    registers.  If one is found the ID of its platform device is saved in the
    gianfar's platform data.
    
    A new function in the gianfar mii code, gfar_get_miibus(), can use the bus
    ID to search through the platform devices for a gianfar_mdio device with
    the right ID.  The platform device's driver data is the mii_bus structure,
    which the SerDes setup code can use to lock the current bus.
    Signed-off-by: default avatarTrent Piepho <tpiepho@freescale.com>
    CC: Andy Fleming <afleming@freescale.com>
    Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
    c132419e
gianfar.c 56.3 KB