mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
![Trent Piepho](/assets/img/avatar_default.png)
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: Trent Piepho <tpiepho@freescale.com> CC: Andy Fleming <afleming@freescale.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
52 lines
1.8 KiB
C
52 lines
1.8 KiB
C
/*
|
|
* drivers/net/gianfar_mii.h
|
|
*
|
|
* Gianfar Ethernet Driver -- MII Management Bus Implementation
|
|
* Driver for the MDIO bus controller in the Gianfar register space
|
|
*
|
|
* Author: Andy Fleming
|
|
* Maintainer: Kumar Gala
|
|
*
|
|
* Copyright (c) 2002-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.
|
|
*
|
|
*/
|
|
#ifndef __GIANFAR_MII_H
|
|
#define __GIANFAR_MII_H
|
|
|
|
struct gfar_private; /* forward ref */
|
|
|
|
#define MIIMIND_BUSY 0x00000001
|
|
#define MIIMIND_NOTVALID 0x00000004
|
|
|
|
#define MII_READ_COMMAND 0x00000001
|
|
|
|
#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \
|
|
| SUPPORTED_10baseT_Full \
|
|
| SUPPORTED_100baseT_Half \
|
|
| SUPPORTED_100baseT_Full \
|
|
| SUPPORTED_Autoneg \
|
|
| SUPPORTED_MII)
|
|
|
|
struct gfar_mii {
|
|
u32 miimcfg; /* 0x.520 - MII Management Config Register */
|
|
u32 miimcom; /* 0x.524 - MII Management Command Register */
|
|
u32 miimadd; /* 0x.528 - MII Management Address Register */
|
|
u32 miimcon; /* 0x.52c - MII Management Control Register */
|
|
u32 miimstat; /* 0x.530 - MII Management Status Register */
|
|
u32 miimind; /* 0x.534 - MII Management Indicator Register */
|
|
};
|
|
|
|
int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
|
|
int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
|
|
int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
|
|
int regnum, u16 value);
|
|
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
|
|
struct mii_bus *gfar_get_miibus(const struct gfar_private *priv);
|
|
int __init gfar_mdio_init(void);
|
|
void gfar_mdio_exit(void);
|
|
#endif /* GIANFAR_PHY_H */
|