From: Antoine Tenart <antoine.tenart@bootlin.com>
To: Russell King - ARM Linux admin <linux@armlinux.org.uk>
Cc: Andrew Lunn <andrew@lunn.ch>,
Antoine Tenart <antoine.tenart@bootlin.com>,
davem@davemloft.net, alexandre.belloni@bootlin.com,
nicolas.ferre@microchip.com, netdev@vger.kernel.org,
thomas.petazzoni@bootlin.com
Subject: Re: [PATCH net-next] net: macb: convert to phylink
Date: Wed, 23 Oct 2019 11:07:57 +0200 [thread overview]
Message-ID: <20191023090757.GA3355@kwain> (raw)
In-Reply-To: <20191018200823.GK25745@shell.armlinux.org.uk>
Hi Russell,
Sorry for not including you at first on this patch, I'll make sure I do
for v2.
On Fri, Oct 18, 2019 at 09:08:23PM +0100, Russell King - ARM Linux admin wrote:
> On Fri, Oct 18, 2019 at 09:08:10PM +0200, Andrew Lunn wrote:
> > On Fri, Oct 18, 2019 at 04:39:24PM +0200, Antoine Tenart wrote:
> > > +
> > > +static int macb_mac_link_state(struct phylink_config *config,
> > > + struct phylink_link_state *state)
> > > +{
> > > + return -EOPNOTSUPP;
>
> Without this implemented, phylink can't support in-band link modes
> necessary for SFP support. Since phylink is mostly about supporting
> SFP cages and similar, I'm not sure what the point is.
See the answer below.
> > > +static void macb_mac_config(struct phylink_config *config, unsigned int mode,
> > > + const struct phylink_link_state *state)
> > > +{
> > > + struct net_device *ndev = to_net_dev(config->dev);
> > > + struct macb *bp = netdev_priv(ndev);
> > > unsigned long flags;
> > > - int status_change = 0;
> > > + u32 old_ctrl, ctrl;
> > >
> > > spin_lock_irqsave(&bp->lock, flags);
> > >
> > > - if (phydev->link) {
> > > - if ((bp->speed != phydev->speed) ||
> > > - (bp->duplex != phydev->duplex)) {
> > > - u32 reg;
> > > + old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR);
> > >
> > > - reg = macb_readl(bp, NCFGR);
> > > - reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
> > > - if (macb_is_gem(bp))
> > > - reg &= ~GEM_BIT(GBE);
> > > + /* Clear all the bits we might set later */
> > > + ctrl &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD) | MACB_BIT(PAE) |
> > > + GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));
> > >
> > > - if (phydev->duplex)
> > > - reg |= MACB_BIT(FD);
> > > - if (phydev->speed == SPEED_100)
> > > - reg |= MACB_BIT(SPD);
> > > - if (phydev->speed == SPEED_1000 &&
> > > - bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
> > > - reg |= GEM_BIT(GBE);
> > > + if (state->speed == SPEED_1000)
> > > + ctrl |= GEM_BIT(GBE);
> > > + else if (state->speed == SPEED_100)
> > > + ctrl |= MACB_BIT(SPD);
> > >
> > > - macb_or_gem_writel(bp, NCFGR, reg);
> > > + if (state->duplex)
> > > + ctrl |= MACB_BIT(FD);
> > >
> > > - bp->speed = phydev->speed;
> > > - bp->duplex = phydev->duplex;
> > > - status_change = 1;
> > > - }
> > > - }
> > > + /* We do not support MLO_PAUSE_RX yet */
> > > + if (state->pause & MLO_PAUSE_TX)
> > > + ctrl |= MACB_BIT(PAE);
> > >
> > > - if (phydev->link != bp->link) {
> > > - if (!phydev->link) {
> > > - bp->speed = 0;
> > > - bp->duplex = -1;
> > > - }
> > > - bp->link = phydev->link;
> > > + if (state->interface == PHY_INTERFACE_MODE_SGMII)
> > > + ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
>
> Hmm, so you support SGMII but have no way to read the results of SGMII
> negotiation?
That seemed odd, I did not find a way to get the status (at least in the
datasheet I was using). I sent a first version without link_state being
implemented, but I'll double check now.
> > > + /* Apply the new configuration, if any */
> > > + if (old_ctrl ^ ctrl) {
> > > + macb_or_gem_writel(bp, NCFGR, ctrl);
> > >
> > > - status_change = 1;
> > > + if (state->link)
> > > + macb_set_tx_clk(bp->tx_clk, state->speed, ndev);
>
> Please see include/linux/phylink.h for documentation on the mac_config()
> method. It exhaustively describes which members of the state are valid
> for each value of "mode", and describes which are not valid to be used.
> "state->link" is one such case of an invalid use.
I'll have a look at this. I may be done in link_up as well, where we
know the state of the link.
> > > +static int macb_phylink_connect(struct macb *bp)
> > > +{
> > > + struct net_device *dev = bp->dev;
> > > + struct phy_device *phydev;
> > > + int ret;
> > > +
> > > + if (bp->phy_node) {
> > > + ret = phylink_of_phy_connect(bp->phylink, bp->phy_node, 0);
>
> This looks quite odd.
>
> phylink expects the second argument to always be the container device
> node of the "phy-handle", "phy" or "phy-device" property, never the
> node of the PHY itself. Looking at how the driver sets up
> bp->phy_node, it is the PHY's node itself sometimes, and in that case
> will almost certainly fail.
That right, thanks for spotting this. I'll fix it.
> > > + if (ret) {
> > > + netdev_err(dev, "Could not attach PHY (%d)\n", ret);
> > > + return ret;
> > > + }
> > > + } else {
> > > + phydev = phy_find_first(bp->mii_bus);
> > > + if (!phydev) {
> > > + netdev_err(dev, "no PHY found\n");
> > > + return -ENXIO;
> > > + }
> > > +
> > > + /* attach the mac to the phy */
> > > + ret = phylink_connect_phy(bp->phylink, phydev);
> > > + if (ret) {
> > > + netdev_err(dev, "Could not attach to PHY (%d)\n", ret);
> > > + return ret;
> > > }
>
> I'm not entirely sure what this is trying to achieve.
You may not have a "phy" property in the MAC node with this driver, so I
kept the logic of what was done previously, using phy_find_first() when
the phy isn't described in the dt. Do you suggest another approach?
> > > }
> > > +
> > > + phylink_start(bp->phylink);
>
> You're ready to handle a link-up event at this point in the driver?
Yes, the h/w is initialized, and we can handle link events.
> > > static int macb_open(struct net_device *dev)
> > > {
> > > - struct macb *bp = netdev_priv(dev);
> > > size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN;
> > > + struct macb *bp = netdev_priv(dev);
> > > struct macb_queue *queue;
> > > unsigned int q;
> > > int err;
> > > @@ -2417,12 +2480,6 @@ static int macb_open(struct net_device *dev)
> > > /* carrier starts down */
> > > netif_carrier_off(dev);
>
> Note, that's included in phylink_start().
That's right, I added it to phylink_start... :) I'll fix it.
> > > @@ -2467,8 +2524,8 @@ static int macb_close(struct net_device *dev)
> > > for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
> > > napi_disable(&queue->napi);
> > >
> > > - if (dev->phydev)
> > > - phy_stop(dev->phydev);
> > > + phylink_stop(bp->phylink);
> > > + phylink_disconnect_phy(bp->phylink);
>
> This is fine if _this_ driver was the one to attach the PHY, otherwise
> it will disconnect someone else's PHY (eg, the copper SFP PHY if this
> driver supports SFPs.)
Do you suggest removing this? I'm seeing lots (all?) of phylink
converted drivers to still call this, what's the reasoning behind that?
> > > @@ -2703,8 +2760,9 @@ static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
> > > wol->wolopts = 0;
> > >
> > > if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) {
> > > - wol->supported = WAKE_MAGIC;
> > > + phylink_ethtool_get_wol(bp->phylink, wol);
> > >
> > > + wol->supported |= WAKE_MAGIC;
> > > if (bp->wol & MACB_WOL_ENABLED)
> > > wol->wolopts |= WAKE_MAGIC;
>
> I'm not sure that the logic here is actually correct. What would be
> the result if the PHY has WOL disabled but bp->wol has both these
> enabled?
That's a good question. We could check if there's a PHY, and if so make
sure it supports WOL before setting those bits.
> > > static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> > > {
> > > - struct phy_device *phydev = dev->phydev;
> > > struct macb *bp = netdev_priv(dev);
> > >
> > > if (!netif_running(dev))
> > > return -EINVAL;
> > >
> > > - if (!phydev)
> > > - return -ENODEV;
> > > -
> > > if (!bp->ptp_info)
> > > - return phy_mii_ioctl(phydev, rq, cmd);
> > > + return phylink_mii_ioctl(bp->phylink, rq, cmd);
> > >
> > > switch (cmd) {
> > > case SIOCSHWTSTAMP:
> > > @@ -3206,7 +3281,7 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> > > case SIOCGHWTSTAMP:
> > > return bp->ptp_info->get_hwtst(dev, rq);
> > > default:
> > > - return phy_mii_ioctl(phydev, rq, cmd);
> > > + return phylink_mii_ioctl(bp->phylink, rq, cmd);
> > > }
>
> This can probably be cleaned up - move
>
> return phylink_mii_ioctl(bp->phylink, rq, cmd);
>
> to the bottom, and just make the switch() conditional on bp->ptp_info
> being non-NULL.
I'll do this.
> > > @@ -4377,18 +4448,12 @@ static int macb_remove(struct platform_device *pdev)
> > > {
> > > struct net_device *dev;
> > > struct macb *bp;
> > > - struct device_node *np = pdev->dev.of_node;
> > >
> > > dev = platform_get_drvdata(pdev);
> > >
> > > if (dev) {
> > > bp = netdev_priv(dev);
> > > - if (dev->phydev)
> > > - phy_disconnect(dev->phydev);
> > > mdiobus_unregister(bp->mii_bus);
> > > - if (np && of_phy_is_fixed_link(np))
> > > - of_phy_deregister_fixed_link(np);
> > > - dev->phydev = NULL;
> > > mdiobus_free(bp->mii_bus);
> > >
> > > unregister_netdev(dev);
> > > @@ -4403,7 +4468,6 @@ static int macb_remove(struct platform_device *pdev)
> > > clk_disable_unprepare(bp->tsu_clk);
> > > pm_runtime_set_suspended(&pdev->dev);
> > > }
> > > - of_node_put(bp->phy_node);
> > > free_netdev(dev);
> > > }
>
> Doesn't this need to cleanup phylink somewhere via a call to
> phylink_destroy() ?
You're right, I'll fix it.
> > > @@ -4421,7 +4485,6 @@ static int __maybe_unused macb_suspend(struct device *dev)
> > > if (!netif_running(netdev))
> > > return 0;
> > >
> > > -
> > > if (bp->wol & MACB_WOL_ENABLED) {
> > > macb_writel(bp, IER, MACB_BIT(WOL));
> > > macb_writel(bp, WOL, MACB_BIT(MAG));
> > > @@ -4432,8 +4495,6 @@ static int __maybe_unused macb_suspend(struct device *dev)
> > > for (q = 0, queue = bp->queues; q < bp->num_queues;
> > > ++q, ++queue)
> > > napi_disable(&queue->napi);
> > > - phy_stop(netdev->phydev);
> > > - phy_suspend(netdev->phydev);
>
> So you don't need to shutdown the phylib state machine after all?
>
> > > spin_lock_irqsave(&bp->lock, flags);
> > > macb_reset_hw(bp);
> > > spin_unlock_irqrestore(&bp->lock, flags);
> > > @@ -4481,12 +4542,8 @@ static int __maybe_unused macb_resume(struct device *dev)
> > > for (q = 0, queue = bp->queues; q < bp->num_queues;
> > > ++q, ++queue)
> > > napi_enable(&queue->napi);
> > > - phy_resume(netdev->phydev);
> > > - phy_init_hw(netdev->phydev);
> > > - phy_start(netdev->phydev);
>
> This looks like it was re-setting up the PHY, but nothing happens here
> after conversion? Do we need to add something to phylink for this?
> Has this been tested?
I made some tests but after an internal discussion it seems like I can't
test the feature myself. Someone will, and we'll probably have to add a
suspend/resume logic to phylink.
Thanks for the review!
Antoine
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
next prev parent reply other threads:[~2019-10-23 9:08 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-18 14:39 [PATCH net-next] net: macb: convert to phylink Antoine Tenart
2019-10-18 14:52 ` Alexandre Belloni
2019-10-18 19:08 ` Andrew Lunn
2019-10-18 20:08 ` Russell King - ARM Linux admin
2019-10-22 12:24 ` Alexandre Belloni
2019-10-23 9:07 ` Antoine Tenart [this message]
2019-10-18 19:14 ` Andrew Lunn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191023090757.GA3355@kwain \
--to=antoine.tenart@bootlin.com \
--cc=alexandre.belloni@bootlin.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=nicolas.ferre@microchip.com \
--cc=thomas.petazzoni@bootlin.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.