Skip to content

Commit 5f6c99e

Browse files
Shaohui Xiedavem330
Shaohui Xie
authored andcommitted
net: phy: fix a bug in get_phy_c45_ids
When probing devices-in-package for a c45 phy, device zero is the last device to probe, however, if driver reads 0 from device zero, c45_ids->devices_in_package is set to '0', the loop condition of probing will be matched again, see codes below: for (i = 1;i < num_ids && c45_ids->devices_in_package == 0;i++) driver will run in a dead loop. This patch restructures the bug and confusing loop, it provides a helper function get_phy_c45_devs_in_pkg which to read devices-in-package registers of a MMD, and rewrites the loop with using the helper function. Signed-off-by: Shaohui Xie <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b2663a4 commit 5f6c99e

File tree

1 file changed

+49
-25
lines changed

1 file changed

+49
-25
lines changed

drivers/net/phy/phy_device.c

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,37 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
205205
}
206206
EXPORT_SYMBOL(phy_device_create);
207207

208+
/* get_phy_c45_devs_in_pkg - reads a MMD's devices in package registers.
209+
* @bus: the target MII bus
210+
* @addr: PHY address on the MII bus
211+
* @dev_addr: MMD address in the PHY.
212+
* @devices_in_package: where to store the devices in package information.
213+
*
214+
* Description: reads devices in package registers of a MMD at @dev_addr
215+
* from PHY at @addr on @bus.
216+
*
217+
* Returns: 0 on success, -EIO on failure.
218+
*/
219+
static int get_phy_c45_devs_in_pkg(struct mii_bus *bus, int addr, int dev_addr,
220+
u32 *devices_in_package)
221+
{
222+
int phy_reg, reg_addr;
223+
224+
reg_addr = MII_ADDR_C45 | dev_addr << 16 | MDIO_DEVS2;
225+
phy_reg = mdiobus_read(bus, addr, reg_addr);
226+
if (phy_reg < 0)
227+
return -EIO;
228+
*devices_in_package = (phy_reg & 0xffff) << 16;
229+
230+
reg_addr = MII_ADDR_C45 | dev_addr << 16 | MDIO_DEVS1;
231+
phy_reg = mdiobus_read(bus, addr, reg_addr);
232+
if (phy_reg < 0)
233+
return -EIO;
234+
*devices_in_package |= (phy_reg & 0xffff);
235+
236+
return 0;
237+
}
238+
208239
/**
209240
* get_phy_c45_ids - reads the specified addr for its 802.3-c45 IDs.
210241
* @bus: the target MII bus
@@ -223,38 +254,31 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, u32 *phy_id,
223254
int phy_reg;
224255
int i, reg_addr;
225256
const int num_ids = ARRAY_SIZE(c45_ids->device_ids);
257+
u32 *devs = &c45_ids->devices_in_package;
226258

227-
/* Find first non-zero Devices In package. Device
228-
* zero is reserved, so don't probe it.
259+
/* Find first non-zero Devices In package. Device zero is reserved
260+
* for 802.3 c45 complied PHYs, so don't probe it at first.
229261
*/
230-
for (i = 1;
231-
i < num_ids && c45_ids->devices_in_package == 0;
232-
i++) {
233-
retry: reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS2;
234-
phy_reg = mdiobus_read(bus, addr, reg_addr);
262+
for (i = 1; i < num_ids && *devs == 0; i++) {
263+
phy_reg = get_phy_c45_devs_in_pkg(bus, addr, i, devs);
235264
if (phy_reg < 0)
236265
return -EIO;
237-
c45_ids->devices_in_package = (phy_reg & 0xffff) << 16;
238266

239-
reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS1;
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 ((c45_ids->devices_in_package & 0x1fffffff) == 0x1fffffff) {
246-
if (i) {
247-
/* If mostly Fs, there is no device there,
248-
* then let's continue to probe more, as some
249-
* 10G PHYs have zero Devices In package,
250-
* e.g. Cortina CS4315/CS4340 PHY.
251-
*/
252-
i = 0;
253-
goto retry;
254-
} else {
255-
/* no device there, let's get out of here */
267+
if ((*devs & 0x1fffffff) == 0x1fffffff) {
268+
/* If mostly Fs, there is no device there,
269+
* then let's continue to probe more, as some
270+
* 10G PHYs have zero Devices In package,
271+
* e.g. Cortina CS4315/CS4340 PHY.
272+
*/
273+
phy_reg = get_phy_c45_devs_in_pkg(bus, addr, 0, devs);
274+
if (phy_reg < 0)
275+
return -EIO;
276+
/* no device there, let's get out of here */
277+
if ((*devs & 0x1fffffff) == 0x1fffffff) {
256278
*phy_id = 0xffffffff;
257279
return 0;
280+
} else {
281+
break;
258282
}
259283
}
260284
}

0 commit comments

Comments
 (0)