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.cior...@nxp.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.radule...@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
> 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 */
> 

Reply via email to