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 */ >