All of lore.kernel.org
 help / color / mirror / Atom feed
From: jonnyc@amazon.com (Chocron, Jonathan)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH net-next 4/8] net: ethernet: add the Alpine Ethernet driver
Date: Sun, 27 Aug 2017 13:47:19 +0000	[thread overview]
Message-ID: <1503841641816.62526@amazon.com> (raw)
In-Reply-To: <20170203205823.GA22572@lunn.ch>

This is a fixed version of my previous response (using proper indentation and leaving only the specific questions responded to).

> > +/* MDIO */
> > +#define AL_ETH_MDIO_C45_DEV_MASK     0x1f0000
> > +#define AL_ETH_MDIO_C45_DEV_SHIFT    16
> > +#define AL_ETH_MDIO_C45_REG_MASK     0xffff
> > +
> > +static int al_mdio_read(struct mii_bus *bp, int mii_id, int reg)
> > +{
> > +     struct al_eth_adapter *adapter = bp->priv;
> > +     u16 value = 0;
> > +     int rc;
> > +     int timeout = MDIO_TIMEOUT_MSEC;
> > +
> > +     while (timeout > 0) {
> > +             if (reg & MII_ADDR_C45) {
> > +                     netdev_dbg(adapter->netdev, "[c45]: dev %x reg %x val %x\n",
> > +                                ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
> > +                                (reg & AL_ETH_MDIO_C45_REG_MASK), value);
> > +                     rc = al_eth_mdio_read(&adapter->hw_adapter, adapter->phy_addr,
> > +                             ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
> > +                             (reg & AL_ETH_MDIO_C45_REG_MASK), &value);
> > +             } else {
> > +                     rc = al_eth_mdio_read(&adapter->hw_adapter, adapter->phy_addr,
> > +                                           MDIO_DEVAD_NONE, reg, &value);
> > +             }
> > +
> > +             if (rc == 0)
> > +                     return value;
> > +
> > +             netdev_dbg(adapter->netdev,
> > +                        "mdio read failed. try again in 10 msec\n");
> > +
> > +             timeout -= 10;
> > +             msleep(10);
> > +     }
> 
> This is rather unusual, retrying MDIO operations. Are you working
> around a hardware bug? I suspect this also opens up race conditions,
> in particular with PHY interrupts, which can be clear on read.

The MDIO bus is shared between the ethernet units. There is a HW lock used to arbitrate between different interfaces trying to access the bus, 
therefore there is a retry loop. The reg isn't accessed before obtaining the lock, so there shouldn't be any clear on read issues.

> > +/* al_eth_mdiobus_setup - initialize mdiobus and register to kernel */
> > +static int al_eth_mdiobus_setup(struct al_eth_adapter *adapter)
> > +{
> > +     struct phy_device *phydev;
> > +     int i;
> > +     int ret = 0;
> > +
> > +     adapter->mdio_bus = mdiobus_alloc();
> > +     if (!adapter->mdio_bus)
> > +             return -ENOMEM;
> > +
> > +     adapter->mdio_bus->name     = "al mdio bus";
> > +     snprintf(adapter->mdio_bus->id, MII_BUS_ID_SIZE, "%x",
> > +              (adapter->pdev->bus->number << 8) | adapter->pdev->devfn);
> > +     adapter->mdio_bus->priv     = adapter;
> > +     adapter->mdio_bus->parent   = &adapter->pdev->dev;
> > +     adapter->mdio_bus->read     = &al_mdio_read;
> > +     adapter->mdio_bus->write    = &al_mdio_write;
> > +     adapter->mdio_bus->phy_mask = ~BIT(adapter->phy_addr);
>
> Why do this?

Since the MDIO bus is shared, we want each interface to probe only for the PHY associated with it.

> > + * acquire mdio interface ownership
> > + * when mdio interface shared between multiple eth controllers, this function waits until the ownership granted for this controller.
> > + * this function does nothing when the mdio interface is used only by this controller.
> > + *
> > + * @param adapter
> > + * @return 0 on success, -ETIMEDOUT  on timeout.
> > + */
> > +static int al_eth_mdio_lock(struct al_hw_eth_adapter *adapter)
> > +{
> > +     int count = 0;
> > +     u32 mdio_ctrl_1;
> > +
> > +     if (!adapter->shared_mdio_if)
> > +             return 0; /* nothing to do when interface is not shared */
> > +
> > +     do {
> > +             mdio_ctrl_1 = readl(&adapter->mac_regs_base->gen.mdio_ctrl_1);
> > +             if (mdio_ctrl_1 & BIT(0)) {
> > +                     if (count > 0)
> > +                             netdev_dbg(adapter->netdev,
> > +                                        "eth %s mdio interface still busy!\n",
> > +                                        adapter->name);
> > +             } else {
> > +                     return 0;
> > +             }
> > +             udelay(AL_ETH_MDIO_DELAY_PERIOD);
> > +     } while (count++ < (AL_ETH_MDIO_DELAY_COUNT * 4));
>
> This needs explaining. How can a read alone perform a lock? How is
> this race free?

This is how this HW lock works: when the bit is 0 this means the lock is free. When a read transaction arrives
to the lock, it changes its value to 1 but sends 0 as the response, basically taking ownership.
When the owner is done, it writes  a 0 which essentially "frees" the lock.

> > +             if (adapter->mdio_type == AL_ETH_MDIO_TYPE_CLAUSE_22)
> > +                     rc = al_eth_mdio_10g_mac_type22(adapter, 1, phy_addr,
> > +                                                     reg, val);
> > +             else
> > +                     rc = al_eth_mdio_10g_mac_type45(adapter, 1, phy_addr,
> > +                                                     device, reg, val);
> 
> This seems odd. My understanding is that the device on the MDIO bus,
> the PHY, is either c22 or c45. The PHY driver will tell you this, not
> the adaptor.
 
The current implementation sets mdio_type according to information which is originally deduced from the
DeviceTree (the bootloader parses the ethernet node of the DeviceTree and saves this data to HW registers, which are then read by this driver).
How can this information be obtained by the PHY driver?

>    Andrew

Jonathan

WARNING: multiple messages have this Message-ID (diff)
From: "Chocron, Jonathan" <jonnyc@amazon.com>
To: Andrew Lunn <andrew@lunn.ch>,
	Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"davem@davemloft.net" <davem@davemloft.net>,
	"linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>,
	"thomas.petazzoni@free-electrons.com"
	<thomas.petazzoni@free-electrons.com>,
	"arnd@arndb.de" <arnd@arndb.de>
Subject: Re: [PATCH net-next 4/8] net: ethernet: add the Alpine Ethernet driver
Date: Sun, 27 Aug 2017 13:47:19 +0000	[thread overview]
Message-ID: <1503841641816.62526@amazon.com> (raw)
In-Reply-To: <20170203205823.GA22572@lunn.ch>

This is a fixed version of my previous response (using proper indentation and leaving only the specific questions responded to).

> > +/* MDIO */
> > +#define AL_ETH_MDIO_C45_DEV_MASK     0x1f0000
> > +#define AL_ETH_MDIO_C45_DEV_SHIFT    16
> > +#define AL_ETH_MDIO_C45_REG_MASK     0xffff
> > +
> > +static int al_mdio_read(struct mii_bus *bp, int mii_id, int reg)
> > +{
> > +     struct al_eth_adapter *adapter = bp->priv;
> > +     u16 value = 0;
> > +     int rc;
> > +     int timeout = MDIO_TIMEOUT_MSEC;
> > +
> > +     while (timeout > 0) {
> > +             if (reg & MII_ADDR_C45) {
> > +                     netdev_dbg(adapter->netdev, "[c45]: dev %x reg %x val %x\n",
> > +                                ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
> > +                                (reg & AL_ETH_MDIO_C45_REG_MASK), value);
> > +                     rc = al_eth_mdio_read(&adapter->hw_adapter, adapter->phy_addr,
> > +                             ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
> > +                             (reg & AL_ETH_MDIO_C45_REG_MASK), &value);
> > +             } else {
> > +                     rc = al_eth_mdio_read(&adapter->hw_adapter, adapter->phy_addr,
> > +                                           MDIO_DEVAD_NONE, reg, &value);
> > +             }
> > +
> > +             if (rc == 0)
> > +                     return value;
> > +
> > +             netdev_dbg(adapter->netdev,
> > +                        "mdio read failed. try again in 10 msec\n");
> > +
> > +             timeout -= 10;
> > +             msleep(10);
> > +     }
> 
> This is rather unusual, retrying MDIO operations. Are you working
> around a hardware bug? I suspect this also opens up race conditions,
> in particular with PHY interrupts, which can be clear on read.

The MDIO bus is shared between the ethernet units. There is a HW lock used to arbitrate between different interfaces trying to access the bus, 
therefore there is a retry loop. The reg isn't accessed before obtaining the lock, so there shouldn't be any clear on read issues.

> > +/* al_eth_mdiobus_setup - initialize mdiobus and register to kernel */
> > +static int al_eth_mdiobus_setup(struct al_eth_adapter *adapter)
> > +{
> > +     struct phy_device *phydev;
> > +     int i;
> > +     int ret = 0;
> > +
> > +     adapter->mdio_bus = mdiobus_alloc();
> > +     if (!adapter->mdio_bus)
> > +             return -ENOMEM;
> > +
> > +     adapter->mdio_bus->name     = "al mdio bus";
> > +     snprintf(adapter->mdio_bus->id, MII_BUS_ID_SIZE, "%x",
> > +              (adapter->pdev->bus->number << 8) | adapter->pdev->devfn);
> > +     adapter->mdio_bus->priv     = adapter;
> > +     adapter->mdio_bus->parent   = &adapter->pdev->dev;
> > +     adapter->mdio_bus->read     = &al_mdio_read;
> > +     adapter->mdio_bus->write    = &al_mdio_write;
> > +     adapter->mdio_bus->phy_mask = ~BIT(adapter->phy_addr);
>
> Why do this?

Since the MDIO bus is shared, we want each interface to probe only for the PHY associated with it.

> > + * acquire mdio interface ownership
> > + * when mdio interface shared between multiple eth controllers, this function waits until the ownership granted for this controller.
> > + * this function does nothing when the mdio interface is used only by this controller.
> > + *
> > + * @param adapter
> > + * @return 0 on success, -ETIMEDOUT  on timeout.
> > + */
> > +static int al_eth_mdio_lock(struct al_hw_eth_adapter *adapter)
> > +{
> > +     int count = 0;
> > +     u32 mdio_ctrl_1;
> > +
> > +     if (!adapter->shared_mdio_if)
> > +             return 0; /* nothing to do when interface is not shared */
> > +
> > +     do {
> > +             mdio_ctrl_1 = readl(&adapter->mac_regs_base->gen.mdio_ctrl_1);
> > +             if (mdio_ctrl_1 & BIT(0)) {
> > +                     if (count > 0)
> > +                             netdev_dbg(adapter->netdev,
> > +                                        "eth %s mdio interface still busy!\n",
> > +                                        adapter->name);
> > +             } else {
> > +                     return 0;
> > +             }
> > +             udelay(AL_ETH_MDIO_DELAY_PERIOD);
> > +     } while (count++ < (AL_ETH_MDIO_DELAY_COUNT * 4));
>
> This needs explaining. How can a read alone perform a lock? How is
> this race free?

This is how this HW lock works: when the bit is 0 this means the lock is free. When a read transaction arrives
to the lock, it changes its value to 1 but sends 0 as the response, basically taking ownership.
When the owner is done, it writes  a 0 which essentially "frees" the lock.

> > +             if (adapter->mdio_type == AL_ETH_MDIO_TYPE_CLAUSE_22)
> > +                     rc = al_eth_mdio_10g_mac_type22(adapter, 1, phy_addr,
> > +                                                     reg, val);
> > +             else
> > +                     rc = al_eth_mdio_10g_mac_type45(adapter, 1, phy_addr,
> > +                                                     device, reg, val);
> 
> This seems odd. My understanding is that the device on the MDIO bus,
> the PHY, is either c22 or c45. The PHY driver will tell you this, not
> the adaptor.
 
The current implementation sets mdio_type according to information which is originally deduced from the
DeviceTree (the bootloader parses the ethernet node of the DeviceTree and saves this data to HW registers, which are then read by this driver).
How can this information be obtained by the PHY driver?

>    Andrew

Jonathan

  parent reply	other threads:[~2017-08-27 13:47 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-03 18:12 [PATCH net-next 0/8] ARM: Alpine: Ethernet support Antoine Tenart
2017-02-03 18:12 ` Antoine Tenart
2017-02-03 18:12 ` [PATCH net-next 1/8] alpine: add I/O fabric interrupt controller (iofic) helpers Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart
2017-02-03 18:12 ` [PATCH net-next 2/8] soc: alpine: add udma helpers Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart
2017-02-03 18:12 ` [PATCH net-next 3/8] pci: add Annapurna Labs PCI id Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart
2017-02-03 18:12 ` [PATCH net-next 4/8] net: ethernet: add the Alpine Ethernet driver Antoine Tenart
2017-02-03 20:58   ` Andrew Lunn
2017-02-03 20:58     ` Andrew Lunn
2017-08-07  7:39     ` Chocron, Jonathan
2017-08-07  7:39       ` Chocron, Jonathan
2017-08-27 13:47     ` Chocron, Jonathan [this message]
2017-08-27 13:47       ` Chocron, Jonathan
2017-08-28 18:09       ` Andrew Lunn
2017-08-28 18:09         ` Andrew Lunn
2017-11-02 16:05         ` Chocron, Jonathan
2017-11-02 16:05           ` Chocron, Jonathan
2017-11-02 18:19           ` Florian Fainelli
2017-11-02 18:19             ` Florian Fainelli
2017-11-05 12:29             ` BSHARA, Said
2017-11-05 12:29               ` BSHARA, Said
2017-11-05 15:22               ` Andrew Lunn
2017-11-05 15:22                 ` Andrew Lunn
2017-02-03 18:12 ` [PATCH net-next 5/8] net: ethernet: annapurna: add statistics helper Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart
2017-02-03 19:34   ` Florian Fainelli
2017-02-03 19:34     ` Florian Fainelli
2017-02-03 21:24   ` kbuild test robot
2017-02-03 21:24     ` kbuild test robot
2017-02-03 18:12 ` [PATCH net-next 6/8] net: ethernet: annapurna: add wol helpers to the Alpine driver Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart
2017-02-03 18:21   ` Sergei Shtylyov
2017-02-03 18:21     ` Sergei Shtylyov
2017-02-06 11:35     ` David Laight
2017-02-06 11:35       ` David Laight
2017-02-06 12:02       ` Sergei Shtylyov
2017-02-06 12:02         ` Sergei Shtylyov
2017-02-10 10:12       ` Antoine Tenart
2017-02-10 10:12         ` Antoine Tenart
2017-02-03 18:12 ` [PATCH net-next 7/8] net: ethernet: annapurna: add eee " Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart
2017-02-03 19:01   ` Florian Fainelli
2017-02-03 19:01     ` Florian Fainelli
2017-02-03 18:12 ` [PATCH net-next 8/8] net: ethernet: annapurna: add the coalesce " Antoine Tenart
2017-02-03 18:12   ` Antoine Tenart

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=1503841641816.62526@amazon.com \
    --to=jonnyc@amazon.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /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.