Merge branch 'net-phy-remove-probe_capabilities'
Michael Walle says: ==================== net: phy: Remove probe_capabilities With all the drivers which used .probe_capabilities converted to the new c45 MDIO access methods, we can now decide based upon these whether a bus driver supports c45 and we can get rid of the not widely used probe_capabilites. Unfortunately, due to a now broader support of c45 scans, this will trigger a bug on some boards with a (c22-only) Micrel PHY. These PHYs don't ignore c45 accesses correctly, thinking they are addressed themselves and distrupt the MDIO access. To avoid this, a blacklist for c45 scans is introduced. ==================== Link: https://lore.kernel.org/r/20230116-net-next-remove-probe-capabilities-v2-0-15513b05e1f4@walle.cc Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
3ef4a8c896
@ -523,7 +523,6 @@ static int adin1110_register_mdiobus(struct adin1110_priv *priv,
|
||||
mii_bus->priv = priv;
|
||||
mii_bus->parent = dev;
|
||||
mii_bus->phy_mask = ~((u32)GENMASK(2, 0));
|
||||
mii_bus->probe_capabilities = MDIOBUS_C22;
|
||||
snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
|
||||
|
||||
ret = devm_mdiobus_register(dev, mii_bus);
|
||||
|
@ -397,7 +397,6 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
|
||||
bus->read_c45 = xgmac_mdio_read_c45;
|
||||
bus->write_c45 = xgmac_mdio_write_c45;
|
||||
bus->parent = &pdev->dev;
|
||||
bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res->start);
|
||||
|
||||
priv = bus->priv;
|
||||
|
@ -965,7 +965,7 @@ static int pxa168_init_phy(struct net_device *dev)
|
||||
if (dev->phydev)
|
||||
return 0;
|
||||
|
||||
phy = mdiobus_scan(pep->smi_bus, pep->phy_addr);
|
||||
phy = mdiobus_scan_c22(pep->smi_bus, pep->phy_addr);
|
||||
if (IS_ERR(phy))
|
||||
return PTR_ERR(phy);
|
||||
|
||||
|
@ -814,7 +814,6 @@ static int mtk_mdio_init(struct mtk_eth *eth)
|
||||
eth->mii_bus->write = mtk_mdio_write_c22;
|
||||
eth->mii_bus->read_c45 = mtk_mdio_read_c45;
|
||||
eth->mii_bus->write_c45 = mtk_mdio_write_c45;
|
||||
eth->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
eth->mii_bus->priv = eth;
|
||||
eth->mii_bus->parent = eth->dev;
|
||||
|
||||
|
@ -3302,7 +3302,6 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
|
||||
lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
|
||||
netif_dbg(adapter, drv, adapter->netdev,
|
||||
"SGMII operation\n");
|
||||
adapter->mdiobus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
adapter->mdiobus->read = lan743x_mdiobus_read_c22;
|
||||
adapter->mdiobus->write = lan743x_mdiobus_write_c22;
|
||||
adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45;
|
||||
@ -3318,7 +3317,6 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
|
||||
netif_dbg(adapter, drv, adapter->netdev,
|
||||
"RGMII operation\n");
|
||||
// Only C22 support when RGMII I/F
|
||||
adapter->mdiobus->probe_capabilities = MDIOBUS_C22;
|
||||
adapter->mdiobus->read = lan743x_mdiobus_read_c22;
|
||||
adapter->mdiobus->write = lan743x_mdiobus_write_c22;
|
||||
adapter->mdiobus->name = "lan743x-mdiobus";
|
||||
|
@ -553,9 +553,6 @@ int stmmac_mdio_register(struct net_device *ndev)
|
||||
|
||||
new_bus->name = "stmmac";
|
||||
|
||||
if (priv->plat->has_gmac4)
|
||||
new_bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
|
||||
if (priv->plat->has_xgmac) {
|
||||
new_bus->read = &stmmac_xgmac2_mdio_read_c22;
|
||||
new_bus->write = &stmmac_xgmac2_mdio_write_c22;
|
||||
|
@ -164,7 +164,6 @@ static int aspeed_mdio_probe(struct platform_device *pdev)
|
||||
bus->write = aspeed_mdio_write_c22;
|
||||
bus->read_c45 = aspeed_mdio_read_c45;
|
||||
bus->write_c45 = aspeed_mdio_write_c45;
|
||||
bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
|
||||
rc = of_mdiobus_register(bus, pdev->dev.of_node);
|
||||
if (rc) {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/micrel_phy.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
@ -506,6 +507,126 @@ static int mdiobus_create_device(struct mii_bus *bus,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr, bool c45)
|
||||
{
|
||||
struct phy_device *phydev = ERR_PTR(-ENODEV);
|
||||
int err;
|
||||
|
||||
phydev = get_phy_device(bus, addr, c45);
|
||||
if (IS_ERR(phydev))
|
||||
return phydev;
|
||||
|
||||
/* For DT, see if the auto-probed phy has a corresponding child
|
||||
* in the bus node, and set the of_node pointer in this case.
|
||||
*/
|
||||
of_mdiobus_link_mdiodev(bus, &phydev->mdio);
|
||||
|
||||
err = phy_device_register(phydev);
|
||||
if (err) {
|
||||
phy_device_free(phydev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
return phydev;
|
||||
}
|
||||
|
||||
/**
|
||||
* mdiobus_scan_c22 - scan one address on a bus for C22 MDIO devices.
|
||||
* @bus: mii_bus to scan
|
||||
* @addr: address on bus to scan
|
||||
*
|
||||
* This function scans one address on the MDIO bus, looking for
|
||||
* devices which can be identified using a vendor/product ID in
|
||||
* registers 2 and 3. Not all MDIO devices have such registers, but
|
||||
* PHY devices typically do. Hence this function assumes anything
|
||||
* found is a PHY, or can be treated as a PHY. Other MDIO devices,
|
||||
* such as switches, will probably not be found during the scan.
|
||||
*/
|
||||
struct phy_device *mdiobus_scan_c22(struct mii_bus *bus, int addr)
|
||||
{
|
||||
return mdiobus_scan(bus, addr, false);
|
||||
}
|
||||
EXPORT_SYMBOL(mdiobus_scan_c22);
|
||||
|
||||
/**
|
||||
* mdiobus_scan_c45 - scan one address on a bus for C45 MDIO devices.
|
||||
* @bus: mii_bus to scan
|
||||
* @addr: address on bus to scan
|
||||
*
|
||||
* This function scans one address on the MDIO bus, looking for
|
||||
* devices which can be identified using a vendor/product ID in
|
||||
* registers 2 and 3. Not all MDIO devices have such registers, but
|
||||
* PHY devices typically do. Hence this function assumes anything
|
||||
* found is a PHY, or can be treated as a PHY. Other MDIO devices,
|
||||
* such as switches, will probably not be found during the scan.
|
||||
*/
|
||||
static struct phy_device *mdiobus_scan_c45(struct mii_bus *bus, int addr)
|
||||
{
|
||||
return mdiobus_scan(bus, addr, true);
|
||||
}
|
||||
|
||||
static int mdiobus_scan_bus_c22(struct mii_bus *bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++) {
|
||||
if ((bus->phy_mask & BIT(i)) == 0) {
|
||||
struct phy_device *phydev;
|
||||
|
||||
phydev = mdiobus_scan_c22(bus, i);
|
||||
if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV))
|
||||
return PTR_ERR(phydev);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdiobus_scan_bus_c45(struct mii_bus *bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++) {
|
||||
if ((bus->phy_mask & BIT(i)) == 0) {
|
||||
struct phy_device *phydev;
|
||||
|
||||
/* Don't scan C45 if we already have a C22 device */
|
||||
if (bus->mdio_map[i])
|
||||
continue;
|
||||
|
||||
phydev = mdiobus_scan_c45(bus, i);
|
||||
if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV))
|
||||
return PTR_ERR(phydev);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There are some C22 PHYs which do bad things when where is a C45
|
||||
* transaction on the bus, like accepting a read themselves, and
|
||||
* stomping over the true devices reply, to performing a write to
|
||||
* themselves which was intended for another device. Now that C22
|
||||
* devices have been found, see if any of them are bad for C45, and if we
|
||||
* should skip the C45 scan.
|
||||
*/
|
||||
static bool mdiobus_prevent_c45_scan(struct mii_bus *bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++) {
|
||||
struct phy_device *phydev;
|
||||
u32 oui;
|
||||
|
||||
phydev = mdiobus_get_phy(bus, i);
|
||||
if (!phydev)
|
||||
continue;
|
||||
oui = phydev->phy_id >> 10;
|
||||
|
||||
if (oui == MICREL_OUI)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
|
||||
* @bus: target mii_bus
|
||||
@ -523,8 +644,9 @@ static int mdiobus_create_device(struct mii_bus *bus,
|
||||
int __mdiobus_register(struct mii_bus *bus, struct module *owner)
|
||||
{
|
||||
struct mdio_device *mdiodev;
|
||||
int i, err;
|
||||
struct gpio_desc *gpiod;
|
||||
bool prevent_c45_scan;
|
||||
int i, err;
|
||||
|
||||
if (!bus || !bus->name)
|
||||
return -EINVAL;
|
||||
@ -589,16 +711,18 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
|
||||
goto error_reset_gpiod;
|
||||
}
|
||||
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++) {
|
||||
if ((bus->phy_mask & BIT(i)) == 0) {
|
||||
struct phy_device *phydev;
|
||||
if (bus->read) {
|
||||
err = mdiobus_scan_bus_c22(bus);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
phydev = mdiobus_scan(bus, i);
|
||||
if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) {
|
||||
err = PTR_ERR(phydev);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
prevent_c45_scan = mdiobus_prevent_c45_scan(bus);
|
||||
|
||||
if (!prevent_c45_scan && bus->read_c45) {
|
||||
err = mdiobus_scan_bus_c45(bus);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
mdiobus_setup_mdiodev_from_board_info(bus, mdiobus_create_device);
|
||||
@ -608,7 +732,7 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
|
||||
return 0;
|
||||
|
||||
error:
|
||||
while (--i >= 0) {
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++) {
|
||||
mdiodev = bus->mdio_map[i];
|
||||
if (!mdiodev)
|
||||
continue;
|
||||
@ -679,57 +803,6 @@ void mdiobus_free(struct mii_bus *bus)
|
||||
}
|
||||
EXPORT_SYMBOL(mdiobus_free);
|
||||
|
||||
/**
|
||||
* mdiobus_scan - scan a bus for MDIO devices.
|
||||
* @bus: mii_bus to scan
|
||||
* @addr: address on bus to scan
|
||||
*
|
||||
* This function scans the MDIO bus, looking for devices which can be
|
||||
* identified using a vendor/product ID in registers 2 and 3. Not all
|
||||
* MDIO devices have such registers, but PHY devices typically
|
||||
* do. Hence this function assumes anything found is a PHY, or can be
|
||||
* treated as a PHY. Other MDIO devices, such as switches, will
|
||||
* probably not be found during the scan.
|
||||
*/
|
||||
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
|
||||
{
|
||||
struct phy_device *phydev = ERR_PTR(-ENODEV);
|
||||
int err;
|
||||
|
||||
switch (bus->probe_capabilities) {
|
||||
case MDIOBUS_NO_CAP:
|
||||
case MDIOBUS_C22:
|
||||
phydev = get_phy_device(bus, addr, false);
|
||||
break;
|
||||
case MDIOBUS_C45:
|
||||
phydev = get_phy_device(bus, addr, true);
|
||||
break;
|
||||
case MDIOBUS_C22_C45:
|
||||
phydev = get_phy_device(bus, addr, false);
|
||||
if (IS_ERR(phydev))
|
||||
phydev = get_phy_device(bus, addr, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_ERR(phydev))
|
||||
return phydev;
|
||||
|
||||
/*
|
||||
* For DT, see if the auto-probed phy has a correspoding child
|
||||
* in the bus node, and set the of_node pointer in this case.
|
||||
*/
|
||||
of_mdiobus_link_mdiodev(bus, &phydev->mdio);
|
||||
|
||||
err = phy_device_register(phydev);
|
||||
if (err) {
|
||||
phy_device_free(phydev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
return phydev;
|
||||
}
|
||||
EXPORT_SYMBOL(mdiobus_scan);
|
||||
|
||||
static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
|
||||
{
|
||||
preempt_disable();
|
||||
|
@ -946,7 +946,7 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
|
||||
* probe with C45 to see if we're able to get a valid PHY ID in the C45
|
||||
* space, if successful, create the C45 PHY device.
|
||||
*/
|
||||
if (!is_c45 && phy_id == 0 && bus->probe_capabilities >= MDIOBUS_C45) {
|
||||
if (!is_c45 && phy_id == 0 && bus->read_c45) {
|
||||
r = get_phy_c45_ids(bus, addr, &c45_ids);
|
||||
if (!r)
|
||||
return phy_device_create(bus, addr, phy_id,
|
||||
|
@ -8,6 +8,8 @@
|
||||
#ifndef _MICREL_PHY_H
|
||||
#define _MICREL_PHY_H
|
||||
|
||||
#define MICREL_OUI 0x0885
|
||||
|
||||
#define MICREL_PHY_ID_MASK 0x00fffff0
|
||||
|
||||
#define PHY_ID_KSZ8873MLL 0x000e7237
|
||||
|
@ -419,14 +419,6 @@ struct mii_bus {
|
||||
/** @reset_gpiod: Reset GPIO descriptor pointer */
|
||||
struct gpio_desc *reset_gpiod;
|
||||
|
||||
/** @probe_capabilities: bus capabilities, used for probing */
|
||||
enum {
|
||||
MDIOBUS_NO_CAP = 0,
|
||||
MDIOBUS_C22,
|
||||
MDIOBUS_C45,
|
||||
MDIOBUS_C22_C45,
|
||||
} probe_capabilities;
|
||||
|
||||
/** @shared_lock: protect access to the shared element */
|
||||
struct mutex shared_lock;
|
||||
|
||||
@ -464,7 +456,7 @@ static inline struct mii_bus *devm_mdiobus_alloc(struct device *dev)
|
||||
}
|
||||
|
||||
struct mii_bus *mdio_find_bus(const char *mdio_name);
|
||||
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
|
||||
struct phy_device *mdiobus_scan_c22(struct mii_bus *bus, int addr);
|
||||
|
||||
#define PHY_INTERRUPT_DISABLED false
|
||||
#define PHY_INTERRUPT_ENABLED true
|
||||
|
Loading…
Reference in New Issue
Block a user