diff options
| author | Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | 2010-03-09 09:17:42 +0000 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-03-16 21:23:42 -0700 | 
| commit | abf35df21513c51d7761c41fa6d3b819cdf4103e (patch) | |
| tree | 3152b04190035149aba67936ef0cff81cc6af3a0 | |
| parent | 23606cf5d1192c2b17912cb2ef6e62f9b11de133 (diff) | |
| download | olio-linux-3.10-abf35df21513c51d7761c41fa6d3b819cdf4103e.tar.xz olio-linux-3.10-abf35df21513c51d7761c41fa6d3b819cdf4103e.zip  | |
NET: Support clause 45 MDIO commands at the MDIO bus level
IEEE 802.3ae clause 45 specifies a somewhat modified MDIO protocol
for use by 10GIGE phys. The main change is a 21 bit address split into
a 5 bit device ID and a 16 bit register offset. The definition is designed
so that normal and extended devices can run on the same MDIO bus.
Extend mdio-bitbang to do the new protocol. At the MDIO bus level the
protocol is requested by or'ing MII_ADDR_C45 into the register offset.
Make phy_read/phy_write/etc pass a full 32 bit register offset.
This does not attempt to make the phy layer support C45 style PHYs, just
to provide the MDIO bus support.
Tested against a Broadcom 10GE phy with ID 0x206034, and several
Broadcom 10/100/1000 Phys in normal mode.
Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/phy/mdio-bitbang.c | 60 | ||||
| -rw-r--r-- | drivers/net/phy/mdio_bus.c | 4 | ||||
| -rw-r--r-- | include/linux/phy.h | 12 | 
3 files changed, 61 insertions, 15 deletions
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index 2576055b350..0ff06617a4a 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -23,8 +23,13 @@  #include <linux/types.h>  #include <linux/delay.h> -#define MDIO_READ 1 -#define MDIO_WRITE 0 +#define MDIO_READ 2 +#define MDIO_WRITE 1 + +#define MDIO_C45 (1<<15) +#define MDIO_C45_ADDR (MDIO_C45 | 0) +#define MDIO_C45_READ (MDIO_C45 | 3) +#define MDIO_C45_WRITE (MDIO_C45 | 1)  #define MDIO_SETUP_TIME 10  #define MDIO_HOLD_TIME 10 @@ -90,7 +95,7 @@ static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)  /* Utility to send the preamble, address, and   * register (common to read and write).   */ -static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg) +static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg)  {  	const struct mdiobb_ops *ops = ctrl->ops;  	int i; @@ -109,23 +114,56 @@ static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg)  	for (i = 0; i < 32; i++)  		mdiobb_send_bit(ctrl, 1); -	/* send the start bit (01) and the read opcode (10) or write (10) */ +	/* send the start bit (01) and the read opcode (10) or write (10). +	   Clause 45 operation uses 00 for the start and 11, 10 for +	   read/write */  	mdiobb_send_bit(ctrl, 0); -	mdiobb_send_bit(ctrl, 1); -	mdiobb_send_bit(ctrl, read); -	mdiobb_send_bit(ctrl, !read); +	if (op & MDIO_C45) +		mdiobb_send_bit(ctrl, 0); +	else +		mdiobb_send_bit(ctrl, 1); +	mdiobb_send_bit(ctrl, (op >> 1) & 1); +	mdiobb_send_bit(ctrl, (op >> 0) & 1);  	mdiobb_send_num(ctrl, phy, 5);  	mdiobb_send_num(ctrl, reg, 5);  } +/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the +   lower 16 bits of the 21 bit address. This transfer is done identically to a +   MDIO_WRITE except for a different code. To enable clause 45 mode or +   MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices +   can exist on the same bus. Normal devices should ignore the MDIO_ADDR +   phase. */ +static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) +{ +	unsigned int dev_addr = (addr >> 16) & 0x1F; +	unsigned int reg = addr & 0xFFFF; +	mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); + +	/* send the turnaround (10) */ +	mdiobb_send_bit(ctrl, 1); +	mdiobb_send_bit(ctrl, 0); + +	mdiobb_send_num(ctrl, reg, 16); + +	ctrl->ops->set_mdio_dir(ctrl, 0); +	mdiobb_get_bit(ctrl); + +	return dev_addr; +}  static int mdiobb_read(struct mii_bus *bus, int phy, int reg)  {  	struct mdiobb_ctrl *ctrl = bus->priv;  	int ret, i; -	mdiobb_cmd(ctrl, MDIO_READ, phy, reg); +	if (reg & MII_ADDR_C45) { +		reg = mdiobb_cmd_addr(ctrl, phy, reg); +		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); +	} else +		mdiobb_cmd(ctrl, MDIO_READ, phy, reg); +  	ctrl->ops->set_mdio_dir(ctrl, 0);  	/* check the turnaround bit: the PHY should be driving it to zero */ @@ -148,7 +186,11 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)  {  	struct mdiobb_ctrl *ctrl = bus->priv; -	mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); +	if (reg & MII_ADDR_C45) { +		reg = mdiobb_cmd_addr(ctrl, phy, reg); +		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); +	} else +		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);  	/* send the turnaround (10) */  	mdiobb_send_bit(ctrl, 1); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index e17b70291bb..6a6b8199a0d 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -208,7 +208,7 @@ EXPORT_SYMBOL(mdiobus_scan);   * because the bus read/write functions may wait for an interrupt   * to conclude the operation.   */ -int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum) +int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)  {  	int retval; @@ -233,7 +233,7 @@ EXPORT_SYMBOL(mdiobus_read);   * because the bus read/write functions may wait for an interrupt   * to conclude the operation.   */ -int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val) +int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)  {  	int err; diff --git a/include/linux/phy.h b/include/linux/phy.h index 14d7fdf6a90..d9bce4b526b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -81,6 +81,10 @@ typedef enum {   */  #define MII_BUS_ID_SIZE	(20 - 3) +/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit +   IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */ +#define MII_ADDR_C45 (1<<30) +  /*   * The Bus class for PHYs.  Devices which provide access to   * PHYs should register using this structure @@ -127,8 +131,8 @@ int mdiobus_register(struct mii_bus *bus);  void mdiobus_unregister(struct mii_bus *bus);  void mdiobus_free(struct mii_bus *bus);  struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); -int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum); -int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val); +int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); +int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);  #define PHY_INTERRUPT_DISABLED	0x0 @@ -422,7 +426,7 @@ struct phy_fixup {   * because the bus read/write functions may wait for an interrupt   * to conclude the operation.   */ -static inline int phy_read(struct phy_device *phydev, u16 regnum) +static inline int phy_read(struct phy_device *phydev, u32 regnum)  {  	return mdiobus_read(phydev->bus, phydev->addr, regnum);  } @@ -437,7 +441,7 @@ static inline int phy_read(struct phy_device *phydev, u16 regnum)   * because the bus read/write functions may wait for an interrupt   * to conclude the operation.   */ -static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val) +static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)  {  	return mdiobus_write(phydev->bus, phydev->addr, regnum, val);  }  |