static int bcm7xxx_28nm_ephy_config_init(struct phy_device *phydev) { u8 rev = phydev->phy_id & ~phydev->drv->phy_id_mask; int ret = 0; pr_info_once("%s: %s PHY revision: 0x%02x\n", phydev_name(phydev), phydev->drv->name, rev); /* Dummy read to a register to workaround a possible issue upon reset * where the internal inverter may not allow the first MDIO transaction * to pass the MDIO management controller and make us return 0xffff for * such reads. */ phy_read(phydev, MII_BMSR); /* Apply AFE software work-around if necessary */ if (rev == 0x01) { ret = bcm7xxx_28nm_ephy_01_afe_config_init(phydev); if (ret) return ret; } ret = bcm7xxx_28nm_ephy_eee_enable(phydev); if (ret) return ret; return bcm7xxx_28nm_ephy_apd_enable(phydev); }
static int mii_probe(struct net_device *dev, int phy_mode) { struct bfin_mac_local *lp = netdev_priv(dev); struct phy_device *phydev; unsigned short sysctl; u32 sclk, mdc_div; /* Enable PHY output early */ if (!(bfin_read_VR_CTL() & CLKBUFOE)) bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE); sclk = get_sclk(); mdc_div = ((sclk / MDC_CLK) / 2) - 1; sysctl = bfin_read_EMAC_SYSCTL(); sysctl = (sysctl & ~MDCDIV) | SET_MDCDIV(mdc_div); bfin_write_EMAC_SYSCTL(sysctl); phydev = phy_find_first(lp->mii_bus); if (!phydev) { netdev_err(dev, "no phy device found\n"); return -ENODEV; } if (phy_mode != PHY_INTERFACE_MODE_RMII && phy_mode != PHY_INTERFACE_MODE_MII) { netdev_err(dev, "invalid phy interface mode\n"); return -EINVAL; } phydev = phy_connect(dev, phydev_name(phydev), &bfin_mac_adjust_link, phy_mode); if (IS_ERR(phydev)) { netdev_err(dev, "could not attach PHY\n"); return PTR_ERR(phydev); } /* mask with MAC supported features */ phydev->supported &= (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_Pause | SUPPORTED_Asym_Pause | SUPPORTED_MII | SUPPORTED_TP); phydev->advertising = phydev->supported; lp->old_link = 0; lp->old_speed = 0; lp->old_duplex = -1; lp->phydev = phydev; phy_attached_print(phydev, "mdc_clk=%dHz(mdc_div=%d)@sclk=%dMHz)\n", MDC_CLK, mdc_div, sclk / 1000000); return 0; }
/** * stmmac_mdio_register * @ndev: net device structure * Description: it registers the MII bus */ int stmmac_mdio_register(struct net_device *ndev) { int err = 0; struct mii_bus *new_bus; struct stmmac_priv *priv = netdev_priv(ndev); int addr, found; new_bus = mdiobus_alloc(); if (new_bus == NULL) return -ENOMEM; /* Assign IRQ to phy at address phy_addr */ if (priv->phy_addr != -1) new_bus->irq[priv->phy_addr] = priv->phy_irq; new_bus->name = "STMMAC MII Bus"; new_bus->read = &stmmac_mdio_read; new_bus->write = &stmmac_mdio_write; new_bus->reset = &stmmac_mdio_reset; snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); new_bus->priv = ndev; new_bus->phy_mask = priv->phy_mask; new_bus->parent = priv->device; err = mdiobus_register(new_bus); if (err != 0) { pr_err("%s: Cannot register as MDIO bus\n", new_bus->name); goto bus_register_fail; } priv->mii = new_bus; found = 0; for (addr = 0; addr < 32; addr++) { struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); if (phydev) { if (priv->phy_addr == -1) { priv->phy_addr = addr; phydev->irq = priv->phy_irq; new_bus->irq[addr] = priv->phy_irq; } if (addr == priv->phy_addr) { pr_info("%s: PHY ID %08x at %d IRQ %d (%s)%s\n", ndev->name, phydev->phy_id, addr, phydev->irq, phydev_name(phydev), (addr == priv->phy_addr) ? " active" : ""); } found = 1; } } if (!found) pr_warning("%s: No PHY found\n", ndev->name); return 0; bus_register_fail: kfree(new_bus); return err; }
static int bcm7xxx_28nm_config_init(struct phy_device *phydev) { u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags); u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags); u8 count; int ret = 0; /* Newer devices have moved the revision information back into a * standard location in MII_PHYS_ID[23] */ if (rev == 0) rev = phydev->phy_id & ~phydev->drv->phy_id_mask; pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n", phydev_name(phydev), phydev->drv->name, rev, patch); /* Dummy read to a register to workaround an issue upon reset where the * internal inverter may not allow the first MDIO transaction to pass * the MDIO management controller and make us return 0xffff for such * reads. */ phy_read(phydev, MII_BMSR); switch (rev) { case 0xb0: ret = bcm7xxx_28nm_b0_afe_config_init(phydev); break; case 0xd0: ret = bcm7xxx_28nm_d0_afe_config_init(phydev); break; case 0xe0: case 0xf0: /* Rev G0 introduces a roll over */ case 0x10: ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev); break; case 0x01: ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev); break; default: break; } if (ret) return ret; ret = bcm_phy_downshift_get(phydev, &count); if (ret) return ret; /* Only enable EEE if Wirespeed/downshift is disabled */ ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); if (ret) return ret; return bcm_phy_enable_apd(phydev, true); }
static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac, struct phy_device *phy) { phy_attach(eth->netdev[mac->id], phydev_name(phy), PHY_INTERFACE_MODE_MII); phy->autoneg = AUTONEG_ENABLE; phy->speed = 0; phy->duplex = 0; phy->supported &= PHY_BASIC_FEATURES; phy->advertising = phy->supported | ADVERTISED_Autoneg; phy_start_aneg(phy); }
static int ag71xx_phy_connect_fixed(struct ag71xx *ag) { struct platform_device *pdev = ag->pdev; struct device *dev = NULL; struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); int ret = 0; if (!pdev) return -ENODEV; dev = &pdev->dev; if (!dev) return -ENODEV; if (!ag->phy_dev) { pr_err("Missing PHY for %s", dev_name(dev)); return -ENODEV; } /* use fixed settings */ switch (pdata->speed) { case SPEED_10: case SPEED_100: case SPEED_1000: break; default: dev_err(dev, "invalid speed specified\n"); ret = -EINVAL; break; } dev_dbg(dev, "using fixed link parameters\n"); ag->duplex = pdata->duplex; ag->speed = pdata->speed; if (!ret) { dev_info(dev, "connected to fixed PHY at %s [uid=%08x, driver=%s]\n", phydev_name(ag->phy_dev), ag->phy_dev->phy_id, ag->phy_dev->drv->name); } else { pr_err("Failed to connect to fixed PHY\n"); } return ret; }
static int tc_mii_probe(struct net_device *dev) { struct tc35815_local *lp = netdev_priv(dev); struct phy_device *phydev; u32 dropmask; phydev = phy_find_first(lp->mii_bus); if (!phydev) { printk(KERN_ERR "%s: no PHY found\n", dev->name); return -ENODEV; } /* attach the mac to the phy */ phydev = phy_connect(dev, phydev_name(phydev), &tc_handle_link_change, lp->chiptype == TC35815_TX4939 ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); return PTR_ERR(phydev); } phy_attached_info(phydev); /* mask with MAC supported features */ phydev->supported &= PHY_BASIC_FEATURES; dropmask = 0; if (options.speed == 10) dropmask |= SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; else if (options.speed == 100) dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full; if (options.duplex == 1) dropmask |= SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full; else if (options.duplex == 2) dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_100baseT_Half; phydev->supported &= ~dropmask; phydev->advertising = phydev->supported; lp->link = 0; lp->speed = 0; lp->duplex = -1; return 0; }
int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac, struct device_node *phy_node) { const __be32 *_port = NULL; struct phy_device *phydev; int phy_mode, port; _port = of_get_property(phy_node, "reg", NULL); if (!_port || (be32_to_cpu(*_port) >= 0x20)) { pr_err("%s: invalid port id\n", phy_node->name); return -EINVAL; } port = be32_to_cpu(*_port); phy_mode = of_get_phy_mode(phy_node); if (phy_mode < 0) { dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode); eth->phy->phy_node[port] = NULL; return -EINVAL; } phydev = of_phy_connect(eth->netdev[mac->id], phy_node, mtk_phy_link_adjust, 0, phy_mode); if (!phydev) { dev_err(eth->dev, "could not connect to PHY\n"); eth->phy->phy_node[port] = NULL; return -ENODEV; } phydev->supported &= PHY_GBIT_FEATURES; phydev->advertising = phydev->supported; dev_info(eth->dev, "connected port %d to PHY at %s [uid=%08x, driver=%s]\n", port, phydev_name(phydev), phydev->phy_id, phydev->drv->name); eth->phy->phy[port] = phydev; eth->link[port] = 0; return 0; }
static int bcm7xxx_28nm_config_init(struct phy_device *phydev) { u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags); u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags); int ret = 0; pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n", phydev_name(phydev), phydev->drv->name, rev, patch); /* Dummy read to a register to workaround an issue upon reset where the * internal inverter may not allow the first MDIO transaction to pass * the MDIO management controller and make us return 0xffff for such * reads. */ phy_read(phydev, MII_BMSR); switch (rev) { case 0xb0: ret = bcm7xxx_28nm_b0_afe_config_init(phydev); break; case 0xd0: ret = bcm7xxx_28nm_d0_afe_config_init(phydev); break; case 0xe0: case 0xf0: /* Rev G0 introduces a roll over */ case 0x10: ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev); break; default: break; } if (ret) return ret; ret = bcm_phy_enable_eee(phydev); if (ret) return ret; return bcm_phy_enable_apd(phydev, true); }
static int lpc_mii_probe(struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); struct phy_device *phydev = phy_find_first(pldat->mii_bus); if (!phydev) { netdev_err(ndev, "no PHY found\n"); return -ENODEV; } /* Attach to the PHY */ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) netdev_info(ndev, "using MII interface\n"); else netdev_info(ndev, "using RMII interface\n"); phydev = phy_connect(ndev, phydev_name(phydev), &lpc_handle_link_change, lpc_phy_interface_mode(&pldat->pdev->dev)); if (IS_ERR(phydev)) { netdev_err(ndev, "Could not attach to PHY\n"); return PTR_ERR(phydev); } /* mask with MAC supported features */ phydev->supported &= PHY_BASIC_FEATURES; phydev->advertising = phydev->supported; pldat->link = 0; pldat->speed = 0; pldat->duplex = -1; phy_attached_info(phydev); return 0; }
static int pci_eth_mii_probe(struct net_device *dev) { struct pci_eth_private *priv = netdev_priv(dev); struct phy_device *phydev = NULL; phydev = phy_find_first(priv->mii_bus); if (!phydev) { dev_err(&priv->pdev->dev, "no PHY found\n"); return -ENODEV; } phydev = phy_connect(dev, phydev_name(phydev), &pci_eth_adjust_link, PHY_INTERFACE_MODE_MII); if (IS_ERR(phydev)) { dev_err(&priv->pdev->dev, "could not attach to PHY\n"); return PTR_ERR(phydev); } /* mask with MAC supported features */ phydev->supported &= (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | SUPPORTED_TP); phydev->advertising = phydev->supported; priv->phydev = phydev; priv->old_link = 0; priv->old_duplex = -1; phy_attached_info(phydev); return 0; }
static int ag71xx_phy_connect_multi(struct ag71xx *ag) { struct device *dev = &ag->pdev->dev; struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); struct phy_device *phydev = NULL; int phy_addr; int ret = 0; for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { if (!(pdata->phy_mask & (1 << phy_addr))) continue; #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) if (ag->mii_bus->phy_map[phy_addr] == NULL) continue; DBG("%s: PHY found at %s, uid=%08x\n", dev_name(dev), dev_name(&ag->mii_bus->phy_map[phy_addr]->dev), &ag->mii_bus->phy_map[phy_addr]->phy_id), &ag->mii_bus->phy_map[phy_addr]->phy_id : 0); if (phydev == NULL) phydev = ag->mii_bus->phy_map[phy_addr]; #else if (ag->mii_bus->mdio_map[phy_addr] == NULL) continue; DBG("%s: PHY found at %s, uid=%08x\n", dev_name(dev), dev_name(&ag->mii_bus->mdio_map[phy_addr]->dev), mdiobus_get_phy(ag->mii_bus, phy_addr) ? mdiobus_get_phy(ag->mii_bus, phy_addr)->phy_id : 0); if (phydev == NULL) phydev = mdiobus_get_phy(ag->mii_bus, phy_addr); #endif } if (!phydev) { dev_err(dev, "no PHY found with phy_mask=%08x\n", pdata->phy_mask); return -ENODEV; } #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) ag->phy_dev = phy_connect(ag->dev, dev_name(&phydev->dev), #else ag->phy_dev = phy_connect(ag->dev, phydev_name(phydev), #endif &ag71xx_phy_link_adjust, pdata->phy_if_mode); if (IS_ERR(ag->phy_dev)) { dev_err(dev, "could not connect to PHY at %s\n", #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) dev_name(&phydev->dev)); #else phydev_name(phydev)); #endif return PTR_ERR(ag->phy_dev); }
/** * stmmac_mdio_register * @ndev: net device structure * Description: it registers the MII bus */ int stmmac_mdio_register(struct net_device *ndev) { int err = 0; struct mii_bus *new_bus; struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; struct device_node *mdio_node = priv->plat->mdio_node; int addr, found; if (!mdio_bus_data) return 0; new_bus = mdiobus_alloc(); if (new_bus == NULL) return -ENOMEM; if (mdio_bus_data->irqs) memcpy(new_bus->irq, mdio_bus_data, sizeof(new_bus->irq)); #ifdef CONFIG_OF if (priv->device->of_node) mdio_bus_data->reset_gpio = -1; #endif new_bus->name = "stmmac"; new_bus->read = &stmmac_mdio_read; new_bus->write = &stmmac_mdio_write; new_bus->reset = &stmmac_mdio_reset; snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", new_bus->name, priv->plat->bus_id); new_bus->priv = ndev; new_bus->phy_mask = mdio_bus_data->phy_mask; new_bus->parent = priv->device; if (mdio_node) err = of_mdiobus_register(new_bus, mdio_node); else err = mdiobus_register(new_bus); if (err != 0) { pr_err("%s: Cannot register as MDIO bus\n", new_bus->name); goto bus_register_fail; } if (priv->plat->phy_node || mdio_node) goto bus_register_done; found = 0; for (addr = 0; addr < PHY_MAX_ADDR; addr++) { struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); if (phydev) { int act = 0; char irq_num[4]; char *irq_str; /* * If an IRQ was provided to be assigned after * the bus probe, do it here. */ if ((mdio_bus_data->irqs == NULL) && (mdio_bus_data->probed_phy_irq > 0)) { new_bus->irq[addr] = mdio_bus_data->probed_phy_irq; phydev->irq = mdio_bus_data->probed_phy_irq; } /* * If we're going to bind the MAC to this PHY bus, * and no PHY number was provided to the MAC, * use the one probed here. */ if (priv->plat->phy_addr == -1) priv->plat->phy_addr = addr; act = (priv->plat->phy_addr == addr); switch (phydev->irq) { case PHY_POLL: irq_str = "POLL"; break; case PHY_IGNORE_INTERRUPT: irq_str = "IGNORE"; break; default: sprintf(irq_num, "%d", phydev->irq); irq_str = irq_num; break; } pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n", ndev->name, phydev->phy_id, addr, irq_str, phydev_name(phydev), act ? " active" : ""); found = 1; } } if (!found && !mdio_node) { pr_warn("%s: No PHY found\n", ndev->name); mdiobus_unregister(new_bus); mdiobus_free(new_bus); return -ENODEV; } bus_register_done: priv->mii = new_bus; return 0; bus_register_fail: mdiobus_free(new_bus); return err; }
int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) { struct dsa_notifier_bridge_info info = { .sw_index = dp->ds->index, .port = dp->index, .br = br, }; int err; /* Here the port is already bridged. Reflect the current configuration * so that drivers can program their chips accordingly. */ dp->bridge_dev = br; err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); /* The bridging is rolled back on error */ if (err) dp->bridge_dev = NULL; return err; } void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) { struct dsa_notifier_bridge_info info = { .sw_index = dp->ds->index, .port = dp->index, .br = br, }; int err; /* Here the port is already unbridged. Reflect the current configuration * so that drivers can program their chips accordingly. */ dp->bridge_dev = NULL; err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); if (err) pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional */ dsa_port_set_state_now(dp, BR_STATE_FORWARDING); } int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, struct switchdev_trans *trans) { struct dsa_switch *ds = dp->ds; /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ if (switchdev_trans_ph_prepare(trans)) return 0; if (ds->ops->port_vlan_filtering) return ds->ops->port_vlan_filtering(ds, dp->index, vlan_filtering); return 0; } int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, struct switchdev_trans *trans) { unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); struct dsa_notifier_ageing_time_info info = { .ageing_time = ageing_time, .trans = trans, }; if (switchdev_trans_ph_prepare(trans)) return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); dp->ageing_time = ageing_time; return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); } int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, u16 vid) { struct dsa_notifier_fdb_info info = { .sw_index = dp->ds->index, .port = dp->index, .addr = addr, .vid = vid, }; return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info); } int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, u16 vid) { struct dsa_notifier_fdb_info info = { .sw_index = dp->ds->index, .port = dp->index, .addr = addr, .vid = vid, }; return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); } int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data) { struct dsa_switch *ds = dp->ds; int port = dp->index; if (!ds->ops->port_fdb_dump) return -EOPNOTSUPP; return ds->ops->port_fdb_dump(ds, port, cb, data); } int dsa_port_mdb_add(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb, struct switchdev_trans *trans) { struct dsa_notifier_mdb_info info = { .sw_index = dp->ds->index, .port = dp->index, .trans = trans, .mdb = mdb, }; return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info); } int dsa_port_mdb_del(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb) { struct dsa_notifier_mdb_info info = { .sw_index = dp->ds->index, .port = dp->index, .mdb = mdb, }; return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info); } int dsa_port_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans) { struct dsa_notifier_vlan_info info = { .sw_index = dp->ds->index, .port = dp->index, .trans = trans, .vlan = vlan, }; if (netif_is_bridge_master(vlan->obj.orig_dev)) return -EOPNOTSUPP; if (br_vlan_enabled(dp->bridge_dev)) return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); return 0; } int dsa_port_vlan_del(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan) { struct dsa_notifier_vlan_info info = { .sw_index = dp->ds->index, .port = dp->index, .vlan = vlan, }; if (netif_is_bridge_master(vlan->obj.orig_dev)) return -EOPNOTSUPP; if (br_vlan_enabled(dp->bridge_dev)) return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); return 0; } static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp) { struct device_node *phy_dn; struct phy_device *phydev; phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0); if (!phy_dn) return NULL; phydev = of_phy_find_device(phy_dn); if (!phydev) { of_node_put(phy_dn); return ERR_PTR(-EPROBE_DEFER); } return phydev; } static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable) { struct dsa_switch *ds = dp->ds; struct phy_device *phydev; int port = dp->index; int err = 0; phydev = dsa_port_get_phy_device(dp); if (!phydev) return 0; if (IS_ERR(phydev)) return PTR_ERR(phydev); if (enable) { err = genphy_config_init(phydev); if (err < 0) goto err_put_dev; err = genphy_resume(phydev); if (err < 0) goto err_put_dev; err = genphy_read_status(phydev); if (err < 0) goto err_put_dev; } else { err = genphy_suspend(phydev); if (err < 0) goto err_put_dev; } if (ds->ops->adjust_link) ds->ops->adjust_link(ds, port, phydev); dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev)); err_put_dev: put_device(&phydev->mdio.dev); return err; } static int dsa_port_fixed_link_register_of(struct dsa_port *dp) { struct device_node *dn = dp->dn; struct dsa_switch *ds = dp->ds; struct phy_device *phydev; int port = dp->index; int mode; int err; err = of_phy_register_fixed_link(dn); if (err) { dev_err(ds->dev, "failed to register the fixed PHY of port %d\n", port); return err; } phydev = of_phy_find_device(dn); mode = of_get_phy_mode(dn); if (mode < 0) mode = PHY_INTERFACE_MODE_NA; phydev->interface = mode; genphy_config_init(phydev); genphy_read_status(phydev); if (ds->ops->adjust_link) ds->ops->adjust_link(ds, port, phydev); put_device(&phydev->mdio.dev); return 0; } int dsa_port_link_register_of(struct dsa_port *dp) { if (of_phy_is_fixed_link(dp->dn)) return dsa_port_fixed_link_register_of(dp); else return dsa_port_setup_phy_of(dp, true); } void dsa_port_link_unregister_of(struct dsa_port *dp) { if (of_phy_is_fixed_link(dp->dn)) of_phy_deregister_fixed_link(dp->dn); else dsa_port_setup_phy_of(dp, false); } int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data) { struct phy_device *phydev; int ret = -EOPNOTSUPP; if (of_phy_is_fixed_link(dp->dn)) return ret; phydev = dsa_port_get_phy_device(dp); if (IS_ERR_OR_NULL(phydev)) return ret; ret = phy_ethtool_get_strings(phydev, data); put_device(&phydev->mdio.dev); return ret; } EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings); int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data) { struct phy_device *phydev; int ret = -EOPNOTSUPP; if (of_phy_is_fixed_link(dp->dn)) return ret; phydev = dsa_port_get_phy_device(dp); if (IS_ERR_OR_NULL(phydev)) return ret; ret = phy_ethtool_get_stats(phydev, NULL, data); put_device(&phydev->mdio.dev); return ret; } EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats); int dsa_port_get_phy_sset_count(struct dsa_port *dp) { struct phy_device *phydev; int ret = -EOPNOTSUPP; if (of_phy_is_fixed_link(dp->dn)) return ret; phydev = dsa_port_get_phy_device(dp); if (IS_ERR_OR_NULL(phydev)) return ret; ret = phy_ethtool_get_sset_count(phydev); put_device(&phydev->mdio.dev); return ret; } EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);