Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
phy_link_update [2018/08/28 09:48] rpjdayphy_link_update [2018/08/28 11:57] (current) – [freescale/ucc_geth.c] rpjday
Line 5: Line 5:
 Issues: Issues:
  
-  * Is [[https://elixir.bootlin.com/linux/latest/ident/phy_link_change|phy_link_change()]] relevant?+  * Is [[https://elixir.bootlin.com/linux/latest/ident/phy_link_change|phy_link_change()]] relevant? Don't think so.
  
 ===== Explanation ===== ===== Explanation =====
Line 90: Line 90:
  phy_stop(phydev).  phy_stop(phydev).
 </code> </code>
 +
 ===== struct phy_device ===== ===== struct phy_device =====
- 
-From ''include/linux/phy.h'': 
  
 <code> <code>
 +enum phy_state {
 +        PHY_DOWN = 0,
 +        PHY_STARTING,
 +        PHY_READY,
 +        PHY_PENDING,
 +        PHY_UP,
 +        PHY_AN,
 +        PHY_RUNNING,
 +        PHY_NOLINK,
 +        PHY_FORCING,
 +        PHY_CHANGELINK,
 +        PHY_HALTED,
 +        PHY_RESUMING
 +};
 +...
 struct phy_device { struct phy_device {
-        ... snip ... +        unsigned link:1;       // most recently read link state [01] 
-        void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier)+        enum phy_state state; 
-        void (*adjust_link)(struct net_device *dev);+        int speed
 +        int duplex;
 }; };
 +</code>
 +
 +Printing:
 +
 +<code>
 +netdev_info(ndev, "Link %s, speed %d, %s\n",
 +                  phy->link  ? "up" : "down",
 +                  phy->speed,
 +                  phy->duplex ? "duplex" : "simplex");
 +
 +</code>
 +
 +===== How many drivers use adjust_link()? =====
 +
 +<code>
 +$ grep -rwl adjust_link *
 +amd/xgbe/xgbe-mdio.c
 +freescale/fs_enet/fs_enet.h
 +freescale/fs_enet/fs_enet-main.c
 +freescale/gianfar.c
 +freescale/dpaa/dpaa_ethtool.c
 +freescale/dpaa/dpaa_eth.c
 +freescale/fman/mac.c
 +freescale/fman/mac.h
 +freescale/ucc_geth.c
 +hisilicon/hns3/hnae3.h
 +hisilicon/hns/hns_ethtool.c
 +hisilicon/hns/hns_dsaf_xgmac.c
 +hisilicon/hns/hns_dsaf_gmac.c
 +hisilicon/hns/hns_ae_adapt.c
 +hisilicon/hns/hns_dsaf_mac.h
 +hisilicon/hns/hnae.c
 +hisilicon/hns/hns_enet.c
 +hisilicon/hns/hnae.h
 +hisilicon/hns/hns_dsaf_mac.c
 +qualcomm/emac/emac-mac.c
 +$
 +</code>
 +
 +===== Examples =====
 +
 +==== freescale/fs_enet/fs_enet-main.c ====
 +
 +<code>
 +/*-----------------------------------------------------------------------------
 +  generic link-change handler - should be sufficient for most cases
 + *-----------------------------------------------------------------------------*/
 +static void generic_adjust_link(struct  net_device *dev)
 +{
 +        struct fs_enet_private *fep = netdev_priv(dev);
 +        struct phy_device *phydev = dev->phydev;
 +        int new_state = 0;
 +
 +        if (phydev->link) {
 +                /* adjust to duplex mode */
 +                if (phydev->duplex != fep->oldduplex) {
 +                        new_state = 1;
 +                        fep->oldduplex = phydev->duplex;
 +                }
 +
 +                if (phydev->speed != fep->oldspeed) {
 +                        new_state = 1;
 +                        fep->oldspeed = phydev->speed;
 +                }
 +
 +                if (!fep->oldlink) {
 +                        new_state = 1;
 +                        fep->oldlink = 1;
 +                }
 +
 +                if (new_state)
 +                        fep->ops->restart(dev);
 +        } else if (fep->oldlink) {
 +                new_state = 1;
 +                fep->oldlink = 0;
 +                fep->oldspeed = 0;
 +                fep->oldduplex = -1;
 +        }
 +
 +        if (new_state && netif_msg_link(fep))
 +                phy_print_status(phydev);
 +}
 +
 +static void fs_adjust_link(struct net_device *dev)
 +{
 +        struct fs_enet_private *fep = netdev_priv(dev);
 +        unsigned long flags;
 +
 +        spin_lock_irqsave(&fep->lock, flags);
 +
 +        if(fep->ops->adjust_link)
 +                fep->ops->adjust_link(dev);
 +        else
 +                generic_adjust_link(dev);
 +
 +        spin_unlock_irqrestore(&fep->lock, flags);
 +}
 +
 +static int fs_init_phy(struct net_device *dev)
 +{
 +        struct fs_enet_private *fep = netdev_priv(dev);
 +        struct phy_device *phydev;
 +        phy_interface_t iface;
 +
 +        fep->oldlink = 0;
 +        fep->oldspeed = 0;
 +        fep->oldduplex = -1;
 +
 +        iface = fep->fpi->use_rmii ?
 +                PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII;
 +
 +        phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0,
 +                                iface);
 +        if (!phydev) {
 +                dev_err(&dev->dev, "Could not attach to PHY\n");
 +                return -ENODEV;
 +        }
 +
 +        return 0;
 +}
 +</code>
 +
 +==== freescale/gianfar.c ====
 +
 +<code>
 +static void adjust_link(struct net_device *dev)
 +{
 +        struct gfar_private *priv = netdev_priv(dev);
 +        struct phy_device *phydev = dev->phydev;
 +
 +        if (unlikely(phydev->link != priv->oldlink ||
 +                     (phydev->link && (phydev->duplex != priv->oldduplex ||
 +                                       phydev->speed != priv->oldspeed))))
 +                gfar_update_link_state(priv);
 +}
 +</code>
 +
 +==== freescale/dpaa/dpaa_eth.c ====
 +
 +<code>
 +static void dpaa_adjust_link(struct net_device *net_dev)
 +{
 +        struct mac_device *mac_dev;
 +        struct dpaa_priv *priv;
 +
 +        priv = netdev_priv(net_dev);
 +        mac_dev = priv->mac_dev;
 +        mac_dev->adjust_link(mac_dev);
 +}
 +</code>
 +
 +==== freescale/ucc_geth.c ====
 +
 +<code>
 +/* Called every time the controller might need to be made
 + * aware of new link state.  The PHY code conveys this
 + * information through variables in the ugeth structure, and this
 + * function converts those variables into the appropriate
 + * register values, and can bring down the device if needed.
 + */
 +
 +static void adjust_link(struct net_device *dev)
 +{
 +        struct ucc_geth_private *ugeth = netdev_priv(dev);
 +        struct ucc_geth __iomem *ug_regs;
 +        struct ucc_fast __iomem *uf_regs;
 +        struct phy_device *phydev = ugeth->phydev;
 +        int new_state = 0;
 +
 +        ug_regs = ugeth->ug_regs;
 +        uf_regs = ugeth->uccf->uf_regs;
 +
 +        if (phydev->link) { ...
 +</code>
 +
 +==== hisilicon/hns/hns_enet.c ====
 +
 +<code>
 +/**
 + *hns_nic_adjust_link - adjust net work mode by the phy stat or new param
 + *@ndev: net device
 + */
 +static void hns_nic_adjust_link(struct net_device *ndev)
 +{
 +        struct hns_nic_priv *priv = netdev_priv(ndev);
 +        struct hnae_handle *h = priv->ae_handle;
 +        int state = 1;
 +
 +        if (ndev->phydev) {
 +                h->dev->ops->adjust_link(h, ndev->phydev->speed,
 +                                         ndev->phydev->duplex);
 +                state = ndev->phydev->link;
 +        }
 +        state = state && h->dev->ops->get_status(h);
  
 +        if (state != priv->link) {
 +                if (state) {
 +                        netif_carrier_on(ndev);
 +                        netif_tx_wake_all_queues(ndev);
 +                        netdev_info(ndev, "link up\n");
 +                } else {
 +                        netif_carrier_off(ndev);
 +                        netdev_info(ndev, "link down\n");
 +                }
 +                priv->link = state;
 +        }
 +}
 </code> </code>
  • phy_link_update.1535449726.txt.gz
  • Last modified: 2018/08/28 09:48
  • by rpjday