Skip to content

Commit

Permalink
dpaa2-eth: add MAC/PHY support through phylink
Browse files Browse the repository at this point in the history
The dpaa2-eth driver now has support for connecting to its associated
PHY device found through standard OF bindings.

This happens when the DPNI object (that the driver probes on) gets
connected to a DPMAC. When that happens, the device tree is looked up by
the DPMAC ID, and the associated PHY bindings are found.

The old logic of handling the net device's link state by hand still
needs to be kept, as the DPNI can be connected to other devices on the
bus than a DPMAC: other DPNI, DPSW ports, etc. This logic is only
engaged when there is no DPMAC (and therefore no phylink instance)
attached.

The MC firmware support multiple type of DPMAC links: TYPE_FIXED,
TYPE_PHY. The TYPE_FIXED mode does not require any DPMAC management from
Linux side, and as such, the driver will not handle such a DPMAC.

Although PHYLINK typically handles SFP cages and in-band AN modes, for
the moment the driver only supports the RGMII interfaces found on the
LX2160A. Support for other modes will come later.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
IoanaCiornei authored and davem330 committed Oct 31, 2019
1 parent f5c3fff commit 7194792
Show file tree
Hide file tree
Showing 10 changed files with 818 additions and 21 deletions.
2 changes: 2 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -5053,7 +5053,9 @@ M: Ioana Radulescu <ruxandra.radulescu@nxp.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth*
F: drivers/net/ethernet/freescale/dpaa2/dpaa2-mac*
F: drivers/net/ethernet/freescale/dpaa2/dpni*
F: drivers/net/ethernet/freescale/dpaa2/dpmac*
F: drivers/net/ethernet/freescale/dpaa2/dpkg.h
F: drivers/net/ethernet/freescale/dpaa2/Makefile
F: drivers/net/ethernet/freescale/dpaa2/Kconfig
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/freescale/dpaa2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o
obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o

fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o
fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o
fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o

Expand Down
119 changes: 99 additions & 20 deletions drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2014-2016 Freescale Semiconductor Inc.
* Copyright 2016-2017 NXP
* Copyright 2016-2019 NXP
*/
#include <linux/init.h>
#include <linux/module.h>
Expand Down Expand Up @@ -1276,6 +1276,12 @@ static int link_state_update(struct dpaa2_eth_priv *priv)
!!(state.options & DPNI_LINK_OPT_ASYM_PAUSE);
dpaa2_eth_set_rx_taildrop(priv, !tx_pause);

/* When we manage the MAC/PHY using phylink there is no need
* to manually update the netif_carrier.
*/
if (priv->mac)
goto out;

/* Chech link state; speed / duplex changes are not treated yet */
if (priv->link_state.up == state.up)
goto out;
Expand Down Expand Up @@ -1312,31 +1318,39 @@ static int dpaa2_eth_open(struct net_device *net_dev)
priv->dpbp_dev->obj_desc.id, priv->bpid);
}

/* We'll only start the txqs when the link is actually ready; make sure
* we don't race against the link up notification, which may come
* immediately after dpni_enable();
*/
netif_tx_stop_all_queues(net_dev);
if (!priv->mac) {
/* We'll only start the txqs when the link is actually ready;
* make sure we don't race against the link up notification,
* which may come immediately after dpni_enable();
*/
netif_tx_stop_all_queues(net_dev);

/* Also, explicitly set carrier off, otherwise
* netif_carrier_ok() will return true and cause 'ip link show'
* to report the LOWER_UP flag, even though the link
* notification wasn't even received.
*/
netif_carrier_off(net_dev);
}
enable_ch_napi(priv);
/* Also, explicitly set carrier off, otherwise netif_carrier_ok() will
* return true and cause 'ip link show' to report the LOWER_UP flag,
* even though the link notification wasn't even received.
*/
netif_carrier_off(net_dev);

err = dpni_enable(priv->mc_io, 0, priv->mc_token);
if (err < 0) {
netdev_err(net_dev, "dpni_enable() failed\n");
goto enable_err;
}

/* If the DPMAC object has already processed the link up interrupt,
* we have to learn the link state ourselves.
*/
err = link_state_update(priv);
if (err < 0) {
netdev_err(net_dev, "Can't update link state\n");
goto link_state_err;
if (!priv->mac) {
/* If the DPMAC object has already processed the link up
* interrupt, we have to learn the link state ourselves.
*/
err = link_state_update(priv);
if (err < 0) {
netdev_err(net_dev, "Can't update link state\n");
goto link_state_err;
}
} else {
phylink_start(priv->mac->phylink);
}

return 0;
Expand Down Expand Up @@ -1411,8 +1425,12 @@ static int dpaa2_eth_stop(struct net_device *net_dev)
int dpni_enabled = 0;
int retries = 10;

netif_tx_stop_all_queues(net_dev);
netif_carrier_off(net_dev);
if (!priv->mac) {
netif_tx_stop_all_queues(net_dev);
netif_carrier_off(net_dev);
} else {
phylink_stop(priv->mac->phylink);
}

/* On dpni_disable(), the MC firmware will:
* - stop MAC Rx and wait for all Rx frames to be enqueued to software
Expand Down Expand Up @@ -3342,12 +3360,56 @@ static int poll_link_state(void *arg)
return 0;
}

static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
{
struct fsl_mc_device *dpni_dev, *dpmac_dev;
struct dpaa2_mac *mac;
int err;

dpni_dev = to_fsl_mc_device(priv->net_dev->dev.parent);
dpmac_dev = fsl_mc_get_endpoint(dpni_dev);
if (IS_ERR(dpmac_dev) || dpmac_dev->dev.type != &fsl_mc_bus_dpmac_type)
return 0;

if (dpaa2_mac_is_type_fixed(dpmac_dev, priv->mc_io))
return 0;

mac = kzalloc(sizeof(struct dpaa2_mac), GFP_KERNEL);
if (!mac)
return -ENOMEM;

mac->mc_dev = dpmac_dev;
mac->mc_io = priv->mc_io;
mac->net_dev = priv->net_dev;

err = dpaa2_mac_connect(mac);
if (err) {
netdev_err(priv->net_dev, "Error connecting to the MAC endpoint\n");
kfree(mac);
return err;
}
priv->mac = mac;

return 0;
}

static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)
{
if (!priv->mac)
return;

dpaa2_mac_disconnect(priv->mac);
kfree(priv->mac);
priv->mac = NULL;
}

static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
{
u32 status = ~0;
struct device *dev = (struct device *)arg;
struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev);
struct net_device *net_dev = dev_get_drvdata(dev);
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
int err;

err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle,
Expand All @@ -3363,6 +3425,13 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
if (status & DPNI_IRQ_EVENT_ENDPOINT_CHANGED) {
set_mac_addr(netdev_priv(net_dev));
update_tx_fqids(priv);

rtnl_lock();
if (priv->mac)
dpaa2_eth_disconnect_mac(priv);
else
dpaa2_eth_connect_mac(priv);
rtnl_unlock();
}

return IRQ_HANDLED;
Expand Down Expand Up @@ -3539,6 +3608,10 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv->do_link_poll = true;
}

err = dpaa2_eth_connect_mac(priv);
if (err)
goto err_connect_mac;

err = register_netdev(net_dev);
if (err < 0) {
dev_err(dev, "register_netdev() failed\n");
Expand All @@ -3553,6 +3626,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
return 0;

err_netdev_reg:
dpaa2_eth_disconnect_mac(priv);
err_connect_mac:
if (priv->do_link_poll)
kthread_stop(priv->poll_thread);
else
Expand Down Expand Up @@ -3595,6 +3670,10 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
#ifdef CONFIG_DEBUG_FS
dpaa2_dbg_remove(priv);
#endif
rtnl_lock();
dpaa2_eth_disconnect_mac(priv);
rtnl_unlock();

unregister_netdev(net_dev);

if (priv->do_link_poll)
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "dpaa2-eth-trace.h"
#include "dpaa2-eth-debugfs.h"
#include "dpaa2-mac.h"

#define DPAA2_WRIOP_VERSION(x, y, z) ((x) << 10 | (y) << 5 | (z) << 0)

Expand Down Expand Up @@ -415,6 +416,8 @@ struct dpaa2_eth_priv {
#ifdef CONFIG_DEBUG_FS
struct dpaa2_debugfs dbg;
#endif

struct dpaa2_mac *mac;
};

#define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \
Expand Down
25 changes: 25 additions & 0 deletions drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);

if (priv->mac)
return phylink_ethtool_ksettings_get(priv->mac->phylink,
link_settings);

link_settings->base.autoneg = AUTONEG_DISABLE;
if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
link_settings->base.duplex = DUPLEX_FULL;
Expand All @@ -93,12 +97,29 @@ dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
return 0;
}

static int
dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
const struct ethtool_link_ksettings *link_settings)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);

if (!priv->mac)
return -ENOTSUPP;

return phylink_ethtool_ksettings_set(priv->mac->phylink, link_settings);
}

static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
u64 link_options = priv->link_state.options;

if (priv->mac) {
phylink_ethtool_get_pauseparam(priv->mac->phylink, pause);
return;
}

pause->rx_pause = !!(link_options & DPNI_LINK_OPT_PAUSE);
pause->tx_pause = pause->rx_pause ^
!!(link_options & DPNI_LINK_OPT_ASYM_PAUSE);
Expand All @@ -118,6 +139,9 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev,
return -EOPNOTSUPP;
}

if (priv->mac)
return phylink_ethtool_set_pauseparam(priv->mac->phylink,
pause);
if (pause->autoneg)
return -EOPNOTSUPP;

Expand Down Expand Up @@ -728,6 +752,7 @@ const struct ethtool_ops dpaa2_ethtool_ops = {
.get_drvinfo = dpaa2_eth_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_link_ksettings = dpaa2_eth_get_link_ksettings,
.set_link_ksettings = dpaa2_eth_set_link_ksettings,
.get_pauseparam = dpaa2_eth_get_pauseparam,
.set_pauseparam = dpaa2_eth_set_pauseparam,
.get_sset_count = dpaa2_eth_get_sset_count,
Expand Down
Loading

0 comments on commit 7194792

Please sign in to comment.