* [PATCH 1/4] net: macb: add phylink support
2019-11-08 13:33 [PATCH 0/4] net: macb: cover letter Milind Parab
@ 2019-11-08 13:34 ` Milind Parab
2019-11-08 15:42 ` Antoine Tenart
2019-11-08 13:34 ` [PATCH 2/4] net: macb: add support for sgmii MAC-PHY interface Milind Parab
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Milind Parab @ 2019-11-08 13:34 UTC (permalink / raw)
To: andrew, nicolas.ferre, davem, f.fainelli
Cc: netdev, hkallweit1, linux-kernel, piotrs, dkangude, ewanm,
arthurm, stevenh, Milind Parab
This patch replace phylib API's by phylink API's.
Signed-off-by: Milind Parab <mparab@cadence.com>
---
drivers/net/ethernet/cadence/Kconfig | 2 +-
drivers/net/ethernet/cadence/macb.h | 3 +
drivers/net/ethernet/cadence/macb_main.c | 326 ++++++++++++++++-------------
3 files changed, 184 insertions(+), 147 deletions(-)
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index f4b3bd8..53b50c2 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -22,7 +22,7 @@ if NET_VENDOR_CADENCE
config MACB
tristate "Cadence MACB/GEM support"
depends on HAS_DMA && COMMON_CLK
- select PHYLIB
+ select PHYLINK
---help---
The Cadence MACB ethernet interface is found on many Atmel AT32 and
AT91 parts. This driver also supports the Cadence GEM (Gigabit
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 03983bd..a400705 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -11,6 +11,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/interrupt.h>
+#include <linux/phylink.h>
#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP)
#define MACB_EXT_DESC
@@ -1232,6 +1233,8 @@ struct macb {
u32 rx_intr_mask;
struct macb_pm_data pm_data;
+ struct phylink *pl;
+ struct phylink_config pl_config;
};
#ifdef CONFIG_MACB_USE_HWSTAMP
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index b884cf7..15016ff 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -432,115 +432,160 @@ static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev)
netdev_err(dev, "adjusting tx_clk failed.\n");
}
-static void macb_handle_link_change(struct net_device *dev)
+static void gem_phylink_validate(struct phylink_config *pl_config,
+ unsigned long *supported,
+ struct phylink_link_state *state)
{
- struct macb *bp = netdev_priv(dev);
- struct phy_device *phydev = dev->phydev;
+ struct net_device *netdev = to_net_dev(pl_config->dev);
+ struct macb *bp = netdev_priv(netdev);
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_RGMII:
+ if (!macb_is_gem(bp))
+ goto empty_set;
+ break;
+ default:
+ break;
+ }
+
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_RGMII:
+ if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) {
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+ if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
+ phylink_set(mask, 1000baseT_Half);
+ }
+ /* fallthrough */
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_RMII:
+ phylink_set(mask, 10baseT_Half);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Half);
+ phylink_set(mask, 100baseT_Full);
+ break;
+ default:
+ goto empty_set;
+ }
+
+ linkmode_and(supported, supported, mask);
+ linkmode_and(state->advertising, state->advertising, mask);
+ return;
+
+empty_set:
+ linkmode_zero(supported);
+}
+
+static int gem_phylink_mac_link_state(struct phylink_config *pl_config,
+ struct phylink_link_state *state)
+{
+ return -EOPNOTSUPP;
+}
+
+static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct net_device *netdev = to_net_dev(pl_config->dev);
+ struct macb *bp = netdev_priv(netdev);
+ bool change_interface = bp->phy_interface != state->interface;
unsigned long flags;
- int status_change = 0;
spin_lock_irqsave(&bp->lock, flags);
- if (phydev->link) {
- if ((bp->speed != phydev->speed) ||
- (bp->duplex != phydev->duplex)) {
- u32 reg;
+ if (change_interface)
+ bp->phy_interface = state->interface;
- reg = macb_readl(bp, NCFGR);
- reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
- if (macb_is_gem(bp))
- reg &= ~GEM_BIT(GBE);
+ if (!phylink_autoneg_inband(mode) &&
+ (bp->speed != state->speed ||
+ bp->duplex != state->duplex)) {
+ u32 reg;
- 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);
-
- macb_or_gem_writel(bp, NCFGR, reg);
+ reg = macb_readl(bp, NCFGR);
+ reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+ if (macb_is_gem(bp))
+ reg &= ~GEM_BIT(GBE);
+ if (state->duplex)
+ reg |= MACB_BIT(FD);
- bp->speed = phydev->speed;
- bp->duplex = phydev->duplex;
- status_change = 1;
+ switch (state->speed) {
+ case SPEED_1000:
+ reg |= GEM_BIT(GBE);
+ break;
+ case SPEED_100:
+ reg |= MACB_BIT(SPD);
+ break;
+ default:
+ break;
}
- }
+ macb_or_gem_writel(bp, NCFGR, reg);
- if (phydev->link != bp->link) {
- if (!phydev->link) {
- bp->speed = 0;
- bp->duplex = -1;
- }
- bp->link = phydev->link;
+ bp->speed = state->speed;
+ bp->duplex = state->duplex;
- status_change = 1;
+ if (state->link)
+ macb_set_tx_clk(bp->tx_clk, state->speed, netdev);
}
spin_unlock_irqrestore(&bp->lock, flags);
+}
- if (status_change) {
- if (phydev->link) {
- /* Update the TX clock rate if and only if the link is
- * up and there has been a link change.
- */
- macb_set_tx_clk(bp->tx_clk, phydev->speed, dev);
+static void gem_mac_link_up(struct phylink_config *pl_config, unsigned int mode,
+ phy_interface_t interface, struct phy_device *phy)
+{
+ struct net_device *netdev = to_net_dev(pl_config->dev);
+ struct macb *bp = netdev_priv(netdev);
- netif_carrier_on(dev);
- netdev_info(dev, "link up (%d/%s)\n",
- phydev->speed,
- phydev->duplex == DUPLEX_FULL ?
- "Full" : "Half");
- } else {
- netif_carrier_off(dev);
- netdev_info(dev, "link down\n");
- }
- }
+ bp->link = 1;
+ /* Enable TX and RX */
+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE));
}
+static void gem_mac_link_down(struct phylink_config *pl_config,
+ unsigned int mode, phy_interface_t interface)
+{
+ struct net_device *netdev = to_net_dev(pl_config->dev);
+ struct macb *bp = netdev_priv(netdev);
+
+ bp->link = 0;
+ /* Disable TX and RX */
+ macb_writel(bp, NCR,
+ macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE)));
+}
+
+static const struct phylink_mac_ops gem_phylink_ops = {
+ .validate = gem_phylink_validate,
+ .mac_link_state = gem_phylink_mac_link_state,
+ .mac_config = gem_mac_config,
+ .mac_link_up = gem_mac_link_up,
+ .mac_link_down = gem_mac_link_down,
+};
+
/* based on au1000_eth. c*/
-static int macb_mii_probe(struct net_device *dev)
+static int macb_mii_probe(struct net_device *dev, phy_interface_t phy_mode)
{
struct macb *bp = netdev_priv(dev);
struct phy_device *phydev;
struct device_node *np;
- int ret, i;
+ int ret;
np = bp->pdev->dev.of_node;
ret = 0;
- if (np) {
- if (of_phy_is_fixed_link(np)) {
- bp->phy_node = of_node_get(np);
- } else {
- bp->phy_node = of_parse_phandle(np, "phy-handle", 0);
- /* fallback to standard phy registration if no
- * phy-handle was found nor any phy found during
- * dt phy registration
- */
- if (!bp->phy_node && !phy_find_first(bp->mii_bus)) {
- for (i = 0; i < PHY_MAX_ADDR; i++) {
- phydev = mdiobus_scan(bp->mii_bus, i);
- if (IS_ERR(phydev) &&
- PTR_ERR(phydev) != -ENODEV) {
- ret = PTR_ERR(phydev);
- break;
- }
- }
-
- if (ret)
- return -ENODEV;
- }
- }
+ bp->pl_config.dev = &dev->dev;
+ bp->pl_config.type = PHYLINK_NETDEV;
+ bp->pl = phylink_create(&bp->pl_config, of_fwnode_handle(np),
+ phy_mode, &gem_phylink_ops);
+ if (IS_ERR(bp->pl)) {
+ netdev_err(dev,
+ "error creating PHYLINK: %ld\n", PTR_ERR(bp->pl));
+ return PTR_ERR(bp->pl);
}
- if (bp->phy_node) {
- phydev = of_phy_connect(dev, bp->phy_node,
- &macb_handle_link_change, 0,
- bp->phy_interface);
- if (!phydev)
- return -ENODEV;
- } else {
+ ret = phylink_of_phy_connect(bp->pl, np, 0);
+ if (ret == -ENODEV && bp->mii_bus) {
phydev = phy_find_first(bp->mii_bus);
if (!phydev) {
netdev_err(dev, "no PHY found\n");
@@ -548,32 +593,22 @@ static int macb_mii_probe(struct net_device *dev)
}
/* attach the mac to the phy */
- ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
- bp->phy_interface);
+ ret = phylink_connect_phy(bp->pl, phydev);
if (ret) {
netdev_err(dev, "Could not attach to PHY\n");
return ret;
}
}
- /* mask with MAC supported features */
- if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
- phy_set_max_speed(phydev, SPEED_1000);
- else
- phy_set_max_speed(phydev, SPEED_100);
-
- if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF)
- phy_remove_link_mode(phydev,
- ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
-
bp->link = 0;
- bp->speed = 0;
- bp->duplex = -1;
+ bp->speed = SPEED_UNKNOWN;
+ bp->duplex = DUPLEX_UNKNOWN;
+ bp->phy_interface = PHY_INTERFACE_MODE_MAX;
- return 0;
+ return ret;
}
-static int macb_mii_init(struct macb *bp)
+static int macb_mii_init(struct macb *bp, phy_interface_t phy_mode)
{
struct device_node *np;
int err = -ENXIO;
@@ -598,22 +633,12 @@ static int macb_mii_init(struct macb *bp)
dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
np = bp->pdev->dev.of_node;
- if (np && of_phy_is_fixed_link(np)) {
- if (of_phy_register_fixed_link(np) < 0) {
- dev_err(&bp->pdev->dev,
- "broken fixed-link specification %pOF\n", np);
- goto err_out_free_mdiobus;
- }
-
- err = mdiobus_register(bp->mii_bus);
- } else {
- err = of_mdiobus_register(bp->mii_bus, np);
- }
+ err = of_mdiobus_register(bp->mii_bus, np);
if (err)
goto err_out_free_fixed_link;
- err = macb_mii_probe(bp->dev);
+ err = macb_mii_probe(bp->dev, phy_mode);
if (err)
goto err_out_unregister_bus;
@@ -624,7 +649,6 @@ static int macb_mii_init(struct macb *bp)
err_out_free_fixed_link:
if (np && of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
-err_out_free_mdiobus:
of_node_put(bp->phy_node);
mdiobus_free(bp->mii_bus);
err_out:
@@ -2417,12 +2441,6 @@ static int macb_open(struct net_device *dev)
/* carrier starts down */
netif_carrier_off(dev);
- /* if the phy is not yet register, retry later*/
- if (!dev->phydev) {
- err = -EAGAIN;
- goto pm_exit;
- }
-
/* RX buffers initialization */
macb_init_rx_buffer_size(bp, bufsz);
@@ -2440,7 +2458,7 @@ static int macb_open(struct net_device *dev)
macb_init_hw(bp);
/* schedule a link state check */
- phy_start(dev->phydev);
+ phylink_start(bp->pl);
netif_tx_start_all_queues(dev);
@@ -2467,8 +2485,7 @@ 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->pl);
spin_lock_irqsave(&bp->lock, flags);
macb_reset_hw(bp);
@@ -3157,6 +3174,23 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
return ret;
}
+static int gem_ethtool_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct macb *bp = netdev_priv(netdev);
+
+ return phylink_ethtool_ksettings_get(bp->pl, cmd);
+}
+
+static int
+gem_ethtool_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct macb *bp = netdev_priv(netdev);
+
+ return phylink_ethtool_ksettings_set(bp->pl, cmd);
+}
+
static const struct ethtool_ops macb_ethtool_ops = {
.get_regs_len = macb_get_regs_len,
.get_regs = macb_get_regs,
@@ -3164,8 +3198,8 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
.get_ts_info = ethtool_op_get_ts_info,
.get_wol = macb_get_wol,
.set_wol = macb_set_wol,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_link_ksettings = gem_ethtool_get_link_ksettings,
+ .set_link_ksettings = gem_ethtool_set_link_ksettings,
.get_ringparam = macb_get_ringparam,
.set_ringparam = macb_set_ringparam,
};
@@ -3178,8 +3212,8 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
.get_ethtool_stats = gem_get_ethtool_stats,
.get_strings = gem_get_ethtool_strings,
.get_sset_count = gem_get_sset_count,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_link_ksettings = gem_ethtool_get_link_ksettings,
+ .set_link_ksettings = gem_ethtool_set_link_ksettings,
.get_ringparam = macb_get_ringparam,
.set_ringparam = macb_set_ringparam,
.get_rxnfc = gem_get_rxnfc,
@@ -3188,17 +3222,13 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
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->pl, rq, cmd);
switch (cmd) {
case SIOCSHWTSTAMP:
@@ -3206,7 +3236,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->pl, rq, cmd);
}
}
@@ -3708,7 +3738,7 @@ static int at91ether_open(struct net_device *dev)
MACB_BIT(HRESP));
/* schedule a link state check */
- phy_start(dev->phydev);
+ phylink_start(lp->pl);
netif_start_queue(dev);
@@ -4181,7 +4211,7 @@ static int macb_probe(struct platform_device *pdev)
struct clk *tsu_clk = NULL;
unsigned int queue_mask, num_queues;
bool native_io;
- struct phy_device *phydev;
+ //struct phy_device *phydev;
phy_interface_t interface;
struct net_device *dev;
struct resource *regs;
@@ -4312,21 +4342,17 @@ static int macb_probe(struct platform_device *pdev)
err = of_get_phy_mode(np, &interface);
if (err)
/* not found in DT, MII by default */
- bp->phy_interface = PHY_INTERFACE_MODE_MII;
- else
- bp->phy_interface = interface;
+ interface = PHY_INTERFACE_MODE_MII;
/* IP specific init */
err = init(pdev);
if (err)
goto err_out_free_netdev;
- err = macb_mii_init(bp);
+ err = macb_mii_init(bp, interface);
if (err)
goto err_out_free_netdev;
- phydev = dev->phydev;
-
netif_carrier_off(dev);
err = register_netdev(dev);
@@ -4338,8 +4364,6 @@ static int macb_probe(struct platform_device *pdev)
tasklet_init(&bp->hresp_err_tasklet, macb_hresp_error_task,
(unsigned long)bp);
- phy_attached_info(phydev);
-
netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
dev->base_addr, dev->irq, dev->dev_addr);
@@ -4350,7 +4374,9 @@ static int macb_probe(struct platform_device *pdev)
return 0;
err_out_unregister_mdio:
- phy_disconnect(dev->phydev);
+ rtnl_lock();
+ phylink_disconnect_phy(bp->pl);
+ rtnl_unlock();
mdiobus_unregister(bp->mii_bus);
of_node_put(bp->phy_node);
if (np && of_phy_is_fixed_link(np))
@@ -4384,13 +4410,18 @@ static int macb_remove(struct platform_device *pdev)
if (dev) {
bp = netdev_priv(dev);
- if (dev->phydev)
- phy_disconnect(dev->phydev);
+ if (bp->pl) {
+ rtnl_lock();
+ phylink_disconnect_phy(bp->pl);
+ rtnl_unlock();
+ }
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);
+ if (bp->pl)
+ phylink_destroy(bp->pl);
unregister_netdev(dev);
pm_runtime_disable(&pdev->dev);
@@ -4433,8 +4464,9 @@ 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);
+ phylink_stop(bp->pl);
+ if (netdev->phydev)
+ phy_suspend(netdev->phydev);
spin_lock_irqsave(&bp->lock, flags);
macb_reset_hw(bp);
spin_unlock_irqrestore(&bp->lock, flags);
@@ -4482,9 +4514,11 @@ 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);
+ if (netdev->phydev) {
+ phy_resume(netdev->phydev);
+ phy_init_hw(netdev->phydev);
+ }
+ phylink_start(bp->pl);
}
bp->macbgem_ops.mog_init_rings(bp);
--
1.7.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] net: macb: add phylink support
2019-11-08 13:34 ` [PATCH 1/4] net: macb: add phylink support Milind Parab
@ 2019-11-08 15:42 ` Antoine Tenart
2019-11-11 8:53 ` Milind Parab
0 siblings, 1 reply; 8+ messages in thread
From: Antoine Tenart @ 2019-11-08 15:42 UTC (permalink / raw)
To: Milind Parab
Cc: andrew, nicolas.ferre, davem, f.fainelli, netdev, hkallweit1,
linux-kernel, piotrs, dkangude, ewanm, arthurm, stevenh
Hello Milind,
I sent a similar patch a few weeks ago. Have you seen
https://lore.kernel.org/netdev/20191018145230.GJ3125@piout.net/T/?
I also intended to send the v2 in the next days. I looked briefly at
your patch and it seems it has some of the issues my first version had
(such as not using state->link in mac_config()). This is why I would
suggest to wait for my v2 and to see if the rest of your series could be
based on it. What do you think? I pushed it in the meantime on GH[1].
Also, one of the comments I got was that it should be possible to get
the status of the negotiation, and that it would be very nice to
implement the get_link_state() helper. I couldn't get lots of info
about the status register (NSR), but I had the feeling this register is
exposing the info we need. Do you have more info about this?
Thanks!
Antoine
[1] https://github.com/atenart/linux/commit/eef7734734310e6759a0c5e0b61bc71cf978e46b
On Fri, Nov 08, 2019 at 01:34:23PM +0000, Milind Parab wrote:
> This patch replace phylib API's by phylink API's.
>
> Signed-off-by: Milind Parab <mparab@cadence.com>
> ---
> drivers/net/ethernet/cadence/Kconfig | 2 +-
> drivers/net/ethernet/cadence/macb.h | 3 +
> drivers/net/ethernet/cadence/macb_main.c | 326 ++++++++++++++++-------------
> 3 files changed, 184 insertions(+), 147 deletions(-)
>
> diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
> index f4b3bd8..53b50c2 100644
> --- a/drivers/net/ethernet/cadence/Kconfig
> +++ b/drivers/net/ethernet/cadence/Kconfig
> @@ -22,7 +22,7 @@ if NET_VENDOR_CADENCE
> config MACB
> tristate "Cadence MACB/GEM support"
> depends on HAS_DMA && COMMON_CLK
> - select PHYLIB
> + select PHYLINK
> ---help---
> The Cadence MACB ethernet interface is found on many Atmel AT32 and
> AT91 parts. This driver also supports the Cadence GEM (Gigabit
> diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
> index 03983bd..a400705 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -11,6 +11,7 @@
> #include <linux/ptp_clock_kernel.h>
> #include <linux/net_tstamp.h>
> #include <linux/interrupt.h>
> +#include <linux/phylink.h>
>
> #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP)
> #define MACB_EXT_DESC
> @@ -1232,6 +1233,8 @@ struct macb {
> u32 rx_intr_mask;
>
> struct macb_pm_data pm_data;
> + struct phylink *pl;
> + struct phylink_config pl_config;
> };
>
> #ifdef CONFIG_MACB_USE_HWSTAMP
> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
> index b884cf7..15016ff 100644
> --- a/drivers/net/ethernet/cadence/macb_main.c
> +++ b/drivers/net/ethernet/cadence/macb_main.c
> @@ -432,115 +432,160 @@ static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev)
> netdev_err(dev, "adjusting tx_clk failed.\n");
> }
>
> -static void macb_handle_link_change(struct net_device *dev)
> +static void gem_phylink_validate(struct phylink_config *pl_config,
> + unsigned long *supported,
> + struct phylink_link_state *state)
> {
> - struct macb *bp = netdev_priv(dev);
> - struct phy_device *phydev = dev->phydev;
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
> + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
> +
> + switch (state->interface) {
> + case PHY_INTERFACE_MODE_GMII:
> + case PHY_INTERFACE_MODE_RGMII:
> + if (!macb_is_gem(bp))
> + goto empty_set;
> + break;
> + default:
> + break;
> + }
> +
> + switch (state->interface) {
> + case PHY_INTERFACE_MODE_GMII:
> + case PHY_INTERFACE_MODE_RGMII:
> + if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) {
> + phylink_set(mask, 1000baseT_Full);
> + phylink_set(mask, 1000baseX_Full);
> + if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
> + phylink_set(mask, 1000baseT_Half);
> + }
> + /* fallthrough */
> + case PHY_INTERFACE_MODE_MII:
> + case PHY_INTERFACE_MODE_RMII:
> + phylink_set(mask, 10baseT_Half);
> + phylink_set(mask, 10baseT_Full);
> + phylink_set(mask, 100baseT_Half);
> + phylink_set(mask, 100baseT_Full);
> + break;
> + default:
> + goto empty_set;
> + }
> +
> + linkmode_and(supported, supported, mask);
> + linkmode_and(state->advertising, state->advertising, mask);
> + return;
> +
> +empty_set:
> + linkmode_zero(supported);
> +}
> +
> +static int gem_phylink_mac_link_state(struct phylink_config *pl_config,
> + struct phylink_link_state *state)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
> + const struct phylink_link_state *state)
> +{
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
> + bool change_interface = bp->phy_interface != state->interface;
> unsigned long flags;
> - int status_change = 0;
>
> spin_lock_irqsave(&bp->lock, flags);
>
> - if (phydev->link) {
> - if ((bp->speed != phydev->speed) ||
> - (bp->duplex != phydev->duplex)) {
> - u32 reg;
> + if (change_interface)
> + bp->phy_interface = state->interface;
>
> - reg = macb_readl(bp, NCFGR);
> - reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
> - if (macb_is_gem(bp))
> - reg &= ~GEM_BIT(GBE);
> + if (!phylink_autoneg_inband(mode) &&
> + (bp->speed != state->speed ||
> + bp->duplex != state->duplex)) {
> + u32 reg;
>
> - 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);
> -
> - macb_or_gem_writel(bp, NCFGR, reg);
> + reg = macb_readl(bp, NCFGR);
> + reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
> + if (macb_is_gem(bp))
> + reg &= ~GEM_BIT(GBE);
> + if (state->duplex)
> + reg |= MACB_BIT(FD);
>
> - bp->speed = phydev->speed;
> - bp->duplex = phydev->duplex;
> - status_change = 1;
> + switch (state->speed) {
> + case SPEED_1000:
> + reg |= GEM_BIT(GBE);
> + break;
> + case SPEED_100:
> + reg |= MACB_BIT(SPD);
> + break;
> + default:
> + break;
> }
> - }
> + macb_or_gem_writel(bp, NCFGR, reg);
>
> - if (phydev->link != bp->link) {
> - if (!phydev->link) {
> - bp->speed = 0;
> - bp->duplex = -1;
> - }
> - bp->link = phydev->link;
> + bp->speed = state->speed;
> + bp->duplex = state->duplex;
>
> - status_change = 1;
> + if (state->link)
> + macb_set_tx_clk(bp->tx_clk, state->speed, netdev);
> }
>
> spin_unlock_irqrestore(&bp->lock, flags);
> +}
>
> - if (status_change) {
> - if (phydev->link) {
> - /* Update the TX clock rate if and only if the link is
> - * up and there has been a link change.
> - */
> - macb_set_tx_clk(bp->tx_clk, phydev->speed, dev);
> +static void gem_mac_link_up(struct phylink_config *pl_config, unsigned int mode,
> + phy_interface_t interface, struct phy_device *phy)
> +{
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
>
> - netif_carrier_on(dev);
> - netdev_info(dev, "link up (%d/%s)\n",
> - phydev->speed,
> - phydev->duplex == DUPLEX_FULL ?
> - "Full" : "Half");
> - } else {
> - netif_carrier_off(dev);
> - netdev_info(dev, "link down\n");
> - }
> - }
> + bp->link = 1;
> + /* Enable TX and RX */
> + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE));
> }
>
> +static void gem_mac_link_down(struct phylink_config *pl_config,
> + unsigned int mode, phy_interface_t interface)
> +{
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
> +
> + bp->link = 0;
> + /* Disable TX and RX */
> + macb_writel(bp, NCR,
> + macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE)));
> +}
> +
> +static const struct phylink_mac_ops gem_phylink_ops = {
> + .validate = gem_phylink_validate,
> + .mac_link_state = gem_phylink_mac_link_state,
> + .mac_config = gem_mac_config,
> + .mac_link_up = gem_mac_link_up,
> + .mac_link_down = gem_mac_link_down,
> +};
> +
> /* based on au1000_eth. c*/
> -static int macb_mii_probe(struct net_device *dev)
> +static int macb_mii_probe(struct net_device *dev, phy_interface_t phy_mode)
> {
> struct macb *bp = netdev_priv(dev);
> struct phy_device *phydev;
> struct device_node *np;
> - int ret, i;
> + int ret;
>
> np = bp->pdev->dev.of_node;
> ret = 0;
>
> - if (np) {
> - if (of_phy_is_fixed_link(np)) {
> - bp->phy_node = of_node_get(np);
> - } else {
> - bp->phy_node = of_parse_phandle(np, "phy-handle", 0);
> - /* fallback to standard phy registration if no
> - * phy-handle was found nor any phy found during
> - * dt phy registration
> - */
> - if (!bp->phy_node && !phy_find_first(bp->mii_bus)) {
> - for (i = 0; i < PHY_MAX_ADDR; i++) {
> - phydev = mdiobus_scan(bp->mii_bus, i);
> - if (IS_ERR(phydev) &&
> - PTR_ERR(phydev) != -ENODEV) {
> - ret = PTR_ERR(phydev);
> - break;
> - }
> - }
> -
> - if (ret)
> - return -ENODEV;
> - }
> - }
> + bp->pl_config.dev = &dev->dev;
> + bp->pl_config.type = PHYLINK_NETDEV;
> + bp->pl = phylink_create(&bp->pl_config, of_fwnode_handle(np),
> + phy_mode, &gem_phylink_ops);
> + if (IS_ERR(bp->pl)) {
> + netdev_err(dev,
> + "error creating PHYLINK: %ld\n", PTR_ERR(bp->pl));
> + return PTR_ERR(bp->pl);
> }
>
> - if (bp->phy_node) {
> - phydev = of_phy_connect(dev, bp->phy_node,
> - &macb_handle_link_change, 0,
> - bp->phy_interface);
> - if (!phydev)
> - return -ENODEV;
> - } else {
> + ret = phylink_of_phy_connect(bp->pl, np, 0);
> + if (ret == -ENODEV && bp->mii_bus) {
> phydev = phy_find_first(bp->mii_bus);
> if (!phydev) {
> netdev_err(dev, "no PHY found\n");
> @@ -548,32 +593,22 @@ static int macb_mii_probe(struct net_device *dev)
> }
>
> /* attach the mac to the phy */
> - ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
> - bp->phy_interface);
> + ret = phylink_connect_phy(bp->pl, phydev);
> if (ret) {
> netdev_err(dev, "Could not attach to PHY\n");
> return ret;
> }
> }
>
> - /* mask with MAC supported features */
> - if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
> - phy_set_max_speed(phydev, SPEED_1000);
> - else
> - phy_set_max_speed(phydev, SPEED_100);
> -
> - if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF)
> - phy_remove_link_mode(phydev,
> - ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
> -
> bp->link = 0;
> - bp->speed = 0;
> - bp->duplex = -1;
> + bp->speed = SPEED_UNKNOWN;
> + bp->duplex = DUPLEX_UNKNOWN;
> + bp->phy_interface = PHY_INTERFACE_MODE_MAX;
>
> - return 0;
> + return ret;
> }
>
> -static int macb_mii_init(struct macb *bp)
> +static int macb_mii_init(struct macb *bp, phy_interface_t phy_mode)
> {
> struct device_node *np;
> int err = -ENXIO;
> @@ -598,22 +633,12 @@ static int macb_mii_init(struct macb *bp)
> dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
>
> np = bp->pdev->dev.of_node;
> - if (np && of_phy_is_fixed_link(np)) {
> - if (of_phy_register_fixed_link(np) < 0) {
> - dev_err(&bp->pdev->dev,
> - "broken fixed-link specification %pOF\n", np);
> - goto err_out_free_mdiobus;
> - }
> -
> - err = mdiobus_register(bp->mii_bus);
> - } else {
> - err = of_mdiobus_register(bp->mii_bus, np);
> - }
> + err = of_mdiobus_register(bp->mii_bus, np);
>
> if (err)
> goto err_out_free_fixed_link;
>
> - err = macb_mii_probe(bp->dev);
> + err = macb_mii_probe(bp->dev, phy_mode);
> if (err)
> goto err_out_unregister_bus;
>
> @@ -624,7 +649,6 @@ static int macb_mii_init(struct macb *bp)
> err_out_free_fixed_link:
> if (np && of_phy_is_fixed_link(np))
> of_phy_deregister_fixed_link(np);
> -err_out_free_mdiobus:
> of_node_put(bp->phy_node);
> mdiobus_free(bp->mii_bus);
> err_out:
> @@ -2417,12 +2441,6 @@ static int macb_open(struct net_device *dev)
> /* carrier starts down */
> netif_carrier_off(dev);
>
> - /* if the phy is not yet register, retry later*/
> - if (!dev->phydev) {
> - err = -EAGAIN;
> - goto pm_exit;
> - }
> -
> /* RX buffers initialization */
> macb_init_rx_buffer_size(bp, bufsz);
>
> @@ -2440,7 +2458,7 @@ static int macb_open(struct net_device *dev)
> macb_init_hw(bp);
>
> /* schedule a link state check */
> - phy_start(dev->phydev);
> + phylink_start(bp->pl);
>
> netif_tx_start_all_queues(dev);
>
> @@ -2467,8 +2485,7 @@ 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->pl);
>
> spin_lock_irqsave(&bp->lock, flags);
> macb_reset_hw(bp);
> @@ -3157,6 +3174,23 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
> return ret;
> }
>
> +static int gem_ethtool_get_link_ksettings(struct net_device *netdev,
> + struct ethtool_link_ksettings *cmd)
> +{
> + struct macb *bp = netdev_priv(netdev);
> +
> + return phylink_ethtool_ksettings_get(bp->pl, cmd);
> +}
> +
> +static int
> +gem_ethtool_set_link_ksettings(struct net_device *netdev,
> + const struct ethtool_link_ksettings *cmd)
> +{
> + struct macb *bp = netdev_priv(netdev);
> +
> + return phylink_ethtool_ksettings_set(bp->pl, cmd);
> +}
> +
> static const struct ethtool_ops macb_ethtool_ops = {
> .get_regs_len = macb_get_regs_len,
> .get_regs = macb_get_regs,
> @@ -3164,8 +3198,8 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
> .get_ts_info = ethtool_op_get_ts_info,
> .get_wol = macb_get_wol,
> .set_wol = macb_set_wol,
> - .get_link_ksettings = phy_ethtool_get_link_ksettings,
> - .set_link_ksettings = phy_ethtool_set_link_ksettings,
> + .get_link_ksettings = gem_ethtool_get_link_ksettings,
> + .set_link_ksettings = gem_ethtool_set_link_ksettings,
> .get_ringparam = macb_get_ringparam,
> .set_ringparam = macb_set_ringparam,
> };
> @@ -3178,8 +3212,8 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
> .get_ethtool_stats = gem_get_ethtool_stats,
> .get_strings = gem_get_ethtool_strings,
> .get_sset_count = gem_get_sset_count,
> - .get_link_ksettings = phy_ethtool_get_link_ksettings,
> - .set_link_ksettings = phy_ethtool_set_link_ksettings,
> + .get_link_ksettings = gem_ethtool_get_link_ksettings,
> + .set_link_ksettings = gem_ethtool_set_link_ksettings,
> .get_ringparam = macb_get_ringparam,
> .set_ringparam = macb_set_ringparam,
> .get_rxnfc = gem_get_rxnfc,
> @@ -3188,17 +3222,13 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
>
> 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->pl, rq, cmd);
>
> switch (cmd) {
> case SIOCSHWTSTAMP:
> @@ -3206,7 +3236,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->pl, rq, cmd);
> }
> }
>
> @@ -3708,7 +3738,7 @@ static int at91ether_open(struct net_device *dev)
> MACB_BIT(HRESP));
>
> /* schedule a link state check */
> - phy_start(dev->phydev);
> + phylink_start(lp->pl);
>
> netif_start_queue(dev);
>
> @@ -4181,7 +4211,7 @@ static int macb_probe(struct platform_device *pdev)
> struct clk *tsu_clk = NULL;
> unsigned int queue_mask, num_queues;
> bool native_io;
> - struct phy_device *phydev;
> + //struct phy_device *phydev;
> phy_interface_t interface;
> struct net_device *dev;
> struct resource *regs;
> @@ -4312,21 +4342,17 @@ static int macb_probe(struct platform_device *pdev)
> err = of_get_phy_mode(np, &interface);
> if (err)
> /* not found in DT, MII by default */
> - bp->phy_interface = PHY_INTERFACE_MODE_MII;
> - else
> - bp->phy_interface = interface;
> + interface = PHY_INTERFACE_MODE_MII;
>
> /* IP specific init */
> err = init(pdev);
> if (err)
> goto err_out_free_netdev;
>
> - err = macb_mii_init(bp);
> + err = macb_mii_init(bp, interface);
> if (err)
> goto err_out_free_netdev;
>
> - phydev = dev->phydev;
> -
> netif_carrier_off(dev);
>
> err = register_netdev(dev);
> @@ -4338,8 +4364,6 @@ static int macb_probe(struct platform_device *pdev)
> tasklet_init(&bp->hresp_err_tasklet, macb_hresp_error_task,
> (unsigned long)bp);
>
> - phy_attached_info(phydev);
> -
> netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
> macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
> dev->base_addr, dev->irq, dev->dev_addr);
> @@ -4350,7 +4374,9 @@ static int macb_probe(struct platform_device *pdev)
> return 0;
>
> err_out_unregister_mdio:
> - phy_disconnect(dev->phydev);
> + rtnl_lock();
> + phylink_disconnect_phy(bp->pl);
> + rtnl_unlock();
> mdiobus_unregister(bp->mii_bus);
> of_node_put(bp->phy_node);
> if (np && of_phy_is_fixed_link(np))
> @@ -4384,13 +4410,18 @@ static int macb_remove(struct platform_device *pdev)
>
> if (dev) {
> bp = netdev_priv(dev);
> - if (dev->phydev)
> - phy_disconnect(dev->phydev);
> + if (bp->pl) {
> + rtnl_lock();
> + phylink_disconnect_phy(bp->pl);
> + rtnl_unlock();
> + }
> 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);
> + if (bp->pl)
> + phylink_destroy(bp->pl);
>
> unregister_netdev(dev);
> pm_runtime_disable(&pdev->dev);
> @@ -4433,8 +4464,9 @@ 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);
> + phylink_stop(bp->pl);
> + if (netdev->phydev)
> + phy_suspend(netdev->phydev);
> spin_lock_irqsave(&bp->lock, flags);
> macb_reset_hw(bp);
> spin_unlock_irqrestore(&bp->lock, flags);
> @@ -4482,9 +4514,11 @@ 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);
> + if (netdev->phydev) {
> + phy_resume(netdev->phydev);
> + phy_init_hw(netdev->phydev);
> + }
> + phylink_start(bp->pl);
> }
>
> bp->macbgem_ops.mog_init_rings(bp);
> --
> 1.7.1
>
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 1/4] net: macb: add phylink support
2019-11-08 15:42 ` Antoine Tenart
@ 2019-11-11 8:53 ` Milind Parab
2019-11-12 8:24 ` Antoine Tenart
0 siblings, 1 reply; 8+ messages in thread
From: Milind Parab @ 2019-11-11 8:53 UTC (permalink / raw)
To: Antoine Tenart
Cc: andrew, nicolas.ferre, davem, f.fainelli, netdev, hkallweit1,
linux-kernel, Piotr Sroka, Dhananjay Vilasrao Kangude,
Ewan McCulloch, Arthur Marris, Steven Ho
Hi Antoine,
I had a look at your patch. It is worth waiting for your acceptance rather than duplicating the effort.
When do you plan to submit your "V2" patch?
And please add me and other cadence members in your patch submission.
Regards,
Milind
-----Original Message-----
From: Antoine Tenart <antoine.tenart@bootlin.com>
Sent: Friday, November 8, 2019 9:13 PM
To: Milind Parab <mparab@cadence.com>
Cc: andrew@lunn.ch; nicolas.ferre@microchip.com; davem@davemloft.net; f.fainelli@gmail.com; netdev@vger.kernel.org; hkallweit1@gmail.com; linux-kernel@vger.kernel.org; Piotr Sroka <piotrs@cadence.com>; Dhananjay Vilasrao Kangude <dkangude@cadence.com>; Ewan McCulloch <ewanm@cadence.com>; Arthur Marris <arthurm@cadence.com>; Steven Ho <stevenh@cadence.com>
Subject: Re: [PATCH 1/4] net: macb: add phylink support
EXTERNAL MAIL
Hello Milind,
I sent a similar patch a few weeks ago. Have you seen
https://urldefense.proofpoint.com/v2/url?u=https-3A__lore.kernel.org_netdev_20191018145230.GJ3125-40piout.net_T_-3F&d=DwIDAw&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=BDdk1JtITE_JJ0519WwqU7IKF80Cw1i55lZOGqv2su8&m=ToN1RMBv1eK6uj1h7HO6NdJivPHLvHDYcDwSDfcB3fc&s=5KotdNmEBqzpiI3kom2EL7a373rIiAefrTqD-8Esg6E&e=
I also intended to send the v2 in the next days. I looked briefly at
your patch and it seems it has some of the issues my first version had
(such as not using state->link in mac_config()). This is why I would
suggest to wait for my v2 and to see if the rest of your series could be
based on it. What do you think? I pushed it in the meantime on GH[1].
Also, one of the comments I got was that it should be possible to get
the status of the negotiation, and that it would be very nice to
implement the get_link_state() helper. I couldn't get lots of info
about the status register (NSR), but I had the feeling this register is
exposing the info we need. Do you have more info about this?
Thanks!
Antoine
[1] https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_atenart_linux_commit_eef7734734310e6759a0c5e0b61bc71cf978e46b&d=DwIDAw&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=BDdk1JtITE_JJ0519WwqU7IKF80Cw1i55lZOGqv2su8&m=ToN1RMBv1eK6uj1h7HO6NdJivPHLvHDYcDwSDfcB3fc&s=2u_8Chlk0JlEa5onkqq56GQHC4-VhqUa3e4XnAt2V0Q&e=
On Fri, Nov 08, 2019 at 01:34:23PM +0000, Milind Parab wrote:
> This patch replace phylib API's by phylink API's.
>
> Signed-off-by: Milind Parab <mparab@cadence.com>
> ---
> drivers/net/ethernet/cadence/Kconfig | 2 +-
> drivers/net/ethernet/cadence/macb.h | 3 +
> drivers/net/ethernet/cadence/macb_main.c | 326 ++++++++++++++++-------------
> 3 files changed, 184 insertions(+), 147 deletions(-)
>
> diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
> index f4b3bd8..53b50c2 100644
> --- a/drivers/net/ethernet/cadence/Kconfig
> +++ b/drivers/net/ethernet/cadence/Kconfig
> @@ -22,7 +22,7 @@ if NET_VENDOR_CADENCE
> config MACB
> tristate "Cadence MACB/GEM support"
> depends on HAS_DMA && COMMON_CLK
> - select PHYLIB
> + select PHYLINK
> ---help---
> The Cadence MACB ethernet interface is found on many Atmel AT32 and
> AT91 parts. This driver also supports the Cadence GEM (Gigabit
> diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
> index 03983bd..a400705 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -11,6 +11,7 @@
> #include <linux/ptp_clock_kernel.h>
> #include <linux/net_tstamp.h>
> #include <linux/interrupt.h>
> +#include <linux/phylink.h>
>
> #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP)
> #define MACB_EXT_DESC
> @@ -1232,6 +1233,8 @@ struct macb {
> u32 rx_intr_mask;
>
> struct macb_pm_data pm_data;
> + struct phylink *pl;
> + struct phylink_config pl_config;
> };
>
> #ifdef CONFIG_MACB_USE_HWSTAMP
> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
> index b884cf7..15016ff 100644
> --- a/drivers/net/ethernet/cadence/macb_main.c
> +++ b/drivers/net/ethernet/cadence/macb_main.c
> @@ -432,115 +432,160 @@ static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev)
> netdev_err(dev, "adjusting tx_clk failed.\n");
> }
>
> -static void macb_handle_link_change(struct net_device *dev)
> +static void gem_phylink_validate(struct phylink_config *pl_config,
> + unsigned long *supported,
> + struct phylink_link_state *state)
> {
> - struct macb *bp = netdev_priv(dev);
> - struct phy_device *phydev = dev->phydev;
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
> + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
> +
> + switch (state->interface) {
> + case PHY_INTERFACE_MODE_GMII:
> + case PHY_INTERFACE_MODE_RGMII:
> + if (!macb_is_gem(bp))
> + goto empty_set;
> + break;
> + default:
> + break;
> + }
> +
> + switch (state->interface) {
> + case PHY_INTERFACE_MODE_GMII:
> + case PHY_INTERFACE_MODE_RGMII:
> + if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) {
> + phylink_set(mask, 1000baseT_Full);
> + phylink_set(mask, 1000baseX_Full);
> + if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
> + phylink_set(mask, 1000baseT_Half);
> + }
> + /* fallthrough */
> + case PHY_INTERFACE_MODE_MII:
> + case PHY_INTERFACE_MODE_RMII:
> + phylink_set(mask, 10baseT_Half);
> + phylink_set(mask, 10baseT_Full);
> + phylink_set(mask, 100baseT_Half);
> + phylink_set(mask, 100baseT_Full);
> + break;
> + default:
> + goto empty_set;
> + }
> +
> + linkmode_and(supported, supported, mask);
> + linkmode_and(state->advertising, state->advertising, mask);
> + return;
> +
> +empty_set:
> + linkmode_zero(supported);
> +}
> +
> +static int gem_phylink_mac_link_state(struct phylink_config *pl_config,
> + struct phylink_link_state *state)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
> + const struct phylink_link_state *state)
> +{
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
> + bool change_interface = bp->phy_interface != state->interface;
> unsigned long flags;
> - int status_change = 0;
>
> spin_lock_irqsave(&bp->lock, flags);
>
> - if (phydev->link) {
> - if ((bp->speed != phydev->speed) ||
> - (bp->duplex != phydev->duplex)) {
> - u32 reg;
> + if (change_interface)
> + bp->phy_interface = state->interface;
>
> - reg = macb_readl(bp, NCFGR);
> - reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
> - if (macb_is_gem(bp))
> - reg &= ~GEM_BIT(GBE);
> + if (!phylink_autoneg_inband(mode) &&
> + (bp->speed != state->speed ||
> + bp->duplex != state->duplex)) {
> + u32 reg;
>
> - 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);
> -
> - macb_or_gem_writel(bp, NCFGR, reg);
> + reg = macb_readl(bp, NCFGR);
> + reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
> + if (macb_is_gem(bp))
> + reg &= ~GEM_BIT(GBE);
> + if (state->duplex)
> + reg |= MACB_BIT(FD);
>
> - bp->speed = phydev->speed;
> - bp->duplex = phydev->duplex;
> - status_change = 1;
> + switch (state->speed) {
> + case SPEED_1000:
> + reg |= GEM_BIT(GBE);
> + break;
> + case SPEED_100:
> + reg |= MACB_BIT(SPD);
> + break;
> + default:
> + break;
> }
> - }
> + macb_or_gem_writel(bp, NCFGR, reg);
>
> - if (phydev->link != bp->link) {
> - if (!phydev->link) {
> - bp->speed = 0;
> - bp->duplex = -1;
> - }
> - bp->link = phydev->link;
> + bp->speed = state->speed;
> + bp->duplex = state->duplex;
>
> - status_change = 1;
> + if (state->link)
> + macb_set_tx_clk(bp->tx_clk, state->speed, netdev);
> }
>
> spin_unlock_irqrestore(&bp->lock, flags);
> +}
>
> - if (status_change) {
> - if (phydev->link) {
> - /* Update the TX clock rate if and only if the link is
> - * up and there has been a link change.
> - */
> - macb_set_tx_clk(bp->tx_clk, phydev->speed, dev);
> +static void gem_mac_link_up(struct phylink_config *pl_config, unsigned int mode,
> + phy_interface_t interface, struct phy_device *phy)
> +{
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
>
> - netif_carrier_on(dev);
> - netdev_info(dev, "link up (%d/%s)\n",
> - phydev->speed,
> - phydev->duplex == DUPLEX_FULL ?
> - "Full" : "Half");
> - } else {
> - netif_carrier_off(dev);
> - netdev_info(dev, "link down\n");
> - }
> - }
> + bp->link = 1;
> + /* Enable TX and RX */
> + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE));
> }
>
> +static void gem_mac_link_down(struct phylink_config *pl_config,
> + unsigned int mode, phy_interface_t interface)
> +{
> + struct net_device *netdev = to_net_dev(pl_config->dev);
> + struct macb *bp = netdev_priv(netdev);
> +
> + bp->link = 0;
> + /* Disable TX and RX */
> + macb_writel(bp, NCR,
> + macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE)));
> +}
> +
> +static const struct phylink_mac_ops gem_phylink_ops = {
> + .validate = gem_phylink_validate,
> + .mac_link_state = gem_phylink_mac_link_state,
> + .mac_config = gem_mac_config,
> + .mac_link_up = gem_mac_link_up,
> + .mac_link_down = gem_mac_link_down,
> +};
> +
> /* based on au1000_eth. c*/
> -static int macb_mii_probe(struct net_device *dev)
> +static int macb_mii_probe(struct net_device *dev, phy_interface_t phy_mode)
> {
> struct macb *bp = netdev_priv(dev);
> struct phy_device *phydev;
> struct device_node *np;
> - int ret, i;
> + int ret;
>
> np = bp->pdev->dev.of_node;
> ret = 0;
>
> - if (np) {
> - if (of_phy_is_fixed_link(np)) {
> - bp->phy_node = of_node_get(np);
> - } else {
> - bp->phy_node = of_parse_phandle(np, "phy-handle", 0);
> - /* fallback to standard phy registration if no
> - * phy-handle was found nor any phy found during
> - * dt phy registration
> - */
> - if (!bp->phy_node && !phy_find_first(bp->mii_bus)) {
> - for (i = 0; i < PHY_MAX_ADDR; i++) {
> - phydev = mdiobus_scan(bp->mii_bus, i);
> - if (IS_ERR(phydev) &&
> - PTR_ERR(phydev) != -ENODEV) {
> - ret = PTR_ERR(phydev);
> - break;
> - }
> - }
> -
> - if (ret)
> - return -ENODEV;
> - }
> - }
> + bp->pl_config.dev = &dev->dev;
> + bp->pl_config.type = PHYLINK_NETDEV;
> + bp->pl = phylink_create(&bp->pl_config, of_fwnode_handle(np),
> + phy_mode, &gem_phylink_ops);
> + if (IS_ERR(bp->pl)) {
> + netdev_err(dev,
> + "error creating PHYLINK: %ld\n", PTR_ERR(bp->pl));
> + return PTR_ERR(bp->pl);
> }
>
> - if (bp->phy_node) {
> - phydev = of_phy_connect(dev, bp->phy_node,
> - &macb_handle_link_change, 0,
> - bp->phy_interface);
> - if (!phydev)
> - return -ENODEV;
> - } else {
> + ret = phylink_of_phy_connect(bp->pl, np, 0);
> + if (ret == -ENODEV && bp->mii_bus) {
> phydev = phy_find_first(bp->mii_bus);
> if (!phydev) {
> netdev_err(dev, "no PHY found\n");
> @@ -548,32 +593,22 @@ static int macb_mii_probe(struct net_device *dev)
> }
>
> /* attach the mac to the phy */
> - ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
> - bp->phy_interface);
> + ret = phylink_connect_phy(bp->pl, phydev);
> if (ret) {
> netdev_err(dev, "Could not attach to PHY\n");
> return ret;
> }
> }
>
> - /* mask with MAC supported features */
> - if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
> - phy_set_max_speed(phydev, SPEED_1000);
> - else
> - phy_set_max_speed(phydev, SPEED_100);
> -
> - if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF)
> - phy_remove_link_mode(phydev,
> - ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
> -
> bp->link = 0;
> - bp->speed = 0;
> - bp->duplex = -1;
> + bp->speed = SPEED_UNKNOWN;
> + bp->duplex = DUPLEX_UNKNOWN;
> + bp->phy_interface = PHY_INTERFACE_MODE_MAX;
>
> - return 0;
> + return ret;
> }
>
> -static int macb_mii_init(struct macb *bp)
> +static int macb_mii_init(struct macb *bp, phy_interface_t phy_mode)
> {
> struct device_node *np;
> int err = -ENXIO;
> @@ -598,22 +633,12 @@ static int macb_mii_init(struct macb *bp)
> dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
>
> np = bp->pdev->dev.of_node;
> - if (np && of_phy_is_fixed_link(np)) {
> - if (of_phy_register_fixed_link(np) < 0) {
> - dev_err(&bp->pdev->dev,
> - "broken fixed-link specification %pOF\n", np);
> - goto err_out_free_mdiobus;
> - }
> -
> - err = mdiobus_register(bp->mii_bus);
> - } else {
> - err = of_mdiobus_register(bp->mii_bus, np);
> - }
> + err = of_mdiobus_register(bp->mii_bus, np);
>
> if (err)
> goto err_out_free_fixed_link;
>
> - err = macb_mii_probe(bp->dev);
> + err = macb_mii_probe(bp->dev, phy_mode);
> if (err)
> goto err_out_unregister_bus;
>
> @@ -624,7 +649,6 @@ static int macb_mii_init(struct macb *bp)
> err_out_free_fixed_link:
> if (np && of_phy_is_fixed_link(np))
> of_phy_deregister_fixed_link(np);
> -err_out_free_mdiobus:
> of_node_put(bp->phy_node);
> mdiobus_free(bp->mii_bus);
> err_out:
> @@ -2417,12 +2441,6 @@ static int macb_open(struct net_device *dev)
> /* carrier starts down */
> netif_carrier_off(dev);
>
> - /* if the phy is not yet register, retry later*/
> - if (!dev->phydev) {
> - err = -EAGAIN;
> - goto pm_exit;
> - }
> -
> /* RX buffers initialization */
> macb_init_rx_buffer_size(bp, bufsz);
>
> @@ -2440,7 +2458,7 @@ static int macb_open(struct net_device *dev)
> macb_init_hw(bp);
>
> /* schedule a link state check */
> - phy_start(dev->phydev);
> + phylink_start(bp->pl);
>
> netif_tx_start_all_queues(dev);
>
> @@ -2467,8 +2485,7 @@ 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->pl);
>
> spin_lock_irqsave(&bp->lock, flags);
> macb_reset_hw(bp);
> @@ -3157,6 +3174,23 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
> return ret;
> }
>
> +static int gem_ethtool_get_link_ksettings(struct net_device *netdev,
> + struct ethtool_link_ksettings *cmd)
> +{
> + struct macb *bp = netdev_priv(netdev);
> +
> + return phylink_ethtool_ksettings_get(bp->pl, cmd);
> +}
> +
> +static int
> +gem_ethtool_set_link_ksettings(struct net_device *netdev,
> + const struct ethtool_link_ksettings *cmd)
> +{
> + struct macb *bp = netdev_priv(netdev);
> +
> + return phylink_ethtool_ksettings_set(bp->pl, cmd);
> +}
> +
> static const struct ethtool_ops macb_ethtool_ops = {
> .get_regs_len = macb_get_regs_len,
> .get_regs = macb_get_regs,
> @@ -3164,8 +3198,8 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
> .get_ts_info = ethtool_op_get_ts_info,
> .get_wol = macb_get_wol,
> .set_wol = macb_set_wol,
> - .get_link_ksettings = phy_ethtool_get_link_ksettings,
> - .set_link_ksettings = phy_ethtool_set_link_ksettings,
> + .get_link_ksettings = gem_ethtool_get_link_ksettings,
> + .set_link_ksettings = gem_ethtool_set_link_ksettings,
> .get_ringparam = macb_get_ringparam,
> .set_ringparam = macb_set_ringparam,
> };
> @@ -3178,8 +3212,8 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
> .get_ethtool_stats = gem_get_ethtool_stats,
> .get_strings = gem_get_ethtool_strings,
> .get_sset_count = gem_get_sset_count,
> - .get_link_ksettings = phy_ethtool_get_link_ksettings,
> - .set_link_ksettings = phy_ethtool_set_link_ksettings,
> + .get_link_ksettings = gem_ethtool_get_link_ksettings,
> + .set_link_ksettings = gem_ethtool_set_link_ksettings,
> .get_ringparam = macb_get_ringparam,
> .set_ringparam = macb_set_ringparam,
> .get_rxnfc = gem_get_rxnfc,
> @@ -3188,17 +3222,13 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
>
> 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->pl, rq, cmd);
>
> switch (cmd) {
> case SIOCSHWTSTAMP:
> @@ -3206,7 +3236,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->pl, rq, cmd);
> }
> }
>
> @@ -3708,7 +3738,7 @@ static int at91ether_open(struct net_device *dev)
> MACB_BIT(HRESP));
>
> /* schedule a link state check */
> - phy_start(dev->phydev);
> + phylink_start(lp->pl);
>
> netif_start_queue(dev);
>
> @@ -4181,7 +4211,7 @@ static int macb_probe(struct platform_device *pdev)
> struct clk *tsu_clk = NULL;
> unsigned int queue_mask, num_queues;
> bool native_io;
> - struct phy_device *phydev;
> + //struct phy_device *phydev;
> phy_interface_t interface;
> struct net_device *dev;
> struct resource *regs;
> @@ -4312,21 +4342,17 @@ static int macb_probe(struct platform_device *pdev)
> err = of_get_phy_mode(np, &interface);
> if (err)
> /* not found in DT, MII by default */
> - bp->phy_interface = PHY_INTERFACE_MODE_MII;
> - else
> - bp->phy_interface = interface;
> + interface = PHY_INTERFACE_MODE_MII;
>
> /* IP specific init */
> err = init(pdev);
> if (err)
> goto err_out_free_netdev;
>
> - err = macb_mii_init(bp);
> + err = macb_mii_init(bp, interface);
> if (err)
> goto err_out_free_netdev;
>
> - phydev = dev->phydev;
> -
> netif_carrier_off(dev);
>
> err = register_netdev(dev);
> @@ -4338,8 +4364,6 @@ static int macb_probe(struct platform_device *pdev)
> tasklet_init(&bp->hresp_err_tasklet, macb_hresp_error_task,
> (unsigned long)bp);
>
> - phy_attached_info(phydev);
> -
> netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
> macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
> dev->base_addr, dev->irq, dev->dev_addr);
> @@ -4350,7 +4374,9 @@ static int macb_probe(struct platform_device *pdev)
> return 0;
>
> err_out_unregister_mdio:
> - phy_disconnect(dev->phydev);
> + rtnl_lock();
> + phylink_disconnect_phy(bp->pl);
> + rtnl_unlock();
> mdiobus_unregister(bp->mii_bus);
> of_node_put(bp->phy_node);
> if (np && of_phy_is_fixed_link(np))
> @@ -4384,13 +4410,18 @@ static int macb_remove(struct platform_device *pdev)
>
> if (dev) {
> bp = netdev_priv(dev);
> - if (dev->phydev)
> - phy_disconnect(dev->phydev);
> + if (bp->pl) {
> + rtnl_lock();
> + phylink_disconnect_phy(bp->pl);
> + rtnl_unlock();
> + }
> 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);
> + if (bp->pl)
> + phylink_destroy(bp->pl);
>
> unregister_netdev(dev);
> pm_runtime_disable(&pdev->dev);
> @@ -4433,8 +4464,9 @@ 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);
> + phylink_stop(bp->pl);
> + if (netdev->phydev)
> + phy_suspend(netdev->phydev);
> spin_lock_irqsave(&bp->lock, flags);
> macb_reset_hw(bp);
> spin_unlock_irqrestore(&bp->lock, flags);
> @@ -4482,9 +4514,11 @@ 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);
> + if (netdev->phydev) {
> + phy_resume(netdev->phydev);
> + phy_init_hw(netdev->phydev);
> + }
> + phylink_start(bp->pl);
> }
>
> bp->macbgem_ops.mog_init_rings(bp);
> --
> 1.7.1
>
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://urldefense.proofpoint.com/v2/url?u=https-3A__bootlin.com&d=DwIDAw&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=BDdk1JtITE_JJ0519WwqU7IKF80Cw1i55lZOGqv2su8&m=ToN1RMBv1eK6uj1h7HO6NdJivPHLvHDYcDwSDfcB3fc&s=NT3VgR_be1KAgq5vc1BgdA21q-br_ihwk-41VPk__gY&e=
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] net: macb: add phylink support
2019-11-11 8:53 ` Milind Parab
@ 2019-11-12 8:24 ` Antoine Tenart
0 siblings, 0 replies; 8+ messages in thread
From: Antoine Tenart @ 2019-11-12 8:24 UTC (permalink / raw)
To: Milind Parab
Cc: Antoine Tenart, andrew, nicolas.ferre, davem, f.fainelli, netdev,
hkallweit1, linux-kernel, Piotr Sroka,
Dhananjay Vilasrao Kangude, Ewan McCulloch, Arthur Marris,
Steven Ho
Hi Milind,
On Mon, Nov 11, 2019 at 08:53:39AM +0000, Milind Parab wrote:
>
> I had a look at your patch. It is worth waiting for your acceptance
> rather than duplicating the effort. When do you plan to submit your
> "V2" patch?
> And please add me and other cadence members in your patch submission.
I'll send it today, and I'll add you and the mails you provided in Cc.
Thanks,
Antoine
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] net: macb: add support for sgmii MAC-PHY interface
2019-11-08 13:33 [PATCH 0/4] net: macb: cover letter Milind Parab
2019-11-08 13:34 ` [PATCH 1/4] net: macb: add phylink support Milind Parab
@ 2019-11-08 13:34 ` Milind Parab
2019-11-08 13:34 ` [PATCH 3/4] net: macb: add support for c45 PHY Milind Parab
2019-11-08 13:34 ` [PATCH 4/4] net: macb: add support for high speed interface Milind Parab
3 siblings, 0 replies; 8+ messages in thread
From: Milind Parab @ 2019-11-08 13:34 UTC (permalink / raw)
To: andrew, nicolas.ferre, davem, f.fainelli
Cc: netdev, hkallweit1, linux-kernel, piotrs, dkangude, ewanm,
arthurm, stevenh, Milind Parab
This patch add support for SGMII interface and
2.5Gbps MAC in Cadence ethernet controller driver.
Signed-off-by: Milind Parab <mparab@cadence.com>
---
drivers/net/ethernet/cadence/macb.h | 42 ++++++++++++++++++++---------
drivers/net/ethernet/cadence/macb_main.c | 28 +++++++++++++++++++-
2 files changed, 56 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index a400705..5e2957d 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -77,6 +77,7 @@
#define MACB_RBQPH 0x04D4
/* GEM register offsets. */
+#define GEM_NCR 0x0000 /* Network Control */
#define GEM_NCFGR 0x0004 /* Network Config */
#define GEM_USRIO 0x000c /* User IO */
#define GEM_DMACFG 0x0010 /* DMA Configuration */
@@ -156,6 +157,7 @@
#define GEM_PEFTN 0x01f4 /* PTP Peer Event Frame Tx Ns */
#define GEM_PEFRSL 0x01f8 /* PTP Peer Event Frame Rx Sec Low */
#define GEM_PEFRN 0x01fc /* PTP Peer Event Frame Rx Ns */
+#define GEM_PCS_CTRL 0x0200 /* PCS Control */
#define GEM_DCFG1 0x0280 /* Design Config 1 */
#define GEM_DCFG2 0x0284 /* Design Config 2 */
#define GEM_DCFG3 0x0288 /* Design Config 3 */
@@ -271,6 +273,10 @@
#define MACB_IRXFCS_OFFSET 19
#define MACB_IRXFCS_SIZE 1
+/* GEM specific NCR bitfields. */
+#define GEM_TWO_PT_FIVE_GIG_OFFSET 29
+#define GEM_TWO_PT_FIVE_GIG_SIZE 1
+
/* GEM specific NCFGR bitfields. */
#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */
#define GEM_GBE_SIZE 1
@@ -323,6 +329,9 @@
#define MACB_MDIO_SIZE 1
#define MACB_IDLE_OFFSET 2 /* The PHY management logic is idle */
#define MACB_IDLE_SIZE 1
+#define MACB_DUPLEX_OFFSET 3
+#define MACB_DUPLEX_SIZE 1
+
/* Bitfields in TSR */
#define MACB_UBR_OFFSET 0 /* Used bit read */
@@ -456,11 +465,17 @@
#define MACB_REV_OFFSET 0
#define MACB_REV_SIZE 16
+/* Bitfields in PCS_CONTROL. */
+#define GEM_PCS_CTRL_RST_OFFSET 15
+#define GEM_PCS_CTRL_RST_SIZE 1
+
/* Bitfields in DCFG1. */
#define GEM_IRQCOR_OFFSET 23
#define GEM_IRQCOR_SIZE 1
#define GEM_DBWDEF_OFFSET 25
#define GEM_DBWDEF_SIZE 3
+#define GEM_NO_PCS_OFFSET 0
+#define GEM_NO_PCS_SIZE 1
/* Bitfields in DCFG2. */
#define GEM_RX_PKT_BUFF_OFFSET 20
@@ -637,19 +652,20 @@
#define MACB_MAN_CODE 2
/* Capability mask bits */
-#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001
-#define MACB_CAPS_USRIO_HAS_CLKEN 0x00000002
-#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII 0x00000004
-#define MACB_CAPS_NO_GIGABIT_HALF 0x00000008
-#define MACB_CAPS_USRIO_DISABLED 0x00000010
-#define MACB_CAPS_JUMBO 0x00000020
-#define MACB_CAPS_GEM_HAS_PTP 0x00000040
-#define MACB_CAPS_BD_RD_PREFETCH 0x00000080
-#define MACB_CAPS_NEEDS_RSTONUBR 0x00000100
-#define MACB_CAPS_FIFO_MODE 0x10000000
-#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000
-#define MACB_CAPS_SG_DISABLED 0x40000000
-#define MACB_CAPS_MACB_IS_GEM 0x80000000
+#define MACB_CAPS_ISR_CLEAR_ON_WRITE BIT(0)
+#define MACB_CAPS_USRIO_HAS_CLKEN BIT(1)
+#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII BIT(2)
+#define MACB_CAPS_NO_GIGABIT_HALF BIT(3)
+#define MACB_CAPS_USRIO_DISABLED BIT(4)
+#define MACB_CAPS_JUMBO BIT(5)
+#define MACB_CAPS_GEM_HAS_PTP BIT(6)
+#define MACB_CAPS_BD_RD_PREFETCH BIT(7)
+#define MACB_CAPS_NEEDS_RSTONUBR BIT(8)
+#define MACB_CAPS_FIFO_MODE BIT(28)
+#define MACB_CAPS_GIGABIT_MODE_AVAILABLE BIT(29)
+#define MACB_CAPS_SG_DISABLED BIT(30)
+#define MACB_CAPS_MACB_IS_GEM BIT(31)
+#define MACB_CAPS_PCS BIT(24)
/* LSO settings */
#define MACB_LSO_UFO_ENABLE 0x01
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 15016ff..8269d7a 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -441,6 +441,10 @@ static void gem_phylink_validate(struct phylink_config *pl_config,
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
switch (state->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ if (!(bp->caps & MACB_CAPS_PCS))
+ goto empty_set;
+ break;
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
if (!macb_is_gem(bp))
@@ -451,6 +455,8 @@ static void gem_phylink_validate(struct phylink_config *pl_config,
}
switch (state->interface) {
+ case PHY_INTERFACE_MODE_NA:
+ case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) {
@@ -495,8 +501,26 @@ static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
spin_lock_irqsave(&bp->lock, flags);
- if (change_interface)
+ if (change_interface) {
bp->phy_interface = state->interface;
+ /* 2.5G mode not supported */
+ gem_writel(bp, NCR, ~GEM_BIT(TWO_PT_FIVE_GIG) &
+ gem_readl(bp, NCR));
+
+ if (state->interface == PHY_INTERFACE_MODE_SGMII) {
+ gem_writel(bp, NCFGR, GEM_BIT(SGMIIEN) |
+ GEM_BIT(PCSSEL) |
+ gem_readl(bp, NCFGR));
+ } else {
+ /* Disable SGMII mode and PCS */
+ gem_writel(bp, NCFGR, ~(GEM_BIT(SGMIIEN) |
+ GEM_BIT(PCSSEL)) &
+ gem_readl(bp, NCFGR));
+ /* Reset PCS */
+ gem_writel(bp, PCS_CTRL, gem_readl(bp, PCS_CTRL) |
+ GEM_BIT(PCS_CTRL_RST));
+ }
+ }
if (!phylink_autoneg_inband(mode) &&
(bp->speed != state->speed ||
@@ -3354,6 +3378,8 @@ static void macb_configure_caps(struct macb *bp,
dcfg = gem_readl(bp, DCFG1);
if (GEM_BFEXT(IRQCOR, dcfg) == 0)
bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
+ if (GEM_BFEXT(NO_PCS, dcfg) == 0)
+ bp->caps |= MACB_CAPS_PCS;
dcfg = gem_readl(bp, DCFG2);
if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
bp->caps |= MACB_CAPS_FIFO_MODE;
--
1.7.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] net: macb: add support for c45 PHY
2019-11-08 13:33 [PATCH 0/4] net: macb: cover letter Milind Parab
2019-11-08 13:34 ` [PATCH 1/4] net: macb: add phylink support Milind Parab
2019-11-08 13:34 ` [PATCH 2/4] net: macb: add support for sgmii MAC-PHY interface Milind Parab
@ 2019-11-08 13:34 ` Milind Parab
2019-11-08 13:34 ` [PATCH 4/4] net: macb: add support for high speed interface Milind Parab
3 siblings, 0 replies; 8+ messages in thread
From: Milind Parab @ 2019-11-08 13:34 UTC (permalink / raw)
To: andrew, nicolas.ferre, davem, f.fainelli
Cc: netdev, hkallweit1, linux-kernel, piotrs, dkangude, ewanm,
arthurm, stevenh, Milind Parab
This patch modify MDIO read/write functions to support
communication with C45 PHY.
Signed-off-by: Milind Parab <mparab@cadence.com>
---
drivers/net/ethernet/cadence/macb.h | 15 +++++--
drivers/net/ethernet/cadence/macb_main.c | 61 ++++++++++++++++++++++++-----
2 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 5e2957d..34136a8 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -646,10 +646,17 @@
#define GEM_CLK_DIV96 5
/* Constants for MAN register */
-#define MACB_MAN_SOF 1
-#define MACB_MAN_WRITE 1
-#define MACB_MAN_READ 2
-#define MACB_MAN_CODE 2
+#define MACB_MAN_C22_SOF 1
+#define MACB_MAN_C22_WRITE 1
+#define MACB_MAN_C22_READ 2
+#define MACB_MAN_C22_CODE 2
+
+#define MACB_MAN_C45_SOF 0
+#define MACB_MAN_C45_ADDR 0
+#define MACB_MAN_C45_WRITE 1
+#define MACB_MAN_C45_POST_READ_INCR 2
+#define MACB_MAN_C45_READ 3
+#define MACB_MAN_C45_CODE 2
/* Capability mask bits */
#define MACB_CAPS_ISR_CLEAR_ON_WRITE BIT(0)
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 8269d7a..fe107f0 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -337,11 +337,30 @@ static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
if (status < 0)
goto mdio_read_exit;
- macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
- | MACB_BF(RW, MACB_MAN_READ)
- | MACB_BF(PHYA, mii_id)
- | MACB_BF(REGA, regnum)
- | MACB_BF(CODE, MACB_MAN_CODE)));
+ if (regnum & MII_ADDR_C45) {
+ macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+ | MACB_BF(RW, MACB_MAN_C45_ADDR)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+ | MACB_BF(DATA, regnum & 0xFFFF)
+ | MACB_BF(CODE, MACB_MAN_C45_CODE)));
+
+ status = macb_mdio_wait_for_idle(bp);
+ if (status < 0)
+ goto mdio_read_exit;
+
+ macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+ | MACB_BF(RW, MACB_MAN_C45_READ)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+ | MACB_BF(CODE, MACB_MAN_C45_CODE)));
+ } else {
+ macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
+ | MACB_BF(RW, MACB_MAN_C22_READ)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, regnum)
+ | MACB_BF(CODE, MACB_MAN_C22_CODE)));
+ }
status = macb_mdio_wait_for_idle(bp);
if (status < 0)
@@ -370,12 +389,32 @@ static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
if (status < 0)
goto mdio_write_exit;
- macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
- | MACB_BF(RW, MACB_MAN_WRITE)
- | MACB_BF(PHYA, mii_id)
- | MACB_BF(REGA, regnum)
- | MACB_BF(CODE, MACB_MAN_CODE)
- | MACB_BF(DATA, value)));
+ if (regnum & MII_ADDR_C45) {
+ macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+ | MACB_BF(RW, MACB_MAN_C45_ADDR)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+ | MACB_BF(DATA, regnum & 0xFFFF)
+ | MACB_BF(CODE, MACB_MAN_C45_CODE)));
+
+ status = macb_mdio_wait_for_idle(bp);
+ if (status < 0)
+ goto mdio_write_exit;
+
+ macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+ | MACB_BF(RW, MACB_MAN_C45_WRITE)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+ | MACB_BF(CODE, MACB_MAN_C45_CODE)
+ | MACB_BF(DATA, value)));
+ } else {
+ macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
+ | MACB_BF(RW, MACB_MAN_C22_WRITE)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, regnum)
+ | MACB_BF(CODE, MACB_MAN_C22_CODE)
+ | MACB_BF(DATA, value)));
+ }
status = macb_mdio_wait_for_idle(bp);
if (status < 0)
--
1.7.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/4] net: macb: add support for high speed interface
2019-11-08 13:33 [PATCH 0/4] net: macb: cover letter Milind Parab
` (2 preceding siblings ...)
2019-11-08 13:34 ` [PATCH 3/4] net: macb: add support for c45 PHY Milind Parab
@ 2019-11-08 13:34 ` Milind Parab
3 siblings, 0 replies; 8+ messages in thread
From: Milind Parab @ 2019-11-08 13:34 UTC (permalink / raw)
To: andrew, nicolas.ferre, davem, f.fainelli
Cc: netdev, hkallweit1, linux-kernel, piotrs, dkangude, ewanm,
arthurm, stevenh, Milind Parab
This patch add support for high speed USXGMII PCS and 10G
speed in Cadence ethernet controller driver.
Signed-off-by: Milind Parab <mparab@cadence.com>
---
drivers/net/ethernet/cadence/macb.h | 40 +++++++++
drivers/net/ethernet/cadence/macb_main.c | 130 +++++++++++++++++++++++++++---
2 files changed, 160 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 34136a8..d064d76 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -82,6 +82,7 @@
#define GEM_USRIO 0x000c /* User IO */
#define GEM_DMACFG 0x0010 /* DMA Configuration */
#define GEM_JML 0x0048 /* Jumbo Max Length */
+#define GEM_HS_MAC_CONFIG 0x0050 /* GEM high speed config */
#define GEM_HRB 0x0080 /* Hash Bottom */
#define GEM_HRT 0x0084 /* Hash Top */
#define GEM_SA1B 0x0088 /* Specific1 Bottom */
@@ -167,6 +168,9 @@
#define GEM_DCFG7 0x0298 /* Design Config 7 */
#define GEM_DCFG8 0x029C /* Design Config 8 */
#define GEM_DCFG10 0x02A4 /* Design Config 10 */
+#define GEM_DCFG12 0x02AC /* Design Config 12 */
+#define GEM_USX_CONTROL 0x0A80 /* USXGMII control register */
+#define GEM_USX_STATUS 0x0A88 /* USXGMII status register */
#define GEM_TXBDCTRL 0x04cc /* TX Buffer Descriptor control register */
#define GEM_RXBDCTRL 0x04d0 /* RX Buffer Descriptor control register */
@@ -274,6 +278,8 @@
#define MACB_IRXFCS_SIZE 1
/* GEM specific NCR bitfields. */
+#define GEM_ENABLE_HS_MAC_OFFSET 31
+#define GEM_ENABLE_HS_MAC_SIZE 1
#define GEM_TWO_PT_FIVE_GIG_OFFSET 29
#define GEM_TWO_PT_FIVE_GIG_SIZE 1
@@ -465,6 +471,10 @@
#define MACB_REV_OFFSET 0
#define MACB_REV_SIZE 16
+/* Bitfield in HS_MAC_CONFIG */
+#define GEM_HS_MAC_SPEED_OFFSET 0
+#define GEM_HS_MAC_SPEED_SIZE 3
+
/* Bitfields in PCS_CONTROL. */
#define GEM_PCS_CTRL_RST_OFFSET 15
#define GEM_PCS_CTRL_RST_SIZE 1
@@ -510,6 +520,34 @@
#define GEM_RXBD_RDBUFF_OFFSET 8
#define GEM_RXBD_RDBUFF_SIZE 4
+/* Bitfields in DCFG12. */
+#define GEM_HIGH_SPEED_OFFSET 26
+#define GEM_HIGH_SPEED_SIZE 1
+
+/* Bitfields in USX_CONTROL. */
+#define GEM_USX_CTRL_SPEED_OFFSET 14
+#define GEM_USX_CTRL_SPEED_SIZE 3
+#define GEM_SERDES_RATE_OFFSET 12
+#define GEM_SERDES_RATE_SIZE 2
+#define GEM_RX_SCR_BYPASS_OFFSET 9
+#define GEM_RX_SCR_BYPASS_SIZE 1
+#define GEM_TX_SCR_BYPASS_OFFSET 8
+#define GEM_TX_SCR_BYPASS_SIZE 1
+#define GEM_RX_SYNC_RESET_OFFSET 2
+#define GEM_RX_SYNC_RESET_SIZE 1
+#define GEM_TX_EN_OFFSET 1
+#define GEM_TX_EN_SIZE 1
+#define GEM_SIGNAL_OK_OFFSET 0
+#define GEM_SIGNAL_OK_SIZE 1
+
+/* Bitfields in USX_STATUS. */
+#define GEM_USX_TX_FAULT_OFFSET 28
+#define GEM_USX_TX_FAULT_SIZE 1
+#define GEM_USX_RX_FAULT_OFFSET 27
+#define GEM_USX_RX_FAULT_SIZE 1
+#define GEM_USX_BLOCK_LOCK_OFFSET 0
+#define GEM_USX_BLOCK_LOCK_SIZE 1
+
/* Bitfields in TISUBN */
#define GEM_SUBNSINCR_OFFSET 0
#define GEM_SUBNSINCRL_OFFSET 24
@@ -673,6 +711,7 @@
#define MACB_CAPS_SG_DISABLED BIT(30)
#define MACB_CAPS_MACB_IS_GEM BIT(31)
#define MACB_CAPS_PCS BIT(24)
+#define MACB_CAPS_HIGH_SPEED BIT(25)
/* LSO settings */
#define MACB_LSO_UFO_ENABLE 0x01
@@ -741,6 +780,7 @@
})
#define MACB_READ_NSR(bp) macb_readl(bp, NSR)
+#define GEM_READ_USX_STATUS(bp) gem_readl(bp, USX_STATUS)
/* struct macb_dma_desc - Hardware DMA descriptor
* @addr: DMA address of data buffer
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index fe107f0..a4c197f 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -81,6 +81,18 @@ struct sifive_fu540_macb_mgmt {
#define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0)
#define MACB_WOL_ENABLED (0x1 << 1)
+enum {
+ HS_MAC_SPEED_100M,
+ HS_MAC_SPEED_1000M,
+ HS_MAC_SPEED_2500M,
+ HS_MAC_SPEED_5000M,
+ HS_MAC_SPEED_10000M,
+};
+
+enum {
+ MACB_SERDES_RATE_10G = 1,
+};
+
/* Graceful stop timeouts in us. We should allow up to
* 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
*/
@@ -90,6 +102,8 @@ struct sifive_fu540_macb_mgmt {
#define MACB_MDIO_TIMEOUT 1000000 /* in usecs */
+#define MACB_USX_BLOCK_LOCK_TIMEOUT 1000000 /* in usecs */
+
/* DMA buffer descriptor might be different size
* depends on hardware configuration:
*
@@ -489,12 +503,32 @@ static void gem_phylink_validate(struct phylink_config *pl_config,
if (!macb_is_gem(bp))
goto empty_set;
break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ if (!(bp->caps & MACB_CAPS_HIGH_SPEED &&
+ bp->caps & MACB_CAPS_PCS))
+ goto empty_set;
+ break;
default:
break;
}
switch (state->interface) {
case PHY_INTERFACE_MODE_NA:
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GKR:
+ if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) {
+ phylink_set(mask, 10000baseCR_Full);
+ phylink_set(mask, 10000baseER_Full);
+ phylink_set(mask, 10000baseKR_Full);
+ phylink_set(mask, 10000baseLR_Full);
+ phylink_set(mask, 10000baseLRM_Full);
+ phylink_set(mask, 10000baseSR_Full);
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 5000baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ phylink_set(mask, 1000baseX_Full);
+ }
+ /* fallthrough */
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
@@ -530,6 +564,80 @@ static int gem_phylink_mac_link_state(struct phylink_config *pl_config,
return -EOPNOTSUPP;
}
+static int macb_wait_for_usx_block_lock(struct macb *bp)
+{
+ u32 val;
+
+ return readx_poll_timeout(GEM_READ_USX_STATUS, bp, val,
+ val & GEM_BIT(USX_BLOCK_LOCK),
+ 1, MACB_USX_BLOCK_LOCK_TIMEOUT);
+}
+
+static inline int gem_mac_usx_configure(struct macb *bp, int spd)
+{
+ u32 speed, config;
+
+ gem_writel(bp, NCFGR, GEM_BIT(PCSSEL) |
+ (~GEM_BIT(SGMIIEN) & gem_readl(bp, NCFGR)));
+ gem_writel(bp, NCR, gem_readl(bp, NCR) |
+ GEM_BIT(ENABLE_HS_MAC));
+ gem_writel(bp, NCFGR, gem_readl(bp, NCFGR) |
+ MACB_BIT(FD));
+ config = gem_readl(bp, USX_CONTROL);
+ config = GEM_BFINS(SERDES_RATE, MACB_SERDES_RATE_10G, config);
+ config &= ~GEM_BIT(TX_SCR_BYPASS);
+ config &= ~GEM_BIT(RX_SCR_BYPASS);
+ gem_writel(bp, USX_CONTROL, config |
+ GEM_BIT(TX_EN));
+ config = gem_readl(bp, USX_CONTROL);
+ gem_writel(bp, USX_CONTROL, config | GEM_BIT(SIGNAL_OK));
+ if (macb_wait_for_usx_block_lock(bp) < 0) {
+ netdev_warn(bp->dev, "USXGMII block lock failed");
+ return -ETIMEDOUT;
+ }
+
+ switch (spd) {
+ case SPEED_10000:
+ speed = HS_MAC_SPEED_10000M;
+ break;
+ case SPEED_5000:
+ speed = HS_MAC_SPEED_5000M;
+ break;
+ case SPEED_2500:
+ speed = HS_MAC_SPEED_2500M;
+ break;
+ case SPEED_1000:
+ speed = HS_MAC_SPEED_1000M;
+ break;
+ default:
+ case SPEED_100:
+ speed = HS_MAC_SPEED_100M;
+ break;
+ }
+
+ gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, speed,
+ gem_readl(bp, HS_MAC_CONFIG)));
+ gem_writel(bp, USX_CONTROL, GEM_BFINS(USX_CTRL_SPEED, speed,
+ gem_readl(bp, USX_CONTROL)));
+ return 0;
+}
+
+static inline void gem_mac_configure(struct macb *bp, int speed)
+{
+ switch (speed) {
+ case SPEED_1000:
+ gem_writel(bp, NCFGR, GEM_BIT(GBE) |
+ gem_readl(bp, NCFGR));
+ break;
+ case SPEED_100:
+ macb_writel(bp, NCFGR, MACB_BIT(SPD) |
+ macb_readl(bp, NCFGR));
+ break;
+ default:
+ break;
+ }
+}
+
static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
const struct phylink_link_state *state)
{
@@ -572,18 +680,17 @@ static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
reg &= ~GEM_BIT(GBE);
if (state->duplex)
reg |= MACB_BIT(FD);
+ macb_or_gem_writel(bp, NCFGR, reg);
- switch (state->speed) {
- case SPEED_1000:
- reg |= GEM_BIT(GBE);
- break;
- case SPEED_100:
- reg |= MACB_BIT(SPD);
- break;
- default:
- break;
+ if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
+ if (gem_mac_usx_configure(bp, state->speed) < 0) {
+ spin_unlock_irqrestore(&bp->lock, flags);
+ phylink_mac_change(bp->pl, false);
+ return;
+ }
+ } else {
+ gem_mac_configure(bp, state->speed);
}
- macb_or_gem_writel(bp, NCFGR, reg);
bp->speed = state->speed;
bp->duplex = state->duplex;
@@ -3419,6 +3526,9 @@ static void macb_configure_caps(struct macb *bp,
bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
if (GEM_BFEXT(NO_PCS, dcfg) == 0)
bp->caps |= MACB_CAPS_PCS;
+ dcfg = gem_readl(bp, DCFG12);
+ if (GEM_BFEXT(HIGH_SPEED, dcfg) == 1)
+ bp->caps |= MACB_CAPS_HIGH_SPEED;
dcfg = gem_readl(bp, DCFG2);
if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
bp->caps |= MACB_CAPS_FIFO_MODE;
--
1.7.1
^ permalink raw reply related [flat|nested] 8+ messages in thread