Skip to content

Commit ecbd87b

Browse files
Russell Kingdavem330
authored andcommitted
phylink: add support for MII ioctl access to Clause 45 PHYs
Add support for reading and writing the clause 45 MII registers. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 770a1ad commit ecbd87b

File tree

1 file changed

+124
-33
lines changed

1 file changed

+124
-33
lines changed

drivers/net/phy/phylink.c

Lines changed: 124 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,16 +1127,93 @@ static int phylink_mii_emul_read(struct net_device *ndev, unsigned int reg,
11271127
return val;
11281128
}
11291129

1130+
static int phylink_phy_read(struct phylink *pl, unsigned int phy_id,
1131+
unsigned int reg)
1132+
{
1133+
struct phy_device *phydev = pl->phydev;
1134+
int prtad, devad;
1135+
1136+
if (mdio_phy_id_is_c45(phy_id)) {
1137+
prtad = mdio_phy_id_prtad(phy_id);
1138+
devad = mdio_phy_id_devad(phy_id);
1139+
devad = MII_ADDR_C45 | devad << 16 | reg;
1140+
} else if (phydev->is_c45) {
1141+
switch (reg) {
1142+
case MII_BMCR:
1143+
case MII_BMSR:
1144+
case MII_PHYSID1:
1145+
case MII_PHYSID2:
1146+
devad = __ffs(phydev->c45_ids.devices_in_package);
1147+
break;
1148+
case MII_ADVERTISE:
1149+
case MII_LPA:
1150+
if (!(phydev->c45_ids.devices_in_package & MDIO_DEVS_AN))
1151+
return -EINVAL;
1152+
devad = MDIO_MMD_AN;
1153+
if (reg == MII_ADVERTISE)
1154+
reg = MDIO_AN_ADVERTISE;
1155+
else
1156+
reg = MDIO_AN_LPA;
1157+
break;
1158+
default:
1159+
return -EINVAL;
1160+
}
1161+
prtad = phy_id;
1162+
devad = MII_ADDR_C45 | devad << 16 | reg;
1163+
} else {
1164+
prtad = phy_id;
1165+
devad = reg;
1166+
}
1167+
return mdiobus_read(pl->phydev->mdio.bus, prtad, devad);
1168+
}
1169+
1170+
static int phylink_phy_write(struct phylink *pl, unsigned int phy_id,
1171+
unsigned int reg, unsigned int val)
1172+
{
1173+
struct phy_device *phydev = pl->phydev;
1174+
int prtad, devad;
1175+
1176+
if (mdio_phy_id_is_c45(phy_id)) {
1177+
prtad = mdio_phy_id_prtad(phy_id);
1178+
devad = mdio_phy_id_devad(phy_id);
1179+
devad = MII_ADDR_C45 | devad << 16 | reg;
1180+
} else if (phydev->is_c45) {
1181+
switch (reg) {
1182+
case MII_BMCR:
1183+
case MII_BMSR:
1184+
case MII_PHYSID1:
1185+
case MII_PHYSID2:
1186+
devad = __ffs(phydev->c45_ids.devices_in_package);
1187+
break;
1188+
case MII_ADVERTISE:
1189+
case MII_LPA:
1190+
if (!(phydev->c45_ids.devices_in_package & MDIO_DEVS_AN))
1191+
return -EINVAL;
1192+
devad = MDIO_MMD_AN;
1193+
if (reg == MII_ADVERTISE)
1194+
reg = MDIO_AN_ADVERTISE;
1195+
else
1196+
reg = MDIO_AN_LPA;
1197+
break;
1198+
default:
1199+
return -EINVAL;
1200+
}
1201+
prtad = phy_id;
1202+
devad = MII_ADDR_C45 | devad << 16 | reg;
1203+
} else {
1204+
prtad = phy_id;
1205+
devad = reg;
1206+
}
1207+
1208+
return mdiobus_write(phydev->mdio.bus, prtad, devad, val);
1209+
}
1210+
11301211
static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
11311212
unsigned int reg)
11321213
{
11331214
struct phylink_link_state state;
11341215
int val = 0xffff;
11351216

1136-
/* PHYs only exist for MLO_AN_PHY and MLO_AN_SGMII */
1137-
if (pl->phydev)
1138-
return mdiobus_read(pl->phydev->mdio.bus, phy_id, reg);
1139-
11401217
switch (pl->link_an_mode) {
11411218
case MLO_AN_FIXED:
11421219
if (phy_id == 0) {
@@ -1169,12 +1246,6 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
11691246
static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
11701247
unsigned int reg, unsigned int val)
11711248
{
1172-
/* PHYs only exist for MLO_AN_PHY and MLO_AN_SGMII */
1173-
if (pl->phydev) {
1174-
mdiobus_write(pl->phydev->mdio.bus, phy_id, reg, val);
1175-
return 0;
1176-
}
1177-
11781249
switch (pl->link_an_mode) {
11791250
case MLO_AN_FIXED:
11801251
break;
@@ -1193,36 +1264,56 @@ static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
11931264

11941265
int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
11951266
{
1196-
struct mii_ioctl_data *mii_data = if_mii(ifr);
1197-
int val, ret;
1267+
struct mii_ioctl_data *mii = if_mii(ifr);
1268+
int ret;
11981269

11991270
WARN_ON(!lockdep_rtnl_is_held());
12001271

1201-
switch (cmd) {
1202-
case SIOCGMIIPHY:
1203-
mii_data->phy_id = pl->phydev ? pl->phydev->mdio.addr : 0;
1204-
/* fallthrough */
1272+
if (pl->phydev) {
1273+
/* PHYs only exist for MLO_AN_PHY and MLO_AN_SGMII */
1274+
switch (cmd) {
1275+
case SIOCGMIIPHY:
1276+
mii->phy_id = pl->phydev->mdio.addr;
1277+
1278+
case SIOCGMIIREG:
1279+
ret = phylink_phy_read(pl, mii->phy_id, mii->reg_num);
1280+
if (ret >= 0) {
1281+
mii->val_out = ret;
1282+
ret = 0;
1283+
}
1284+
break;
12051285

1206-
case SIOCGMIIREG:
1207-
val = phylink_mii_read(pl, mii_data->phy_id, mii_data->reg_num);
1208-
if (val < 0) {
1209-
ret = val;
1210-
} else {
1211-
mii_data->val_out = val;
1212-
ret = 0;
1286+
case SIOCSMIIREG:
1287+
ret = phylink_phy_write(pl, mii->phy_id, mii->reg_num,
1288+
mii->val_in);
1289+
break;
1290+
1291+
default:
1292+
ret = phy_mii_ioctl(pl->phydev, ifr, cmd);
1293+
break;
12131294
}
1214-
break;
1295+
} else {
1296+
switch (cmd) {
1297+
case SIOCGMIIPHY:
1298+
mii->phy_id = 0;
1299+
1300+
case SIOCGMIIREG:
1301+
ret = phylink_mii_read(pl, mii->phy_id, mii->reg_num);
1302+
if (ret >= 0) {
1303+
mii->val_out = ret;
1304+
ret = 0;
1305+
}
1306+
break;
12151307

1216-
case SIOCSMIIREG:
1217-
ret = phylink_mii_write(pl, mii_data->phy_id, mii_data->reg_num,
1218-
mii_data->val_in);
1219-
break;
1308+
case SIOCSMIIREG:
1309+
ret = phylink_mii_write(pl, mii->phy_id, mii->reg_num,
1310+
mii->val_in);
1311+
break;
12201312

1221-
default:
1222-
ret = -EOPNOTSUPP;
1223-
if (pl->phydev)
1224-
ret = phy_mii_ioctl(pl->phydev, ifr, cmd);
1225-
break;
1313+
default:
1314+
ret = -EOPNOTSUPP;
1315+
break;
1316+
}
12261317
}
12271318

12281319
return ret;

0 commit comments

Comments
 (0)