aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch
diff options
context:
space:
mode:
authorYangbo Lu <yangbo.lu@nxp.com>2020-04-10 10:47:05 +0800
committerPetr Štetiar <ynezz@true.cz>2020-05-07 12:53:06 +0200
commitcddd4591404fb4c53dc0b3c0b15b942cdbed4356 (patch)
tree392c1179de46b0f804e3789edca19069b64e6b44 /target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch
parentd1d2c0b5579ea4f69a42246c9318539d61ba1999 (diff)
downloadupstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.tar.gz
upstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.tar.bz2
upstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.zip
layerscape: add patches-5.4
Add patches for linux-5.4. The patches are from NXP LSDK-20.04 release which was tagged LSDK-20.04-V5.4. https://source.codeaurora.org/external/qoriq/qoriq-components/linux/ For boards LS1021A-IOT, and Traverse-LS1043 which are not involved in LSDK, port the dts patches from 4.14. The patches are sorted into the following categories: 301-arch-xxxx 302-dts-xxxx 303-core-xxxx 701-net-xxxx 801-audio-xxxx 802-can-xxxx 803-clock-xxxx 804-crypto-xxxx 805-display-xxxx 806-dma-xxxx 807-gpio-xxxx 808-i2c-xxxx 809-jailhouse-xxxx 810-keys-xxxx 811-kvm-xxxx 812-pcie-xxxx 813-pm-xxxx 814-qe-xxxx 815-sata-xxxx 816-sdhc-xxxx 817-spi-xxxx 818-thermal-xxxx 819-uart-xxxx 820-usb-xxxx 821-vfio-xxxx Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch765
1 files changed, 765 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch
new file mode 100644
index 0000000000..750c6ce317
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch
@@ -0,0 +1,765 @@
+From 50ba3c63dc3f4fbeac32fc5675a00756723d786d Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Wed, 12 Apr 2017 12:42:07 +0000
+Subject: [PATCH] staging: fsl-dpaa2/mac: Add Freescale DPAA2 mac driver
+
+Introduce the DPAA2 mac driver, which manages Datapath
+Media Access Control (DPMAC) objects discovered on the
+MC bus.
+
+This driver works as a proxy between phylib including phy
+drivers and the Management Complex firmware. It receives
+updates on link state changes from PHY lib and forwards
+them to the Management Complex and receives interrupts
+from the Management Complex whenever a request is made to
+change the link state.
+
+This is a squashed commit containing contributions of the
+following owners:
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
+Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
+Signed-off-by: Itai Katz <itai.katz@freescale.com>
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/Kconfig | 2 +
+ drivers/staging/fsl-dpaa2/Makefile | 1 +
+ drivers/staging/fsl-dpaa2/mac/Kconfig | 23 ++
+ drivers/staging/fsl-dpaa2/mac/Makefile | 10 +
+ drivers/staging/fsl-dpaa2/mac/mac.c | 670 +++++++++++++++++++++++++++++++++
+ 5 files changed, 706 insertions(+)
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/Kconfig
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/Makefile
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/mac.c
+
+--- a/drivers/staging/fsl-dpaa2/Kconfig
++++ b/drivers/staging/fsl-dpaa2/Kconfig
+@@ -17,3 +17,5 @@ config FSL_DPAA2_ETHSW
+ help
+ Driver for Freescale DPAA2 Ethernet Switch. Select
+ BRIDGE to have support for bridge tools.
++
++source "drivers/staging/fsl-dpaa2/mac/Kconfig"
+--- a/drivers/staging/fsl-dpaa2/Makefile
++++ b/drivers/staging/fsl-dpaa2/Makefile
+@@ -4,3 +4,4 @@
+ #
+
+ obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/
++obj-$(CONFIG_FSL_DPAA2_MAC) += mac/
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/Kconfig
+@@ -0,0 +1,23 @@
++config FSL_DPAA2_MAC
++ tristate "DPAA2 MAC / PHY interface"
++ depends on FSL_MC_BUS && FSL_DPAA2
++ select MDIO_BUS_MUX_MMIOREG
++ select FSL_XGMAC_MDIO
++ select FIXED_PHY
++ ---help---
++ Prototype driver for DPAA2 MAC / PHY interface object.
++ This driver works as a proxy between phylib including phy drivers and
++ the MC firmware. It receives updates on link state changes from PHY
++ lib and forwards them to MC and receives interrupt from MC whenever
++ a request is made to change the link state.
++
++
++config FSL_DPAA2_MAC_NETDEVS
++ bool "Expose net interfaces for PHYs"
++ default n
++ depends on FSL_DPAA2_MAC
++ ---help---
++ Exposes macX net interfaces which allow direct control over MACs and
++ PHYs.
++ .
++ Leave disabled if unsure.
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/Makefile
+@@ -0,0 +1,10 @@
++
++obj-$(CONFIG_FSL_DPAA2_MAC) += dpaa2-mac.o
++
++dpaa2-mac-objs := mac.o dpmac.o
++
++all:
++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
++
++clean:
++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -0,0 +1,670 @@
++/* Copyright 2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of Freescale Semiconductor nor the
++ * names of its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/module.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/msi.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_vlan.h>
++
++#include <uapi/linux/if_bridge.h>
++#include <net/netlink.h>
++
++#include <linux/of.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/phy.h>
++#include <linux/phy_fixed.h>
++
++#include "../../fsl-mc/include/mc.h"
++#include "../../fsl-mc/include/mc-sys.h"
++
++#include "dpmac.h"
++#include "dpmac-cmd.h"
++
++struct dpaa2_mac_priv {
++ struct net_device *netdev;
++ struct fsl_mc_device *mc_dev;
++ struct dpmac_attr attr;
++ struct dpmac_link_state old_state;
++};
++
++/* TODO: fix the 10G modes, mapping can't be right:
++ * XGMII is paralel
++ * XAUI is serial, using 8b/10b encoding
++ * XFI is also serial but using 64b/66b encoding
++ * they can't all map to XGMII...
++ *
++ * This must be kept in sync with enum dpmac_eth_if.
++ */
++static phy_interface_t dpaa2_mac_iface_mode[] = {
++ PHY_INTERFACE_MODE_MII, /* DPMAC_ETH_IF_MII */
++ PHY_INTERFACE_MODE_RMII, /* DPMAC_ETH_IF_RMII */
++ PHY_INTERFACE_MODE_SMII, /* DPMAC_ETH_IF_SMII */
++ PHY_INTERFACE_MODE_GMII, /* DPMAC_ETH_IF_GMII */
++ PHY_INTERFACE_MODE_RGMII, /* DPMAC_ETH_IF_RGMII */
++ PHY_INTERFACE_MODE_SGMII, /* DPMAC_ETH_IF_SGMII */
++ PHY_INTERFACE_MODE_QSGMII, /* DPMAC_ETH_IF_QSGMII */
++ PHY_INTERFACE_MODE_XGMII, /* DPMAC_ETH_IF_XAUI */
++ PHY_INTERFACE_MODE_XGMII, /* DPMAC_ETH_IF_XFI */
++};
++
++static void dpaa2_mac_link_changed(struct net_device *netdev)
++{
++ struct phy_device *phydev;
++ struct dpmac_link_state state = { 0 };
++ struct dpaa2_mac_priv *priv = netdev_priv(netdev);
++ int err;
++
++ /* the PHY just notified us of link state change */
++ phydev = netdev->phydev;
++
++ state.up = !!phydev->link;
++ if (phydev->link) {
++ state.rate = phydev->speed;
++
++ if (!phydev->duplex)
++ state.options |= DPMAC_LINK_OPT_HALF_DUPLEX;
++ if (phydev->autoneg)
++ state.options |= DPMAC_LINK_OPT_AUTONEG;
++
++ netif_carrier_on(netdev);
++ } else {
++ netif_carrier_off(netdev);
++ }
++
++ if (priv->old_state.up != state.up ||
++ priv->old_state.rate != state.rate ||
++ priv->old_state.options != state.options) {
++ priv->old_state = state;
++ phy_print_status(phydev);
++ }
++
++ /* We must interrogate MC at all times, because we don't know
++ * when and whether a potential DPNI may have read the link state.
++ */
++ err = dpmac_set_link_state(priv->mc_dev->mc_io, 0,
++ priv->mc_dev->mc_handle, &state);
++ if (unlikely(err))
++ dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err);
++}
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++static netdev_tx_t dpaa2_mac_drop_frame(struct sk_buff *skb,
++ struct net_device *dev)
++{
++ /* we don't support I/O for now, drop the frame */
++ dev_kfree_skb_any(skb);
++ return NETDEV_TX_OK;
++}
++
++static int dpaa2_mac_open(struct net_device *netdev)
++{
++ /* start PHY state machine */
++ phy_start(netdev->phydev);
++
++ return 0;
++}
++
++static int dpaa2_mac_stop(struct net_device *netdev)
++{
++ if (!netdev->phydev)
++ goto done;
++
++ /* stop PHY state machine */
++ phy_stop(netdev->phydev);
++
++ /* signal link down to firmware */
++ netdev->phydev->link = 0;
++ dpaa2_mac_link_changed(netdev);
++
++done:
++ return 0;
++}
++
++static int dpaa2_mac_get_settings(struct net_device *netdev,
++ struct ethtool_cmd *cmd)
++{
++ return phy_ethtool_gset(netdev->phydev, cmd);
++}
++
++static int dpaa2_mac_set_settings(struct net_device *netdev,
++ struct ethtool_cmd *cmd)
++{
++ return phy_ethtool_sset(netdev->phydev, cmd);
++}
++
++static void dpaa2_mac_get_stats(struct net_device *netdev,
++ struct rtnl_link_stats64 *storage)
++{
++ struct dpaa2_mac_priv *priv = netdev_priv(netdev);
++ u64 tmp;
++ int err;
++
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_EGR_MCAST_FRAME,
++ &storage->tx_packets);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_EGR_BCAST_FRAME, &tmp);
++ if (err)
++ goto error;
++ storage->tx_packets += tmp;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_EGR_UCAST_FRAME, &tmp);
++ if (err)
++ goto error;
++ storage->tx_packets += tmp;
++
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_EGR_UNDERSIZED, &storage->tx_dropped);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_EGR_BYTE, &storage->tx_bytes);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_EGR_ERR_FRAME, &storage->tx_errors);
++ if (err)
++ goto error;
++
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_ING_ALL_FRAME, &storage->rx_packets);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_ING_MCAST_FRAME, &storage->multicast);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_ING_FRAME_DISCARD,
++ &storage->rx_dropped);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_ING_ALIGN_ERR, &storage->rx_errors);
++ if (err)
++ goto error;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_ING_OVERSIZED, &tmp);
++ if (err)
++ goto error;
++ storage->rx_errors += tmp;
++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++ DPMAC_CNT_ING_BYTE, &storage->rx_bytes);
++ if (err)
++ goto error;
++
++ return;
++error:
++ netdev_err(netdev, "dpmac_get_counter err %d\n", err);
++}
++
++static struct {
++ enum dpmac_counter id;
++ char name[ETH_GSTRING_LEN];
++} dpaa2_mac_counters[] = {
++ {DPMAC_CNT_ING_ALL_FRAME, "rx all frames"},
++ {DPMAC_CNT_ING_GOOD_FRAME, "rx frames ok"},
++ {DPMAC_CNT_ING_ERR_FRAME, "rx frame errors"},
++ {DPMAC_CNT_ING_FRAME_DISCARD, "rx frame discards"},
++ {DPMAC_CNT_ING_UCAST_FRAME, "rx u-cast"},
++ {DPMAC_CNT_ING_BCAST_FRAME, "rx b-cast"},
++ {DPMAC_CNT_ING_MCAST_FRAME, "rx m-cast"},
++ {DPMAC_CNT_ING_FRAME_64, "rx 64 bytes"},
++ {DPMAC_CNT_ING_FRAME_127, "rx 65-127 bytes"},
++ {DPMAC_CNT_ING_FRAME_255, "rx 128-255 bytes"},
++ {DPMAC_CNT_ING_FRAME_511, "rx 256-511 bytes"},
++ {DPMAC_CNT_ING_FRAME_1023, "rx 512-1023 bytes"},
++ {DPMAC_CNT_ING_FRAME_1518, "rx 1024-1518 bytes"},
++ {DPMAC_CNT_ING_FRAME_1519_MAX, "rx 1519-max bytes"},
++ {DPMAC_CNT_ING_FRAG, "rx frags"},
++ {DPMAC_CNT_ING_JABBER, "rx jabber"},
++ {DPMAC_CNT_ING_ALIGN_ERR, "rx align errors"},
++ {DPMAC_CNT_ING_OVERSIZED, "rx oversized"},
++ {DPMAC_CNT_ING_VALID_PAUSE_FRAME, "rx pause"},
++ {DPMAC_CNT_ING_BYTE, "rx bytes"},
++ {DPMAC_CNT_ENG_GOOD_FRAME, "tx frames ok"},
++ {DPMAC_CNT_EGR_UCAST_FRAME, "tx u-cast"},
++ {DPMAC_CNT_EGR_MCAST_FRAME, "tx m-cast"},
++ {DPMAC_CNT_EGR_BCAST_FRAME, "tx b-cast"},
++ {DPMAC_CNT_EGR_ERR_FRAME, "tx frame errors"},
++ {DPMAC_CNT_EGR_UNDERSIZED, "tx undersized"},
++ {DPMAC_CNT_EGR_VALID_PAUSE_FRAME, "tx b-pause"},
++ {DPMAC_CNT_EGR_BYTE, "tx bytes"},
++
++};
++
++static void dpaa2_mac_get_strings(struct net_device *netdev,
++ u32 stringset, u8 *data)
++{
++ int i;
++
++ switch (stringset) {
++ case ETH_SS_STATS:
++ for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++)
++ memcpy(data + i * ETH_GSTRING_LEN,
++ dpaa2_mac_counters[i].name,
++ ETH_GSTRING_LEN);
++ break;
++ }
++}
++
++static void dpaa2_mac_get_ethtool_stats(struct net_device *netdev,
++ struct ethtool_stats *stats,
++ u64 *data)
++{
++ struct dpaa2_mac_priv *priv = netdev_priv(netdev);
++ int i;
++ int err;
++
++ for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++) {
++ err = dpmac_get_counter(priv->mc_dev->mc_io,
++ 0,
++ priv->mc_dev->mc_handle,
++ dpaa2_mac_counters[i].id, &data[i]);
++ if (err)
++ netdev_err(netdev, "dpmac_get_counter[%s] err %d\n",
++ dpaa2_mac_counters[i].name, err);
++ }
++}
++
++static int dpaa2_mac_get_sset_count(struct net_device *dev, int sset)
++{
++ switch (sset) {
++ case ETH_SS_STATS:
++ return ARRAY_SIZE(dpaa2_mac_counters);
++ default:
++ return -EOPNOTSUPP;
++ }
++}
++
++static const struct net_device_ops dpaa2_mac_ndo_ops = {
++ .ndo_start_xmit = &dpaa2_mac_drop_frame,
++ .ndo_open = &dpaa2_mac_open,
++ .ndo_stop = &dpaa2_mac_stop,
++ .ndo_get_stats64 = &dpaa2_mac_get_stats,
++};
++
++static const struct ethtool_ops dpaa2_mac_ethtool_ops = {
++ .get_settings = &dpaa2_mac_get_settings,
++ .set_settings = &dpaa2_mac_set_settings,
++ .get_strings = &dpaa2_mac_get_strings,
++ .get_ethtool_stats = &dpaa2_mac_get_ethtool_stats,
++ .get_sset_count = &dpaa2_mac_get_sset_count,
++};
++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++
++static void configure_link(struct dpaa2_mac_priv *priv,
++ struct dpmac_link_cfg *cfg)
++{
++ struct phy_device *phydev = priv->netdev->phydev;
++
++ if (unlikely(!phydev))
++ return;
++
++ phydev->speed = cfg->rate;
++ phydev->duplex = !!(cfg->options & DPMAC_LINK_OPT_HALF_DUPLEX);
++
++ if (cfg->options & DPMAC_LINK_OPT_AUTONEG) {
++ phydev->autoneg = 1;
++ phydev->advertising |= ADVERTISED_Autoneg;
++ } else {
++ phydev->autoneg = 0;
++ phydev->advertising &= ~ADVERTISED_Autoneg;
++ }
++
++ phy_start_aneg(phydev);
++}
++
++static irqreturn_t dpaa2_mac_irq_handler(int irq_num, void *arg)
++{
++ struct device *dev = (struct device *)arg;
++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
++ struct dpaa2_mac_priv *priv = dev_get_drvdata(dev);
++ struct dpmac_link_cfg link_cfg;
++ u32 status;
++ int err;
++
++ err = dpmac_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
++ DPMAC_IRQ_INDEX, &status);
++ if (unlikely(err || !status))
++ return IRQ_NONE;
++
++ /* DPNI-initiated link configuration; 'ifconfig up' also calls this */
++ if (status & DPMAC_IRQ_EVENT_LINK_CFG_REQ) {
++ err = dpmac_get_link_cfg(mc_dev->mc_io, 0, mc_dev->mc_handle,
++ &link_cfg);
++ if (unlikely(err))
++ goto out;
++
++ configure_link(priv, &link_cfg);
++ }
++
++out:
++ dpmac_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
++ DPMAC_IRQ_INDEX, status);
++
++ return IRQ_HANDLED;
++}
++
++static int setup_irqs(struct fsl_mc_device *mc_dev)
++{
++ int err = 0;
++ struct fsl_mc_device_irq *irq;
++
++ err = fsl_mc_allocate_irqs(mc_dev);
++ if (err) {
++ dev_err(&mc_dev->dev, "fsl_mc_allocate_irqs err %d\n", err);
++ return err;
++ }
++
++ irq = mc_dev->irqs[0];
++ err = devm_request_threaded_irq(&mc_dev->dev, irq->msi_desc->irq,
++ NULL, &dpaa2_mac_irq_handler,
++ IRQF_NO_SUSPEND | IRQF_ONESHOT,
++ dev_name(&mc_dev->dev), &mc_dev->dev);
++ if (err) {
++ dev_err(&mc_dev->dev, "devm_request_threaded_irq err %d\n",
++ err);
++ goto free_irq;
++ }
++
++ err = dpmac_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
++ DPMAC_IRQ_INDEX, DPMAC_IRQ_EVENT_LINK_CFG_REQ);
++ if (err) {
++ dev_err(&mc_dev->dev, "dpmac_set_irq_mask err %d\n", err);
++ goto free_irq;
++ }
++ err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
++ DPMAC_IRQ_INDEX, 1);
++ if (err) {
++ dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err);
++ goto free_irq;
++ }
++
++ return 0;
++
++free_irq:
++ fsl_mc_free_irqs(mc_dev);
++
++ return err;
++}
++
++static void teardown_irqs(struct fsl_mc_device *mc_dev)
++{
++ int err;
++
++ err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
++ DPMAC_IRQ_INDEX, 0);
++ if (err)
++ dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err);
++
++ fsl_mc_free_irqs(mc_dev);
++}
++
++static struct device_node *find_dpmac_node(struct device *dev, u16 dpmac_id)
++{
++ struct device_node *dpmacs, *dpmac = NULL;
++ struct device_node *mc_node = dev->of_node;
++ u32 id;
++ int err;
++
++ dpmacs = of_find_node_by_name(mc_node, "dpmacs");
++ if (!dpmacs) {
++ dev_err(dev, "No dpmacs subnode in device-tree\n");
++ return NULL;
++ }
++
++ while ((dpmac = of_get_next_child(dpmacs, dpmac))) {
++ err = of_property_read_u32(dpmac, "reg", &id);
++ if (err)
++ continue;
++ if (id == dpmac_id)
++ return dpmac;
++ }
++
++ return NULL;
++}
++
++static int dpaa2_mac_probe(struct fsl_mc_device *mc_dev)
++{
++ struct device *dev;
++ struct dpaa2_mac_priv *priv = NULL;
++ struct device_node *phy_node, *dpmac_node;
++ struct net_device *netdev;
++ phy_interface_t if_mode;
++ int err = 0;
++
++ dev = &mc_dev->dev;
++
++ /* prepare a net_dev structure to make the phy lib API happy */
++ netdev = alloc_etherdev(sizeof(*priv));
++ if (!netdev) {
++ dev_err(dev, "alloc_etherdev error\n");
++ err = -ENOMEM;
++ goto err_exit;
++ }
++ priv = netdev_priv(netdev);
++ priv->mc_dev = mc_dev;
++ priv->netdev = netdev;
++
++ SET_NETDEV_DEV(netdev, dev);
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++ snprintf(netdev->name, IFNAMSIZ, "mac%d", mc_dev->obj_desc.id);
++#endif
++
++ dev_set_drvdata(dev, priv);
++
++ err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
++ if (err || !mc_dev->mc_io) {
++ dev_err(dev, "fsl_mc_portal_allocate error: %d\n", err);
++ err = -ENODEV;
++ goto err_free_netdev;
++ }
++
++ err = dpmac_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
++ &mc_dev->mc_handle);
++ if (err || !mc_dev->mc_handle) {
++ dev_err(dev, "dpmac_open error: %d\n", err);
++ err = -ENODEV;
++ goto err_free_mcp;
++ }
++
++ err = dpmac_get_attributes(mc_dev->mc_io, 0,
++ mc_dev->mc_handle, &priv->attr);
++ if (err) {
++ dev_err(dev, "dpmac_get_attributes err %d\n", err);
++ err = -EINVAL;
++ goto err_close;
++ }
++
++ /* Look up the DPMAC node in the device-tree. */
++ dpmac_node = find_dpmac_node(dev, priv->attr.id);
++ if (!dpmac_node) {
++ dev_err(dev, "No dpmac@%d subnode found.\n", priv->attr.id);
++ err = -ENODEV;
++ goto err_close;
++ }
++
++ err = setup_irqs(mc_dev);
++ if (err) {
++ err = -EFAULT;
++ goto err_close;
++ }
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++ /* OPTIONAL, register netdev just to make it visible to the user */
++ netdev->netdev_ops = &dpaa2_mac_ndo_ops;
++ netdev->ethtool_ops = &dpaa2_mac_ethtool_ops;
++
++ /* phy starts up enabled so netdev should be up too */
++ netdev->flags |= IFF_UP;
++
++ err = register_netdev(priv->netdev);
++ if (err < 0) {
++ dev_err(dev, "register_netdev error %d\n", err);
++ err = -ENODEV;
++ goto err_free_irq;
++ }
++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++
++ /* probe the PHY as a fixed-link if the link type declared in DPC
++ * explicitly mandates this
++ */
++ if (priv->attr.link_type == DPMAC_LINK_TYPE_FIXED)
++ goto probe_fixed_link;
++
++ if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) {
++ if_mode = dpaa2_mac_iface_mode[priv->attr.eth_if];
++ dev_dbg(dev, "\tusing if mode %s for eth_if %d\n",
++ phy_modes(if_mode), priv->attr.eth_if);
++ } else {
++ dev_warn(dev, "Unexpected interface mode %d, will probe as fixed link\n",
++ priv->attr.eth_if);
++ goto probe_fixed_link;
++ }
++
++ /* try to connect to the PHY */
++ phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
++ if (!phy_node) {
++ if (!phy_node) {
++ dev_err(dev, "dpmac node has no phy-handle property\n");
++ err = -ENODEV;
++ goto err_no_phy;
++ }
++ }
++ netdev->phydev = of_phy_connect(netdev, phy_node,
++ &dpaa2_mac_link_changed, 0, if_mode);
++ if (!netdev->phydev) {
++ /* No need for dev_err(); the kernel's loud enough as it is. */
++ dev_dbg(dev, "Can't of_phy_connect() now.\n");
++ /* We might be waiting for the MDIO MUX to probe, so defer
++ * our own probing.
++ */
++ err = -EPROBE_DEFER;
++ goto err_defer;
++ }
++ dev_info(dev, "Connected to %s PHY.\n", phy_modes(if_mode));
++
++probe_fixed_link:
++ if (!netdev->phydev) {
++ struct fixed_phy_status status = {
++ .link = 1,
++ /* fixed-phys don't support 10Gbps speed for now */
++ .speed = 1000,
++ .duplex = 1,
++ };
++
++ /* try to register a fixed link phy */
++ netdev->phydev = fixed_phy_register(PHY_POLL, &status, NULL);
++ if (!netdev->phydev || IS_ERR(netdev->phydev)) {
++ dev_err(dev, "error trying to register fixed PHY\n");
++ /* So we don't crash unregister_netdev() later on */
++ netdev->phydev = NULL;
++ err = -EFAULT;
++ goto err_no_phy;
++ }
++ dev_info(dev, "Registered fixed PHY.\n");
++ }
++
++ /* start PHY state machine */
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++ dpaa2_mac_open(netdev);
++#else /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++ phy_start(netdev->phydev);
++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++ return 0;
++
++err_defer:
++err_no_phy:
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++ unregister_netdev(netdev);
++err_free_irq:
++#endif
++ teardown_irqs(mc_dev);
++err_close:
++ dpmac_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
++err_free_mcp:
++ fsl_mc_portal_free(mc_dev->mc_io);
++err_free_netdev:
++ free_netdev(netdev);
++err_exit:
++ return err;
++}
++
++static int dpaa2_mac_remove(struct fsl_mc_device *mc_dev)
++{
++ struct device *dev = &mc_dev->dev;
++ struct dpaa2_mac_priv *priv = dev_get_drvdata(dev);
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++ unregister_netdev(priv->netdev);
++#endif
++ teardown_irqs(priv->mc_dev);
++ dpmac_close(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle);
++ fsl_mc_portal_free(priv->mc_dev->mc_io);
++ free_netdev(priv->netdev);
++
++ dev_set_drvdata(dev, NULL);
++ kfree(priv);
++
++ return 0;
++}
++
++static const struct fsl_mc_device_id dpaa2_mac_match_id_table[] = {
++ {
++ .vendor = FSL_MC_VENDOR_FREESCALE,
++ .obj_type = "dpmac",
++ },
++ { .vendor = 0x0 }
++};
++MODULE_DEVICE_TABLE(fslmc, dpaa2_mac_match_id_table);
++
++static struct fsl_mc_driver dpaa2_mac_drv = {
++ .driver = {
++ .name = KBUILD_MODNAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = dpaa2_mac_probe,
++ .remove = dpaa2_mac_remove,
++ .match_id_table = dpaa2_mac_match_id_table,
++};
++
++module_fsl_mc_driver(dpaa2_mac_drv);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("DPAA2 PHY proxy interface driver");