@@ -916,7 +916,7 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
hns_nic_test_strs[MAC_INTERNALLOOP_MAC]);
ethtool_sprintf(&buff,
hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]);
- if ((netdev->phydev) && (!netdev->phydev->is_c45))
+ if (netdev->phydev && !netdev->phydev->has_c45)
ethtool_sprintf(&buff,
hns_nic_test_strs[MAC_INTERNALLOOP_PHY]);
@@ -976,7 +976,7 @@ static int hns_get_sset_count(struct net_device *netdev, int stringset)
if (priv->ae_handle->phy_if == PHY_INTERFACE_MODE_XGMII)
cnt--;
- if ((!netdev->phydev) || (netdev->phydev->is_c45))
+ if (!netdev->phydev || netdev->phydev->has_c45)
cnt--;
return cnt;
@@ -47,7 +47,7 @@ static int bcm84881_probe(struct phy_device *phydev)
/* This driver requires PMAPMD and AN blocks */
const u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
- if (!phydev->is_c45 ||
+ if (!phydev->has_c45 ||
(phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
return -ENODEV;
@@ -499,7 +499,7 @@ static int mv3310_probe(struct phy_device *phydev)
u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
int ret;
- if (!phydev->is_c45 ||
+ if (!phydev->has_c45 ||
(phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
return -ENODEV;
@@ -281,7 +281,7 @@ static int gpy_probe(struct phy_device *phydev)
int fw_version;
int ret;
- if (!phydev->is_c45) {
+ if (!phydev->has_c45) {
ret = phy_get_c45_ids(phydev);
if (ret < 0)
return ret;
@@ -584,7 +584,7 @@ int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
if (phydev->drv && phydev->drv->read_mmd) {
val = phydev->drv->read_mmd(phydev, devad, regnum);
- } else if (phydev->is_c45) {
+ } else if (phydev->has_c45 && !phydev->c45_over_c22) {
val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
devad, regnum);
} else {
@@ -640,7 +640,7 @@ int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
if (phydev->drv && phydev->drv->write_mmd) {
ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
- } else if (phydev->is_c45) {
+ } else if (phydev->has_c45 && !phydev->c45_over_c22) {
ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
devad, regnum, val);
} else {
@@ -169,7 +169,7 @@ int phy_restart_aneg(struct phy_device *phydev)
{
int ret;
- if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
+ if (phydev->has_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
ret = genphy_c45_restart_aneg(phydev);
else
ret = genphy_restart_aneg(phydev);
@@ -190,7 +190,7 @@ int phy_aneg_done(struct phy_device *phydev)
{
if (phydev->drv && phydev->drv->aneg_done)
return phydev->drv->aneg_done(phydev);
- else if (phydev->is_c45)
+ else if (phydev->has_c45)
return genphy_c45_aneg_done(phydev);
else
return genphy_aneg_done(phydev);
@@ -883,7 +883,7 @@ int phy_config_aneg(struct phy_device *phydev)
/* Clause 45 PHYs that don't implement Clause 22 registers are not
* allowed to call genphy_config_aneg()
*/
- if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
+ if (phydev->has_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
return genphy_c45_config_aneg(phydev);
return genphy_config_aneg(phydev);
@@ -516,7 +516,7 @@ static int phy_bus_match(struct device *dev, struct device_driver *drv)
if (phydrv->match_phy_device)
return phydrv->match_phy_device(phydev);
- if (phydev->is_c45) {
+ if (phydev->has_c45) {
for (i = 1; i < num_ids; i++) {
if (phydev->c45_ids.device_ids[i] == 0xffffffff)
continue;
@@ -648,7 +648,24 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
dev->autoneg = AUTONEG_ENABLE;
dev->pma_extable = -ENODATA;
- dev->is_c45 = is_c45;
+
+ /* Depending on the bus capabilities, we have to use C45-over-C22
+ * register access. We have the following cases:
+ *
+ * 1) bus can only do C45.
+ * 2) bus can only do C22.
+ * 3) bus can do C22 and C45.
+ *
+ * 1) and 3) are easy, because we can just use C45 transfers. For 2) we
+ * don't have any other choice but to use C22 transfers. Even if the
+ * PHY wouldn't support it we cannot do any better.
+ *
+ * Set this for C22 PHYs, too, because the PHY driver might promote it
+ * to C45.
+ */
+ dev->c45_over_c22 = bus->read && !bus->read_c45;
+
+ dev->has_c45 = is_c45;
dev->phy_id = phy_id;
if (c45_ids)
dev->c45_ids = *c45_ids;
@@ -1456,7 +1473,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
* exist, and we should use the genphy driver.
*/
if (!d->driver) {
- if (phydev->is_c45)
+ if (phydev->has_c45)
d->driver = &genphy_c45_driver.mdiodrv.driver;
else
d->driver = &genphy_driver.mdiodrv.driver;
@@ -3115,7 +3132,7 @@ static int phy_probe(struct device *dev)
linkmode_copy(phydev->supported, phydrv->features);
else if (phydrv->get_features)
err = phydrv->get_features(phydev);
- else if (phydev->is_c45)
+ else if (phydev->has_c45)
err = genphy_c45_pma_read_abilities(phydev);
else
err = genphy_read_abilities(phydev);
@@ -1642,7 +1642,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
* against all interface modes, which may lead to more ethtool link
* modes being advertised than are actually supported.
*/
- if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
+ if (phy->has_c45 && config.rate_matching == RATE_MATCH_NONE &&
interface != PHY_INTERFACE_MODE_RXAUI &&
interface != PHY_INTERFACE_MODE_XAUI &&
interface != PHY_INTERFACE_MODE_USXGMII)
@@ -2584,7 +2584,7 @@ static int phylink_phy_read(struct phylink *pl, unsigned int phy_id,
reg);
}
- if (phydev->is_c45) {
+ if (phydev->has_c45 && !phydev->c45_over_c22) {
switch (reg) {
case MII_BMCR:
case MII_BMSR:
@@ -2626,7 +2626,7 @@ static int phylink_phy_write(struct phylink *pl, unsigned int phy_id,
reg, val);
}
- if (phydev->is_c45) {
+ if (phydev->has_c45 && !phydev->c45_over_c22) {
switch (reg) {
case MII_BMCR:
case MII_BMSR:
@@ -3101,7 +3101,7 @@ static void phylink_sfp_link_up(void *upstream)
*/
static bool phylink_phy_no_inband(struct phy_device *phy)
{
- return phy->is_c45 &&
+ return phy->has_c45 &&
(phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150;
}
@@ -532,8 +532,9 @@ struct macsec_ops;
* @devlink: Create a link between phy dev and mac dev, if the external phy
* used by current mac interface is managed by another mac interface.
* @phy_id: UID for this device found during discovery
- * @c45_ids: 802.3-c45 Device Identifiers if is_c45.
- * @is_c45: Set to true if this PHY uses clause 45 addressing.
+ * @c45_ids: 802.3-c45 Device Identifiers if has_c45.
+ * @has_c45: Set to true if this PHY has clause 45 address space.
+ * @c45_over_c22: Set to true if c45-over-c22 addressing is used.
* @is_internal: Set to true if this PHY is internal to a MAC.
* @is_pseudo_fixed_link: Set to true if this PHY is an Ethernet switch, etc.
* @is_gigabit_capable: Set to true if PHY supports 1000Mbps
@@ -625,7 +626,8 @@ struct phy_device {
u32 phy_id;
struct phy_c45_device_ids c45_ids;
- unsigned is_c45:1;
+ unsigned has_c45:1;
+ unsigned c45_over_c22:1;
unsigned is_internal:1;
unsigned is_pseudo_fixed_link:1;
unsigned is_gigabit_capable:1;