lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Wed, 23 Oct 2019 13:39:46 +0000
From:   Ioana Ciornei <ioana.ciornei@....com>
To:     "davem@...emloft.net" <davem@...emloft.net>,
        "netdev@...r.kernel.org" <netdev@...r.kernel.org>
CC:     Laurentiu Tudor <laurentiu.tudor@....com>,
        "andrew@...n.ch" <andrew@...n.ch>,
        "f.fainelli@...il.com" <f.fainelli@...il.com>,
        "linux@...linux.org.uk" <linux@...linux.org.uk>
Subject: Re: [PATCH net-next v2 4/5] dpaa2-eth: add MAC/PHY support through
 phylink

On 10/23/19 3:47 PM, Ioana Ciornei wrote:
> 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.

I unfortunately left a compile warning slip in this patch.
I'll send out a v3 once I can bundle it with any other changes.

Sorry for this,
Ioana

> 
> Signed-off-by: Ioana Ciornei <ioana.ciornei@....com>
> ---
> Changes in v2:
>   - move the locks to rtnl outside of dpaa2_eth_[dis]connect_mac functions
>   - remove setting supported/advertised from .validate()
> 
>   MAINTAINERS                                        |   2 +
>   drivers/net/ethernet/freescale/dpaa2/Makefile      |   2 +-
>   drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c   | 117 ++++++--
>   drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h   |   3 +
>   .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c   |  25 ++
>   drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c   | 302 +++++++++++++++++++++
>   drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h   |  32 +++
>   drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h   |  62 +++++
>   drivers/net/ethernet/freescale/dpaa2/dpmac.c       | 149 ++++++++++
>   drivers/net/ethernet/freescale/dpaa2/dpmac.h       | 144 ++++++++++
>   10 files changed, 817 insertions(+), 21 deletions(-)
>   create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
>   create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
>   create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h
>   create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpmac.c
>   create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpmac.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aaa6ee71c000..d0e562d3ce5b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5046,7 +5046,9 @@ M:	Ioana Radulescu <ruxandra.radulescu@....com>
>   L:	netdev@...r.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
> diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile
> index d1e78cdd512f..69184ca3b7b9 100644
> --- a/drivers/net/ethernet/freescale/dpaa2/Makefile
> +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile
> @@ -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
>   
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
> index 602d5118e928..35288a5d231d 100644
> --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
> @@ -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>
> @@ -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;
> @@ -1312,17 +1318,21 @@ 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) {
> @@ -1330,13 +1340,17 @@ static int dpaa2_eth_open(struct net_device *net_dev)
>   		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;
> @@ -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
> @@ -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 (!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,
> @@ -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;
> @@ -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");
> @@ -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
> @@ -3595,6 +3670,8 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
>   #ifdef CONFIG_DEBUG_FS
>   	dpaa2_dbg_remove(priv);
>   #endif
> +	dpaa2_eth_disconnect_mac(priv);
> +
>   	unregister_netdev(net_dev);
>   
>   	if (priv->do_link_poll)
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
> index 686b651edcb2..7635db3ef903 100644
> --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
> @@ -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)
>   
> @@ -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 \
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
> index dc9a6c36cac0..0883620631b8 100644
> --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
> @@ -85,6 +85,10 @@ static void dpaa2_eth_get_drvinfo(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;
> @@ -93,12 +97,29 @@ static void dpaa2_eth_get_drvinfo(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);
> @@ -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;
>   
> @@ -728,6 +752,7 @@ static int dpaa2_eth_get_ts_info(struct net_device *dev,
>   	.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,
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
> new file mode 100644
> index 000000000000..c4e9da845d44
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
> @@ -0,0 +1,302 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> +/* Copyright 2019 NXP */
> +
> +#include "dpaa2-eth.h"
> +#include "dpaa2-mac.h"
> +
> +#define phylink_to_dpaa2_mac(config) \
> +	container_of((config), struct dpaa2_mac, phylink_config)
> +
> +static phy_interface_t phy_mode(enum dpmac_eth_if eth_if)
> +{
> +	switch (eth_if) {
> +	case DPMAC_ETH_IF_RGMII:
> +		return PHY_INTERFACE_MODE_RGMII;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +/* Caller must call of_node_put on the returned value */
> +static struct device_node *dpaa2_mac_get_node(u16 dpmac_id)
> +{
> +	struct device_node *dpmacs, *dpmac = NULL;
> +	u32 id;
> +	int err;
> +
> +	dpmacs = of_find_node_by_name(NULL, "dpmacs");
> +	if (!dpmacs)
> +		return NULL;
> +
> +	while ((dpmac = of_get_next_child(dpmacs, dpmac)) != NULL) {
> +		err = of_property_read_u32(dpmac, "reg", &id);
> +		if (err)
> +			continue;
> +		if (id == dpmac_id)
> +			break;
> +	}
> +
> +	of_node_put(dpmacs);
> +
> +	return dpmac;
> +}
> +
> +static int dpaa2_mac_get_if_mode(struct device_node *node,
> +				 struct dpmac_attr attr)
> +{
> +	int if_mode;
> +
> +	if_mode = of_get_phy_mode(node);
> +	if (if_mode >= 0)
> +		return if_mode;
> +
> +	if_mode = phy_mode(attr.eth_if);
> +	if (if_mode >= 0)
> +		return if_mode;
> +
> +	return -ENODEV;
> +}
> +
> +static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac,
> +					phy_interface_t interface)
> +{
> +	switch (interface) {
> +	case PHY_INTERFACE_MODE_RGMII:
> +	case PHY_INTERFACE_MODE_RGMII_ID:
> +	case PHY_INTERFACE_MODE_RGMII_RXID:
> +	case PHY_INTERFACE_MODE_RGMII_TXID:
> +		return (interface != mac->if_mode);
> +	default:
> +		return true;
> +	}
> +}
> +
> +static void dpaa2_mac_validate(struct phylink_config *config,
> +			       unsigned long *supported,
> +			       struct phylink_link_state *state)
> +{
> +	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
> +	struct dpmac_link_state *dpmac_state = &mac->state;
> +	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
> +
> +	if (state->interface != PHY_INTERFACE_MODE_NA &&
> +	    dpaa2_mac_phy_mode_mismatch(mac, state->interface)) {
> +		goto empty_set;
> +	}
> +
> +	phylink_set_port_modes(mask);
> +	phylink_set(mask, Autoneg);
> +	phylink_set(mask, Pause);
> +	phylink_set(mask, Asym_Pause);
> +
> +	switch (state->interface) {
> +	case PHY_INTERFACE_MODE_RGMII:
> +	case PHY_INTERFACE_MODE_RGMII_ID:
> +	case PHY_INTERFACE_MODE_RGMII_RXID:
> +	case PHY_INTERFACE_MODE_RGMII_TXID:
> +		phylink_set(mask, 10baseT_Full);
> +		phylink_set(mask, 100baseT_Full);
> +		phylink_set(mask, 1000baseT_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 void dpaa2_mac_config(struct phylink_config *config, unsigned int mode,
> +			     const struct phylink_link_state *state)
> +{
> +	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
> +	struct dpmac_link_state *dpmac_state = &mac->state;
> +	int err;
> +
> +	if (state->speed != SPEED_UNKNOWN)
> +		dpmac_state->rate = state->speed;
> +
> +	if (state->duplex != DUPLEX_UNKNOWN) {
> +		if (!state->duplex)
> +			dpmac_state->options |= DPMAC_LINK_OPT_HALF_DUPLEX;
> +		else
> +			dpmac_state->options &= ~DPMAC_LINK_OPT_HALF_DUPLEX;
> +	}
> +
> +	if (state->an_enabled)
> +		dpmac_state->options |= DPMAC_LINK_OPT_AUTONEG;
> +	else
> +		dpmac_state->options &= ~DPMAC_LINK_OPT_AUTONEG;
> +
> +	if (state->pause & MLO_PAUSE_RX)
> +		dpmac_state->options |= DPMAC_LINK_OPT_PAUSE;
> +	else
> +		dpmac_state->options &= ~DPMAC_LINK_OPT_PAUSE;
> +
> +	if (!!(state->pause & MLO_PAUSE_RX) ^ !!(state->pause & MLO_PAUSE_TX))
> +		dpmac_state->options |= DPMAC_LINK_OPT_ASYM_PAUSE;
> +	else
> +		dpmac_state->options &= ~DPMAC_LINK_OPT_ASYM_PAUSE;
> +
> +	err = dpmac_set_link_state(mac->mc_io, 0,
> +				   mac->mc_dev->mc_handle, dpmac_state);
> +	if (err)
> +		netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err);
> +}
> +
> +static void dpaa2_mac_link_up(struct phylink_config *config, unsigned int mode,
> +			      phy_interface_t interface, struct phy_device *phy)
> +{
> +	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
> +	struct dpmac_link_state *dpmac_state = &mac->state;
> +	int err;
> +
> +	dpmac_state->up = 1;
> +	err = dpmac_set_link_state(mac->mc_io, 0,
> +				   mac->mc_dev->mc_handle, dpmac_state);
> +	if (err)
> +		netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err);
> +}
> +
> +static void dpaa2_mac_link_down(struct phylink_config *config,
> +				unsigned int mode,
> +				phy_interface_t interface)
> +{
> +	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
> +	struct dpmac_link_state *dpmac_state = &mac->state;
> +	int err;
> +
> +	dpmac_state->up = 0;
> +	err = dpmac_set_link_state(mac->mc_io, 0,
> +				   mac->mc_dev->mc_handle, dpmac_state);
> +	if (err)
> +		netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err);
> +}
> +
> +static const struct phylink_mac_ops dpaa2_mac_phylink_ops = {
> +	.validate = dpaa2_mac_validate,
> +	.mac_config = dpaa2_mac_config,
> +	.mac_link_up = dpaa2_mac_link_up,
> +	.mac_link_down = dpaa2_mac_link_down,
> +};
> +
> +bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
> +			     struct fsl_mc_io *mc_io)
> +{
> +	struct dpmac_attr attr;
> +	bool fixed = false;
> +	u16 mc_handle = 0;
> +	int err;
> +
> +	err = dpmac_open(mc_io, 0, dpmac_dev->obj_desc.id,
> +			 &mc_handle);
> +	if (err || !mc_handle)
> +		return false;
> +
> +	err = dpmac_get_attributes(mc_io, 0, mc_handle, &attr);
> +	if (err)
> +		goto out;
> +
> +	if (attr.link_type == DPMAC_LINK_TYPE_FIXED)
> +		fixed = true;
> +
> +out:
> +	dpmac_close(mc_io, 0, mc_handle);
> +
> +	return fixed;
> +}
> +
> +int dpaa2_mac_connect(struct dpaa2_mac *mac)
> +{
> +	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
> +	struct net_device *net_dev = mac->net_dev;
> +	struct device_node *dpmac_node;
> +	struct phylink *phylink;
> +	struct dpmac_attr attr;
> +	int err;
> +
> +	err = dpmac_open(mac->mc_io, 0, dpmac_dev->obj_desc.id,
> +			 &dpmac_dev->mc_handle);
> +	if (err || !dpmac_dev->mc_handle) {
> +		netdev_err(net_dev, "dpmac_open() = %d\n", err);
> +		return -ENODEV;
> +	}
> +
> +	err = dpmac_get_attributes(mac->mc_io, 0, dpmac_dev->mc_handle, &attr);
> +	if (err) {
> +		netdev_err(net_dev, "dpmac_get_attributes() = %d\n", err);
> +		goto err_close_dpmac;
> +	}
> +
> +	dpmac_node = dpaa2_mac_get_node(attr.id);
> +	if (!dpmac_node) {
> +		netdev_err(net_dev, "No dpmac@%d node found.\n", attr.id);
> +		err = -ENODEV;
> +		goto err_close_dpmac;
> +	}
> +
> +	err = dpaa2_mac_get_if_mode(dpmac_node, attr);
> +	if (err < 0) {
> +		err = -EINVAL;
> +		goto err_put_node;
> +	}
> +	mac->if_mode = err;
> +
> +	/* The MAC does not have the capability to add RGMII delays so
> +	 * error out if the interface mode requests them and there is no PHY
> +	 * to act upon them
> +	 */
> +	if (of_phy_is_fixed_link(dpmac_node) &&
> +	    (mac->if_mode == PHY_INTERFACE_MODE_RGMII_ID ||
> +	     mac->if_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
> +	     mac->if_mode == PHY_INTERFACE_MODE_RGMII_TXID)) {
> +		netdev_err(net_dev, "RGMII delay not supported\n");
> +		err = -EINVAL;
> +		goto err_put_node;
> +	}
> +
> +	mac->phylink_config.dev = &net_dev->dev;
> +	mac->phylink_config.type = PHYLINK_NETDEV;
> +
> +	phylink = phylink_create(&mac->phylink_config,
> +				 of_fwnode_handle(dpmac_node), mac->if_mode,
> +				 &dpaa2_mac_phylink_ops);
> +	if (IS_ERR(phylink)) {
> +		err = PTR_ERR(phylink);
> +		goto err_put_node;
> +	}
> +	mac->phylink = phylink;
> +
> +	err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
> +	if (err) {
> +		netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err);
> +		goto err_phylink_destroy;
> +	}
> +
> +	of_node_put(dpmac_node);
> +
> +	return 0;
> +
> +err_phylink_destroy:
> +	phylink_destroy(mac->phylink);
> +err_put_node:
> +	of_node_put(dpmac_node);
> +err_close_dpmac:
> +	dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
> +	return err;
> +}
> +
> +void dpaa2_mac_disconnect(struct dpaa2_mac *mac)
> +{
> +	if (!mac->phylink)
> +		return;
> +
> +	phylink_disconnect_phy(mac->phylink);
> +	phylink_destroy(mac->phylink);
> +	dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle);
> +}
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
> new file mode 100644
> index 000000000000..8634d0de7ef3
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
> @@ -0,0 +1,32 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> +/* Copyright 2019 NXP */
> +#ifndef DPAA2_MAC_H
> +#define DPAA2_MAC_H
> +
> +#include <linux/of.h>
> +#include <linux/of_mdio.h>
> +#include <linux/of_net.h>
> +#include <linux/phylink.h>
> +
> +#include "dpmac.h"
> +#include "dpmac-cmd.h"
> +
> +struct dpaa2_mac {
> +	struct fsl_mc_device *mc_dev;
> +	struct dpmac_link_state state;
> +	struct net_device *net_dev;
> +	struct fsl_mc_io *mc_io;
> +
> +	struct phylink_config phylink_config;
> +	struct phylink *phylink;
> +	phy_interface_t if_mode;
> +};
> +
> +bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
> +			     struct fsl_mc_io *mc_io);
> +
> +int dpaa2_mac_connect(struct dpaa2_mac *mac);
> +
> +void dpaa2_mac_disconnect(struct dpaa2_mac *mac);
> +
> +#endif /* DPAA2_MAC_H */
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h
> new file mode 100644
> index 000000000000..96a9b0d0992e
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h
> @@ -0,0 +1,62 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> +/* Copyright 2013-2016 Freescale Semiconductor Inc.
> + * Copyright 2019 NXP
> + */
> +#ifndef _FSL_DPMAC_CMD_H
> +#define _FSL_DPMAC_CMD_H
> +
> +/* DPMAC Version */
> +#define DPMAC_VER_MAJOR				4
> +#define DPMAC_VER_MINOR				4
> +#define DPMAC_CMD_BASE_VERSION			1
> +#define DPMAC_CMD_2ND_VERSION			2
> +#define DPMAC_CMD_ID_OFFSET			4
> +
> +#define DPMAC_CMD(id)	(((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_BASE_VERSION)
> +#define DPMAC_CMD_V2(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_2ND_VERSION)
> +
> +/* Command IDs */
> +#define DPMAC_CMDID_CLOSE		DPMAC_CMD(0x800)
> +#define DPMAC_CMDID_OPEN		DPMAC_CMD(0x80c)
> +
> +#define DPMAC_CMDID_GET_ATTR		DPMAC_CMD(0x004)
> +#define DPMAC_CMDID_SET_LINK_STATE	DPMAC_CMD_V2(0x0c3)
> +
> +/* Macros for accessing command fields smaller than 1byte */
> +#define DPMAC_MASK(field)        \
> +	GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \
> +		DPMAC_##field##_SHIFT)
> +
> +#define dpmac_set_field(var, field, val) \
> +	((var) |= (((val) << DPMAC_##field##_SHIFT) & DPMAC_MASK(field)))
> +#define dpmac_get_field(var, field)      \
> +	(((var) & DPMAC_MASK(field)) >> DPMAC_##field##_SHIFT)
> +
> +struct dpmac_cmd_open {
> +	__le32 dpmac_id;
> +};
> +
> +struct dpmac_rsp_get_attributes {
> +	u8 eth_if;
> +	u8 link_type;
> +	__le16 id;
> +	__le32 max_rate;
> +};
> +
> +#define DPMAC_STATE_SIZE	1
> +#define DPMAC_STATE_SHIFT	0
> +#define DPMAC_STATE_VALID_SIZE	1
> +#define DPMAC_STATE_VALID_SHIFT	1
> +
> +struct dpmac_cmd_set_link_state {
> +	__le64 options;
> +	__le32 rate;
> +	__le32 pad0;
> +	/* from lsb: up:1, state_valid:1 */
> +	u8 state;
> +	u8 pad1[7];
> +	__le64 supported;
> +	__le64 advertising;
> +};
> +
> +#endif /* _FSL_DPMAC_CMD_H */
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.c b/drivers/net/ethernet/freescale/dpaa2/dpmac.c
> new file mode 100644
> index 000000000000..b75189deffb1
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> +/* Copyright 2013-2016 Freescale Semiconductor Inc.
> + * Copyright 2019 NXP
> + */
> +#include <linux/fsl/mc.h>
> +#include "dpmac.h"
> +#include "dpmac-cmd.h"
> +
> +/**
> + * dpmac_open() - Open a control session for the specified object.
> + * @mc_io:	Pointer to MC portal's I/O object
> + * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
> + * @dpmac_id:	DPMAC unique ID
> + * @token:	Returned token; use in subsequent API calls
> + *
> + * This function can be used to open a control session for an
> + * already created object; an object may have been declared in
> + * the DPL or by calling the dpmac_create function.
> + * This function returns a unique authentication token,
> + * associated with the specific object ID and the specific MC
> + * portal; this token must be used in all subsequent commands for
> + * this specific object
> + *
> + * Return:	'0' on Success; Error code otherwise.
> + */
> +int dpmac_open(struct fsl_mc_io *mc_io,
> +	       u32 cmd_flags,
> +	       int dpmac_id,
> +	       u16 *token)
> +{
> +	struct dpmac_cmd_open *cmd_params;
> +	struct fsl_mc_command cmd = { 0 };
> +	int err;
> +
> +	/* prepare command */
> +	cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN,
> +					  cmd_flags,
> +					  0);
> +	cmd_params = (struct dpmac_cmd_open *)cmd.params;
> +	cmd_params->dpmac_id = cpu_to_le32(dpmac_id);
> +
> +	/* send command to mc*/
> +	err = mc_send_command(mc_io, &cmd);
> +	if (err)
> +		return err;
> +
> +	/* retrieve response parameters */
> +	*token = mc_cmd_hdr_read_token(&cmd);
> +
> +	return err;
> +}
> +
> +/**
> + * dpmac_close() - Close the control session of the object
> + * @mc_io:	Pointer to MC portal's I/O object
> + * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
> + * @token:	Token of DPMAC object
> + *
> + * After this function is called, no further operations are
> + * allowed on the object without opening a new control session.
> + *
> + * Return:	'0' on Success; Error code otherwise.
> + */
> +int dpmac_close(struct fsl_mc_io *mc_io,
> +		u32 cmd_flags,
> +		u16 token)
> +{
> +	struct fsl_mc_command cmd = { 0 };
> +
> +	/* prepare command */
> +	cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags,
> +					  token);
> +
> +	/* send command to mc*/
> +	return mc_send_command(mc_io, &cmd);
> +}
> +
> +/**
> + * dpmac_get_attributes - Retrieve DPMAC attributes.
> + *
> + * @mc_io:	Pointer to MC portal's I/O object
> + * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
> + * @token:	Token of DPMAC object
> + * @attr:	Returned object's attributes
> + *
> + * Return:	'0' on Success; Error code otherwise.
> + */
> +int dpmac_get_attributes(struct fsl_mc_io *mc_io,
> +			 u32 cmd_flags,
> +			 u16 token,
> +			 struct dpmac_attr *attr)
> +{
> +	struct dpmac_rsp_get_attributes *rsp_params;
> +	struct fsl_mc_command cmd = { 0 };
> +	int err;
> +
> +	/* prepare command */
> +	cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR,
> +					  cmd_flags,
> +					  token);
> +
> +	/* send command to mc*/
> +	err = mc_send_command(mc_io, &cmd);
> +	if (err)
> +		return err;
> +
> +	/* retrieve response parameters */
> +	rsp_params = (struct dpmac_rsp_get_attributes *)cmd.params;
> +	attr->eth_if = rsp_params->eth_if;
> +	attr->link_type = rsp_params->link_type;
> +	attr->id = le16_to_cpu(rsp_params->id);
> +	attr->max_rate = le32_to_cpu(rsp_params->max_rate);
> +
> +	return 0;
> +}
> +
> +/**
> + * dpmac_set_link_state() - Set the Ethernet link status
> + * @mc_io:      Pointer to opaque I/O object
> + * @cmd_flags:  Command flags; one or more of 'MC_CMD_FLAG_'
> + * @token:      Token of DPMAC object
> + * @link_state: Link state configuration
> + *
> + * Return:      '0' on Success; Error code otherwise.
> + */
> +int dpmac_set_link_state(struct fsl_mc_io *mc_io,
> +			 u32 cmd_flags,
> +			 u16 token,
> +			 struct dpmac_link_state *link_state)
> +{
> +	struct dpmac_cmd_set_link_state *cmd_params;
> +	struct fsl_mc_command cmd = { 0 };
> +
> +	/* prepare command */
> +	cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE,
> +					  cmd_flags,
> +					  token);
> +	cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params;
> +	cmd_params->options = cpu_to_le64(link_state->options);
> +	cmd_params->rate = cpu_to_le32(link_state->rate);
> +	dpmac_set_field(cmd_params->state, STATE, link_state->up);
> +	dpmac_set_field(cmd_params->state, STATE_VALID,
> +			link_state->state_valid);
> +	cmd_params->supported = cpu_to_le64(link_state->supported);
> +	cmd_params->advertising = cpu_to_le64(link_state->advertising);
> +
> +	/* send command to mc*/
> +	return mc_send_command(mc_io, &cmd);
> +}
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.h b/drivers/net/ethernet/freescale/dpaa2/dpmac.h
> new file mode 100644
> index 000000000000..4efc410a479e
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.h
> @@ -0,0 +1,144 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> +/* Copyright 2013-2016 Freescale Semiconductor Inc.
> + * Copyright 2019 NXP
> + */
> +#ifndef __FSL_DPMAC_H
> +#define __FSL_DPMAC_H
> +
> +/* Data Path MAC API
> + * Contains initialization APIs and runtime control APIs for DPMAC
> + */
> +
> +struct fsl_mc_io;
> +
> +int dpmac_open(struct fsl_mc_io *mc_io,
> +	       u32 cmd_flags,
> +	       int dpmac_id,
> +	       u16 *token);
> +
> +int dpmac_close(struct fsl_mc_io *mc_io,
> +		u32 cmd_flags,
> +		u16 token);
> +
> +/**
> + * enum dpmac_link_type -  DPMAC link type
> + * @DPMAC_LINK_TYPE_NONE: No link
> + * @DPMAC_LINK_TYPE_FIXED: Link is fixed type
> + * @DPMAC_LINK_TYPE_PHY: Link by PHY ID
> + * @DPMAC_LINK_TYPE_BACKPLANE: Backplane link type
> + */
> +enum dpmac_link_type {
> +	DPMAC_LINK_TYPE_NONE,
> +	DPMAC_LINK_TYPE_FIXED,
> +	DPMAC_LINK_TYPE_PHY,
> +	DPMAC_LINK_TYPE_BACKPLANE
> +};
> +
> +/**
> + * enum dpmac_eth_if - DPMAC Ethrnet interface
> + * @DPMAC_ETH_IF_MII: MII interface
> + * @DPMAC_ETH_IF_RMII: RMII interface
> + * @DPMAC_ETH_IF_SMII: SMII interface
> + * @DPMAC_ETH_IF_GMII: GMII interface
> + * @DPMAC_ETH_IF_RGMII: RGMII interface
> + * @DPMAC_ETH_IF_SGMII: SGMII interface
> + * @DPMAC_ETH_IF_QSGMII: QSGMII interface
> + * @DPMAC_ETH_IF_XAUI: XAUI interface
> + * @DPMAC_ETH_IF_XFI: XFI interface
> + * @DPMAC_ETH_IF_CAUI: CAUI interface
> + * @DPMAC_ETH_IF_1000BASEX: 1000BASEX interface
> + * @DPMAC_ETH_IF_USXGMII: USXGMII interface
> + */
> +enum dpmac_eth_if {
> +	DPMAC_ETH_IF_MII,
> +	DPMAC_ETH_IF_RMII,
> +	DPMAC_ETH_IF_SMII,
> +	DPMAC_ETH_IF_GMII,
> +	DPMAC_ETH_IF_RGMII,
> +	DPMAC_ETH_IF_SGMII,
> +	DPMAC_ETH_IF_QSGMII,
> +	DPMAC_ETH_IF_XAUI,
> +	DPMAC_ETH_IF_XFI,
> +	DPMAC_ETH_IF_CAUI,
> +	DPMAC_ETH_IF_1000BASEX,
> +	DPMAC_ETH_IF_USXGMII,
> +};
> +
> +/**
> + * struct dpmac_attr - Structure representing DPMAC attributes
> + * @id:		DPMAC object ID
> + * @max_rate:	Maximum supported rate - in Mbps
> + * @eth_if:	Ethernet interface
> + * @link_type:	link type
> + */
> +struct dpmac_attr {
> +	u16 id;
> +	u32 max_rate;
> +	enum dpmac_eth_if eth_if;
> +	enum dpmac_link_type link_type;
> +};
> +
> +int dpmac_get_attributes(struct fsl_mc_io *mc_io,
> +			 u32 cmd_flags,
> +			 u16 token,
> +			 struct dpmac_attr *attr);
> +
> +/**
> + * DPMAC link configuration/state options
> + */
> +
> +/**
> + * Enable auto-negotiation
> + */
> +#define DPMAC_LINK_OPT_AUTONEG			BIT_ULL(0)
> +/**
> + * Enable half-duplex mode
> + */
> +#define DPMAC_LINK_OPT_HALF_DUPLEX		BIT_ULL(1)
> +/**
> + * Enable pause frames
> + */
> +#define DPMAC_LINK_OPT_PAUSE			BIT_ULL(2)
> +/**
> + * Enable a-symmetric pause frames
> + */
> +#define DPMAC_LINK_OPT_ASYM_PAUSE		BIT_ULL(3)
> +
> +/**
> + * Advertised link speeds
> + */
> +#define DPMAC_ADVERTISED_10BASET_FULL		BIT_ULL(0)
> +#define DPMAC_ADVERTISED_100BASET_FULL		BIT_ULL(1)
> +#define DPMAC_ADVERTISED_1000BASET_FULL		BIT_ULL(2)
> +#define DPMAC_ADVERTISED_10000BASET_FULL	BIT_ULL(4)
> +#define DPMAC_ADVERTISED_2500BASEX_FULL		BIT_ULL(5)
> +
> +/**
> + * Advertise auto-negotiation enable
> + */
> +#define DPMAC_ADVERTISED_AUTONEG		BIT_ULL(3)
> +
> +/**
> + * struct dpmac_link_state - DPMAC link configuration request
> + * @rate: Rate in Mbps
> + * @options: Enable/Disable DPMAC link cfg features (bitmap)
> + * @up: Link state
> + * @state_valid: Ignore/Update the state of the link
> + * @supported: Speeds capability of the phy (bitmap)
> + * @advertising: Speeds that are advertised for autoneg (bitmap)
> + */
> +struct dpmac_link_state {
> +	u32 rate;
> +	u64 options;
> +	int up;
> +	int state_valid;
> +	u64 supported;
> +	u64 advertising;
> +};
> +
> +int dpmac_set_link_state(struct fsl_mc_io *mc_io,
> +			 u32 cmd_flags,
> +			 u16 token,
> +			 struct dpmac_link_state *link_state);
> +
> +#endif /* __FSL_DPMAC_H */
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ