diff options
author | Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | 2010-03-09 04:17:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-17 00:23:42 -0400 |
commit | abf35df21513c51d7761c41fa6d3b819cdf4103e (patch) | |
tree | 3152b04190035149aba67936ef0cff81cc6af3a0 | |
parent | 23606cf5d1192c2b17912cb2ef6e62f9b11de133 (diff) |
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 2576055b350b..0ff06617a4ab 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c | |||
@@ -23,8 +23,13 @@ | |||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | 25 | ||
26 | #define MDIO_READ 1 | 26 | #define MDIO_READ 2 |
27 | #define MDIO_WRITE 0 | 27 | #define MDIO_WRITE 1 |
28 | |||
29 | #define MDIO_C45 (1<<15) | ||
30 | #define MDIO_C45_ADDR (MDIO_C45 | 0) | ||
31 | #define MDIO_C45_READ (MDIO_C45 | 3) | ||
32 | #define MDIO_C45_WRITE (MDIO_C45 | 1) | ||
28 | 33 | ||
29 | #define MDIO_SETUP_TIME 10 | 34 | #define MDIO_SETUP_TIME 10 |
30 | #define MDIO_HOLD_TIME 10 | 35 | #define MDIO_HOLD_TIME 10 |
@@ -90,7 +95,7 @@ static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) | |||
90 | /* Utility to send the preamble, address, and | 95 | /* Utility to send the preamble, address, and |
91 | * register (common to read and write). | 96 | * register (common to read and write). |
92 | */ | 97 | */ |
93 | static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg) | 98 | static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) |
94 | { | 99 | { |
95 | const struct mdiobb_ops *ops = ctrl->ops; | 100 | const struct mdiobb_ops *ops = ctrl->ops; |
96 | int i; | 101 | int i; |
@@ -109,23 +114,56 @@ static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg) | |||
109 | for (i = 0; i < 32; i++) | 114 | for (i = 0; i < 32; i++) |
110 | mdiobb_send_bit(ctrl, 1); | 115 | mdiobb_send_bit(ctrl, 1); |
111 | 116 | ||
112 | /* send the start bit (01) and the read opcode (10) or write (10) */ | 117 | /* send the start bit (01) and the read opcode (10) or write (10). |
118 | Clause 45 operation uses 00 for the start and 11, 10 for | ||
119 | read/write */ | ||
113 | mdiobb_send_bit(ctrl, 0); | 120 | mdiobb_send_bit(ctrl, 0); |
114 | mdiobb_send_bit(ctrl, 1); | 121 | if (op & MDIO_C45) |
115 | mdiobb_send_bit(ctrl, read); | 122 | mdiobb_send_bit(ctrl, 0); |
116 | mdiobb_send_bit(ctrl, !read); | 123 | else |
124 | mdiobb_send_bit(ctrl, 1); | ||
125 | mdiobb_send_bit(ctrl, (op >> 1) & 1); | ||
126 | mdiobb_send_bit(ctrl, (op >> 0) & 1); | ||
117 | 127 | ||
118 | mdiobb_send_num(ctrl, phy, 5); | 128 | mdiobb_send_num(ctrl, phy, 5); |
119 | mdiobb_send_num(ctrl, reg, 5); | 129 | mdiobb_send_num(ctrl, reg, 5); |
120 | } | 130 | } |
121 | 131 | ||
132 | /* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the | ||
133 | lower 16 bits of the 21 bit address. This transfer is done identically to a | ||
134 | MDIO_WRITE except for a different code. To enable clause 45 mode or | ||
135 | MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices | ||
136 | can exist on the same bus. Normal devices should ignore the MDIO_ADDR | ||
137 | phase. */ | ||
138 | static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) | ||
139 | { | ||
140 | unsigned int dev_addr = (addr >> 16) & 0x1F; | ||
141 | unsigned int reg = addr & 0xFFFF; | ||
142 | mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); | ||
143 | |||
144 | /* send the turnaround (10) */ | ||
145 | mdiobb_send_bit(ctrl, 1); | ||
146 | mdiobb_send_bit(ctrl, 0); | ||
147 | |||
148 | mdiobb_send_num(ctrl, reg, 16); | ||
149 | |||
150 | ctrl->ops->set_mdio_dir(ctrl, 0); | ||
151 | mdiobb_get_bit(ctrl); | ||
152 | |||
153 | return dev_addr; | ||
154 | } | ||
122 | 155 | ||
123 | static int mdiobb_read(struct mii_bus *bus, int phy, int reg) | 156 | static int mdiobb_read(struct mii_bus *bus, int phy, int reg) |
124 | { | 157 | { |
125 | struct mdiobb_ctrl *ctrl = bus->priv; | 158 | struct mdiobb_ctrl *ctrl = bus->priv; |
126 | int ret, i; | 159 | int ret, i; |
127 | 160 | ||
128 | mdiobb_cmd(ctrl, MDIO_READ, phy, reg); | 161 | if (reg & MII_ADDR_C45) { |
162 | reg = mdiobb_cmd_addr(ctrl, phy, reg); | ||
163 | mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); | ||
164 | } else | ||
165 | mdiobb_cmd(ctrl, MDIO_READ, phy, reg); | ||
166 | |||
129 | ctrl->ops->set_mdio_dir(ctrl, 0); | 167 | ctrl->ops->set_mdio_dir(ctrl, 0); |
130 | 168 | ||
131 | /* check the turnaround bit: the PHY should be driving it to zero */ | 169 | /* 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) | |||
148 | { | 186 | { |
149 | struct mdiobb_ctrl *ctrl = bus->priv; | 187 | struct mdiobb_ctrl *ctrl = bus->priv; |
150 | 188 | ||
151 | mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); | 189 | if (reg & MII_ADDR_C45) { |
190 | reg = mdiobb_cmd_addr(ctrl, phy, reg); | ||
191 | mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); | ||
192 | } else | ||
193 | mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); | ||
152 | 194 | ||
153 | /* send the turnaround (10) */ | 195 | /* send the turnaround (10) */ |
154 | mdiobb_send_bit(ctrl, 1); | 196 | mdiobb_send_bit(ctrl, 1); |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index e17b70291bbc..6a6b8199a0d6 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -208,7 +208,7 @@ EXPORT_SYMBOL(mdiobus_scan); | |||
208 | * because the bus read/write functions may wait for an interrupt | 208 | * because the bus read/write functions may wait for an interrupt |
209 | * to conclude the operation. | 209 | * to conclude the operation. |
210 | */ | 210 | */ |
211 | int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum) | 211 | int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) |
212 | { | 212 | { |
213 | int retval; | 213 | int retval; |
214 | 214 | ||
@@ -233,7 +233,7 @@ EXPORT_SYMBOL(mdiobus_read); | |||
233 | * because the bus read/write functions may wait for an interrupt | 233 | * because the bus read/write functions may wait for an interrupt |
234 | * to conclude the operation. | 234 | * to conclude the operation. |
235 | */ | 235 | */ |
236 | int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val) | 236 | int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) |
237 | { | 237 | { |
238 | int err; | 238 | int err; |
239 | 239 | ||
diff --git a/include/linux/phy.h b/include/linux/phy.h index 14d7fdf6a90a..d9bce4b526b4 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h | |||
@@ -81,6 +81,10 @@ typedef enum { | |||
81 | */ | 81 | */ |
82 | #define MII_BUS_ID_SIZE (20 - 3) | 82 | #define MII_BUS_ID_SIZE (20 - 3) |
83 | 83 | ||
84 | /* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit | ||
85 | IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */ | ||
86 | #define MII_ADDR_C45 (1<<30) | ||
87 | |||
84 | /* | 88 | /* |
85 | * The Bus class for PHYs. Devices which provide access to | 89 | * The Bus class for PHYs. Devices which provide access to |
86 | * PHYs should register using this structure | 90 | * PHYs should register using this structure |
@@ -127,8 +131,8 @@ int mdiobus_register(struct mii_bus *bus); | |||
127 | void mdiobus_unregister(struct mii_bus *bus); | 131 | void mdiobus_unregister(struct mii_bus *bus); |
128 | void mdiobus_free(struct mii_bus *bus); | 132 | void mdiobus_free(struct mii_bus *bus); |
129 | struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); | 133 | struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); |
130 | int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum); | 134 | int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); |
131 | int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val); | 135 | int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); |
132 | 136 | ||
133 | 137 | ||
134 | #define PHY_INTERRUPT_DISABLED 0x0 | 138 | #define PHY_INTERRUPT_DISABLED 0x0 |
@@ -422,7 +426,7 @@ struct phy_fixup { | |||
422 | * because the bus read/write functions may wait for an interrupt | 426 | * because the bus read/write functions may wait for an interrupt |
423 | * to conclude the operation. | 427 | * to conclude the operation. |
424 | */ | 428 | */ |
425 | static inline int phy_read(struct phy_device *phydev, u16 regnum) | 429 | static inline int phy_read(struct phy_device *phydev, u32 regnum) |
426 | { | 430 | { |
427 | return mdiobus_read(phydev->bus, phydev->addr, regnum); | 431 | return mdiobus_read(phydev->bus, phydev->addr, regnum); |
428 | } | 432 | } |
@@ -437,7 +441,7 @@ static inline int phy_read(struct phy_device *phydev, u16 regnum) | |||
437 | * because the bus read/write functions may wait for an interrupt | 441 | * because the bus read/write functions may wait for an interrupt |
438 | * to conclude the operation. | 442 | * to conclude the operation. |
439 | */ | 443 | */ |
440 | static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val) | 444 | static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val) |
441 | { | 445 | { |
442 | return mdiobus_write(phydev->bus, phydev->addr, regnum, val); | 446 | return mdiobus_write(phydev->bus, phydev->addr, regnum, val); |
443 | } | 447 | } |