aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2012-06-27 03:33:35 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-28 00:23:24 -0400
commitac28b9f8cd66d6bc54f8063df59e99abd62173a4 (patch)
tree9a837eafeead399aebad03fb891654ddeff37513
parenta3caad0a160c03b7238a2518fa89abda78adef1e (diff)
netdev/phy: Handle IEEE802.3 clause 45 Ethernet PHYs
The IEEE802.3 clause 45 MDIO bus protocol allows for directly addressing PHY registers using a 21 bit address, and is used by many 10G Ethernet PHYS. Already existing is the ability of MDIO bus drivers to use clause 45, with the MII_ADDR_C45 flag. Here we add struct phy_c45_device_ids to hold the device identifier registers present in clause 45. struct phy_device gets a couple of new fields: c45_ids to hold the identifiers and is_c45 to signal that it is clause 45. get_phy_device() gets a new parameter is_c45 to indicate that the PHY device should use the clause 45 protocol, and its callers are adjusted to pass false. The follow-on patch to of_mdio.c will pass true where appropriate. EXPORT phy_device_create() so that the follow-on patch to of_mdio.c can use it to create phy devices for PHYs, that have non-standard device identifier registers, based on the device tree bindings. Signed-off-by: David Daney <david.daney@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/mdio_bus.c2
-rw-r--r--drivers/net/phy/phy_device.c105
-rw-r--r--drivers/of/of_mdio.c2
-rw-r--r--include/linux/phy.h18
4 files changed, 116 insertions, 11 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 31470b0d0c3..2cee6d218d2 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -232,7 +232,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
232 struct phy_device *phydev; 232 struct phy_device *phydev;
233 int err; 233 int err;
234 234
235 phydev = get_phy_device(bus, addr); 235 phydev = get_phy_device(bus, addr, false);
236 if (IS_ERR(phydev) || phydev == NULL) 236 if (IS_ERR(phydev) || phydev == NULL)
237 return phydev; 237 return phydev;
238 238
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 18ab0daf449..ef4cdeebedd 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -152,8 +152,8 @@ int phy_scan_fixups(struct phy_device *phydev)
152} 152}
153EXPORT_SYMBOL(phy_scan_fixups); 153EXPORT_SYMBOL(phy_scan_fixups);
154 154
155static struct phy_device* phy_device_create(struct mii_bus *bus, 155struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
156 int addr, int phy_id) 156 bool is_c45, struct phy_c45_device_ids *c45_ids)
157{ 157{
158 struct phy_device *dev; 158 struct phy_device *dev;
159 159
@@ -174,8 +174,11 @@ static struct phy_device* phy_device_create(struct mii_bus *bus,
174 174
175 dev->autoneg = AUTONEG_ENABLE; 175 dev->autoneg = AUTONEG_ENABLE;
176 176
177 dev->is_c45 = is_c45;
177 dev->addr = addr; 178 dev->addr = addr;
178 dev->phy_id = phy_id; 179 dev->phy_id = phy_id;
180 if (c45_ids)
181 dev->c45_ids = *c45_ids;
179 dev->bus = bus; 182 dev->bus = bus;
180 dev->dev.parent = bus->parent; 183 dev->dev.parent = bus->parent;
181 dev->dev.bus = &mdio_bus_type; 184 dev->dev.bus = &mdio_bus_type;
@@ -200,20 +203,99 @@ static struct phy_device* phy_device_create(struct mii_bus *bus,
200 203
201 return dev; 204 return dev;
202} 205}
206EXPORT_SYMBOL(phy_device_create);
207
208/**
209 * get_phy_c45_ids - reads the specified addr for its 802.3-c45 IDs.
210 * @bus: the target MII bus
211 * @addr: PHY address on the MII bus
212 * @phy_id: where to store the ID retrieved.
213 * @c45_ids: where to store the c45 ID information.
214 *
215 * If the PHY devices-in-package appears to be valid, it and the
216 * corresponding identifiers are stored in @c45_ids, zero is stored
217 * in @phy_id. Otherwise 0xffffffff is stored in @phy_id. Returns
218 * zero on success.
219 *
220 */
221static int get_phy_c45_ids(struct mii_bus *bus, int addr, u32 *phy_id,
222 struct phy_c45_device_ids *c45_ids) {
223 int phy_reg;
224 int i, reg_addr;
225 const int num_ids = ARRAY_SIZE(c45_ids->device_ids);
226
227 /* Find first non-zero Devices In package. Device
228 * zero is reserved, so don't probe it.
229 */
230 for (i = 1;
231 i < num_ids && c45_ids->devices_in_package == 0;
232 i++) {
233 reg_addr = MII_ADDR_C45 | i << 16 | 6;
234 phy_reg = mdiobus_read(bus, addr, reg_addr);
235 if (phy_reg < 0)
236 return -EIO;
237 c45_ids->devices_in_package = (phy_reg & 0xffff) << 16;
238
239 reg_addr = MII_ADDR_C45 | i << 16 | 5;
240 phy_reg = mdiobus_read(bus, addr, reg_addr);
241 if (phy_reg < 0)
242 return -EIO;
243 c45_ids->devices_in_package |= (phy_reg & 0xffff);
244
245 /* If mostly Fs, there is no device there,
246 * let's get out of here.
247 */
248 if ((c45_ids->devices_in_package & 0x1fffffff) == 0x1fffffff) {
249 *phy_id = 0xffffffff;
250 return 0;
251 }
252 }
253
254 /* Now probe Device Identifiers for each device present. */
255 for (i = 1; i < num_ids; i++) {
256 if (!(c45_ids->devices_in_package & (1 << i)))
257 continue;
258
259 reg_addr = MII_ADDR_C45 | i << 16 | MII_PHYSID1;
260 phy_reg = mdiobus_read(bus, addr, reg_addr);
261 if (phy_reg < 0)
262 return -EIO;
263 c45_ids->device_ids[i] = (phy_reg & 0xffff) << 16;
264
265 reg_addr = MII_ADDR_C45 | i << 16 | MII_PHYSID2;
266 phy_reg = mdiobus_read(bus, addr, reg_addr);
267 if (phy_reg < 0)
268 return -EIO;
269 c45_ids->device_ids[i] |= (phy_reg & 0xffff);
270 }
271 *phy_id = 0;
272 return 0;
273}
203 274
204/** 275/**
205 * get_phy_id - reads the specified addr for its ID. 276 * get_phy_id - reads the specified addr for its ID.
206 * @bus: the target MII bus 277 * @bus: the target MII bus
207 * @addr: PHY address on the MII bus 278 * @addr: PHY address on the MII bus
208 * @phy_id: where to store the ID retrieved. 279 * @phy_id: where to store the ID retrieved.
280 * @is_c45: If true the PHY uses the 802.3 clause 45 protocol
281 * @c45_ids: where to store the c45 ID information.
282 *
283 * Description: In the case of a 802.3-c22 PHY, reads the ID registers
284 * of the PHY at @addr on the @bus, stores it in @phy_id and returns
285 * zero on success.
286 *
287 * In the case of a 802.3-c45 PHY, get_phy_c45_ids() is invoked, and
288 * its return value is in turn returned.
209 * 289 *
210 * Description: Reads the ID registers of the PHY at @addr on the
211 * @bus, stores it in @phy_id and returns zero on success.
212 */ 290 */
213static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) 291static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
292 bool is_c45, struct phy_c45_device_ids *c45_ids)
214{ 293{
215 int phy_reg; 294 int phy_reg;
216 295
296 if (is_c45)
297 return get_phy_c45_ids(bus, addr, phy_id, c45_ids);
298
217 /* Grab the bits from PHYIR1, and put them 299 /* Grab the bits from PHYIR1, and put them
218 * in the upper half */ 300 * in the upper half */
219 phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); 301 phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
@@ -238,17 +320,19 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
238 * get_phy_device - reads the specified PHY device and returns its @phy_device struct 320 * get_phy_device - reads the specified PHY device and returns its @phy_device struct
239 * @bus: the target MII bus 321 * @bus: the target MII bus
240 * @addr: PHY address on the MII bus 322 * @addr: PHY address on the MII bus
323 * @is_c45: If true the PHY uses the 802.3 clause 45 protocol
241 * 324 *
242 * Description: Reads the ID registers of the PHY at @addr on the 325 * Description: Reads the ID registers of the PHY at @addr on the
243 * @bus, then allocates and returns the phy_device to represent it. 326 * @bus, then allocates and returns the phy_device to represent it.
244 */ 327 */
245struct phy_device * get_phy_device(struct mii_bus *bus, int addr) 328struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
246{ 329{
247 struct phy_device *dev = NULL; 330 struct phy_device *dev = NULL;
248 u32 phy_id; 331 u32 phy_id;
332 struct phy_c45_device_ids c45_ids = {0};
249 int r; 333 int r;
250 334
251 r = get_phy_id(bus, addr, &phy_id); 335 r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
252 if (r) 336 if (r)
253 return ERR_PTR(r); 337 return ERR_PTR(r);
254 338
@@ -256,7 +340,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
256 if ((phy_id & 0x1fffffff) == 0x1fffffff) 340 if ((phy_id & 0x1fffffff) == 0x1fffffff)
257 return NULL; 341 return NULL;
258 342
259 dev = phy_device_create(bus, addr, phy_id); 343 dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
260 344
261 return dev; 345 return dev;
262} 346}
@@ -449,6 +533,11 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
449 /* Assume that if there is no driver, that it doesn't 533 /* Assume that if there is no driver, that it doesn't
450 * exist, and we should use the genphy driver. */ 534 * exist, and we should use the genphy driver. */
451 if (NULL == d->driver) { 535 if (NULL == d->driver) {
536 if (phydev->is_c45) {
537 pr_err("No driver for phy %x\n", phydev->phy_id);
538 return -ENODEV;
539 }
540
452 d->driver = &genphy_driver.driver; 541 d->driver = &genphy_driver.driver;
453 542
454 err = d->driver->probe(d); 543 err = d->driver->probe(d);
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 2574abde8d9..6c24cad322d 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -79,7 +79,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
79 mdio->irq[addr] = PHY_POLL; 79 mdio->irq[addr] = PHY_POLL;
80 } 80 }
81 81
82 phy = get_phy_device(mdio, addr); 82 phy = get_phy_device(mdio, addr, false);
83 if (!phy || IS_ERR(phy)) { 83 if (!phy || IS_ERR(phy)) {
84 dev_err(&mdio->dev, "error probing PHY at address %i\n", 84 dev_err(&mdio->dev, "error probing PHY at address %i\n",
85 addr); 85 addr);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index c291cae8ce3..597d05dd0fb 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -243,6 +243,15 @@ enum phy_state {
243 PHY_RESUMING 243 PHY_RESUMING
244}; 244};
245 245
246/**
247 * struct phy_c45_device_ids - 802.3-c45 Device Identifiers
248 * @devices_in_package: Bit vector of devices present.
249 * @device_ids: The device identifer for each present device.
250 */
251struct phy_c45_device_ids {
252 u32 devices_in_package;
253 u32 device_ids[8];
254};
246 255
247/* phy_device: An instance of a PHY 256/* phy_device: An instance of a PHY
248 * 257 *
@@ -250,6 +259,8 @@ enum phy_state {
250 * bus: Pointer to the bus this PHY is on 259 * bus: Pointer to the bus this PHY is on
251 * dev: driver model device structure for this PHY 260 * dev: driver model device structure for this PHY
252 * phy_id: UID for this device found during discovery 261 * phy_id: UID for this device found during discovery
262 * c45_ids: 802.3-c45 Device Identifers if is_c45.
263 * is_c45: Set to true if this phy uses clause 45 addressing.
253 * state: state of the PHY for management purposes 264 * state: state of the PHY for management purposes
254 * dev_flags: Device-specific flags used by the PHY driver. 265 * dev_flags: Device-specific flags used by the PHY driver.
255 * addr: Bus address of PHY 266 * addr: Bus address of PHY
@@ -285,6 +296,9 @@ struct phy_device {
285 296
286 u32 phy_id; 297 u32 phy_id;
287 298
299 struct phy_c45_device_ids c45_ids;
300 bool is_c45;
301
288 enum phy_state state; 302 enum phy_state state;
289 303
290 u32 dev_flags; 304 u32 dev_flags;
@@ -480,7 +494,9 @@ static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)
480 return mdiobus_write(phydev->bus, phydev->addr, regnum, val); 494 return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
481} 495}
482 496
483struct phy_device* get_phy_device(struct mii_bus *bus, int addr); 497struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
498 bool is_c45, struct phy_c45_device_ids *c45_ids);
499struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45);
484int phy_device_register(struct phy_device *phy); 500int phy_device_register(struct phy_device *phy);
485int phy_init_hw(struct phy_device *phydev); 501int phy_init_hw(struct phy_device *phydev);
486struct phy_device * phy_attach(struct net_device *dev, 502struct phy_device * phy_attach(struct net_device *dev,