lkml.org 
[lkml]   [2017]   [Sep]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH net-next] net: mvpp2: phylink support
    Date
    Convert the PPv2 driver to use phylink, which models the MAC to PHY
    link. The phylink support is made such a way the GoP link IRQ can still
    be used: the two modes are incompatible and the GoP link IRQ will be
    used if no PHY is described in the device tree. This is the same
    behaviour as before.

    Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
    ---
    drivers/net/ethernet/marvell/Kconfig | 1 +
    drivers/net/ethernet/marvell/mvpp2.c | 502 +++++++++++++++++++++--------------
    2 files changed, 303 insertions(+), 200 deletions(-)

    diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
    index da6fb825afea..991138b8dfba 100644
    --- a/drivers/net/ethernet/marvell/Kconfig
    +++ b/drivers/net/ethernet/marvell/Kconfig
    @@ -86,6 +86,7 @@ config MVPP2
    depends on ARCH_MVEBU || COMPILE_TEST
    depends on HAS_DMA
    select MVMDIO
    + select PHYLINK
    ---help---
    This driver supports the network interface units in the
    Marvell ARMADA 375, 7K and 8K SoCs.
    diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
    index 8041d692db3c..5fb7e76ee128 100644
    --- a/drivers/net/ethernet/marvell/mvpp2.c
    +++ b/drivers/net/ethernet/marvell/mvpp2.c
    @@ -28,6 +28,7 @@
    #include <linux/of_address.h>
    #include <linux/of_device.h>
    #include <linux/phy.h>
    +#include <linux/phylink.h>
    #include <linux/phy/phy.h>
    #include <linux/clk.h>
    #include <linux/hrtimer.h>
    @@ -341,6 +342,7 @@
    #define MVPP2_GMAC_FORCE_LINK_PASS BIT(1)
    #define MVPP2_GMAC_IN_BAND_AUTONEG BIT(2)
    #define MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS BIT(3)
    +#define MVPP2_GMAC_IN_BAND_RESTART_AN BIT(4)
    #define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
    #define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
    #define MVPP2_GMAC_AN_SPEED_EN BIT(7)
    @@ -350,6 +352,12 @@
    #define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
    #define MVPP2_GMAC_STATUS0 0x10
    #define MVPP2_GMAC_STATUS0_LINK_UP BIT(0)
    +#define MVPP2_GMAC_STATUS0_GMII_SPEED BIT(1)
    +#define MVPP2_GMAC_STATUS0_MII_SPEED BIT(2)
    +#define MVPP2_GMAC_STATUS0_FULL_DUPLEX BIT(3)
    +#define MVPP2_GMAC_STATUS0_RX_PAUSE BIT(6)
    +#define MVPP2_GMAC_STATUS0_TX_PAUSE BIT(7)
    +#define MVPP2_GMAC_STATUS0_AN_COMPLETE BIT(11)
    #define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
    #define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6
    #define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
    @@ -878,12 +886,11 @@ struct mvpp2_port {
    u16 rx_ring_size;
    struct mvpp2_pcpu_stats __percpu *stats;

    + struct device_node *of_node;
    +
    phy_interface_t phy_interface;
    - struct device_node *phy_node;
    + struct phylink *phylink;
    struct phy *comphy;
    - unsigned int link;
    - unsigned int duplex;
    - unsigned int speed;

    struct mvpp2_bm_pool *pool_long;
    struct mvpp2_bm_pool *pool_short;
    @@ -4716,13 +4723,14 @@ static void mvpp2_port_periodic_xon_disable(struct mvpp2_port *port)
    }

    /* Configure loopback port */
    -static void mvpp2_port_loopback_set(struct mvpp2_port *port)
    +static void mvpp2_port_loopback_set(struct mvpp2_port *port,
    + const struct phylink_link_state *state)
    {
    u32 val;

    val = readl(port->base + MVPP2_GMAC_CTRL_1_REG);

    - if (port->speed == 1000)
    + if (state->speed == 1000)
    val |= MVPP2_GMAC_GMII_LB_EN_MASK;
    else
    val &= ~MVPP2_GMAC_GMII_LB_EN_MASK;
    @@ -4778,10 +4786,6 @@ static void mvpp2_defaults_set(struct mvpp2_port *port)
    int tx_port_num, val, queue, ptxq, lrxq;

    if (port->priv->hw_version == MVPP21) {
    - /* Configure port to loopback if needed */
    - if (port->flags & MVPP2_F_LOOPBACK)
    - mvpp2_port_loopback_set(port);
    -
    /* Update TX FIFO MIN Threshold */
    val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
    val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
    @@ -5860,111 +5864,6 @@ static irqreturn_t mvpp2_link_status_isr(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    -static void mvpp2_gmac_set_autoneg(struct mvpp2_port *port,
    - struct phy_device *phydev)
    -{
    - u32 val;
    -
    - if (port->phy_interface != PHY_INTERFACE_MODE_RGMII &&
    - port->phy_interface != PHY_INTERFACE_MODE_RGMII_ID &&
    - port->phy_interface != PHY_INTERFACE_MODE_RGMII_RXID &&
    - port->phy_interface != PHY_INTERFACE_MODE_RGMII_TXID &&
    - port->phy_interface != PHY_INTERFACE_MODE_SGMII)
    - return;
    -
    - val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    - val &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
    - MVPP2_GMAC_CONFIG_GMII_SPEED |
    - MVPP2_GMAC_CONFIG_FULL_DUPLEX |
    - MVPP2_GMAC_AN_SPEED_EN |
    - MVPP2_GMAC_AN_DUPLEX_EN);
    -
    - if (phydev->duplex)
    - val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
    -
    - if (phydev->speed == SPEED_1000)
    - val |= MVPP2_GMAC_CONFIG_GMII_SPEED;
    - else if (phydev->speed == SPEED_100)
    - val |= MVPP2_GMAC_CONFIG_MII_SPEED;
    -
    - writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    -}
    -
    -/* Adjust link */
    -static void mvpp2_link_event(struct net_device *dev)
    -{
    - struct mvpp2_port *port = netdev_priv(dev);
    - struct phy_device *phydev = dev->phydev;
    - bool link_reconfigured = false;
    - u32 val;
    -
    - if (phydev->link) {
    - if (port->phy_interface != phydev->interface && port->comphy) {
    - /* disable current port for reconfiguration */
    - mvpp2_interrupts_disable(port);
    - netif_carrier_off(port->dev);
    - mvpp2_port_disable(port);
    - phy_power_off(port->comphy);
    -
    - /* comphy reconfiguration */
    - port->phy_interface = phydev->interface;
    - mvpp22_comphy_init(port);
    -
    - /* gop/mac reconfiguration */
    - mvpp22_gop_init(port);
    - mvpp2_port_mii_set(port);
    -
    - link_reconfigured = true;
    - }
    -
    - if ((port->speed != phydev->speed) ||
    - (port->duplex != phydev->duplex)) {
    - mvpp2_gmac_set_autoneg(port, phydev);
    -
    - port->duplex = phydev->duplex;
    - port->speed = phydev->speed;
    - }
    - }
    -
    - if (phydev->link != port->link || link_reconfigured) {
    - port->link = phydev->link;
    -
    - if (phydev->link) {
    - if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
    - port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
    - port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
    - port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID ||
    - port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
    - val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    - val |= (MVPP2_GMAC_FORCE_LINK_PASS |
    - MVPP2_GMAC_FORCE_LINK_DOWN);
    - writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    - }
    -
    - mvpp2_interrupts_enable(port);
    - mvpp2_port_enable(port);
    -
    - mvpp2_egress_enable(port);
    - mvpp2_ingress_enable(port);
    - netif_carrier_on(dev);
    - netif_tx_wake_all_queues(dev);
    - } else {
    - port->duplex = -1;
    - port->speed = 0;
    -
    - netif_tx_stop_all_queues(dev);
    - netif_carrier_off(dev);
    - mvpp2_ingress_disable(port);
    - mvpp2_egress_disable(port);
    -
    - mvpp2_port_disable(port);
    - mvpp2_interrupts_disable(port);
    - }
    -
    - phy_print_status(phydev);
    - }
    -}
    -
    static void mvpp2_timer_set(struct mvpp2_port_pcpu *port_pcpu)
    {
    ktime_t interval;
    @@ -6582,7 +6481,6 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
    /* Set hw internals when starting port */
    static void mvpp2_start_dev(struct mvpp2_port *port)
    {
    - struct net_device *ndev = port->dev;
    int i;

    if (port->gop_id == 0 &&
    @@ -6607,15 +6505,14 @@ static void mvpp2_start_dev(struct mvpp2_port *port)

    mvpp2_port_mii_set(port);
    mvpp2_port_enable(port);
    - if (ndev->phydev)
    - phy_start(ndev->phydev);
    + if (port->phylink)
    + phylink_start(port->phylink);
    netif_tx_start_all_queues(port->dev);
    }

    /* Set hw internals when stopping port */
    static void mvpp2_stop_dev(struct mvpp2_port *port)
    {
    - struct net_device *ndev = port->dev;
    int i;

    /* Stop new packets from arriving to RXQs */
    @@ -6634,8 +6531,8 @@ static void mvpp2_stop_dev(struct mvpp2_port *port)

    mvpp2_egress_disable(port);
    mvpp2_port_disable(port);
    - if (ndev->phydev)
    - phy_stop(ndev->phydev);
    + if (port->phylink)
    + phylink_stop(port->phylink);
    phy_power_off(port->comphy);
    }

    @@ -6688,40 +6585,6 @@ static void mvpp21_get_mac_address(struct mvpp2_port *port, unsigned char *addr)
    addr[5] = (mac_addr_l >> MVPP2_GMAC_SA_LOW_OFFS) & 0xFF;
    }

    -static int mvpp2_phy_connect(struct mvpp2_port *port)
    -{
    - struct phy_device *phy_dev;
    -
    - /* No PHY is attached */
    - if (!port->phy_node)
    - return 0;
    -
    - phy_dev = of_phy_connect(port->dev, port->phy_node, mvpp2_link_event, 0,
    - port->phy_interface);
    - if (!phy_dev) {
    - netdev_err(port->dev, "cannot connect to phy\n");
    - return -ENODEV;
    - }
    - phy_dev->supported &= PHY_GBIT_FEATURES;
    - phy_dev->advertising = phy_dev->supported;
    -
    - port->link = 0;
    - port->duplex = 0;
    - port->speed = 0;
    -
    - return 0;
    -}
    -
    -static void mvpp2_phy_disconnect(struct mvpp2_port *port)
    -{
    - struct net_device *ndev = port->dev;
    -
    - if (!ndev->phydev)
    - return;
    -
    - phy_disconnect(ndev->phydev);
    -}
    -
    static int mvpp2_irqs_init(struct mvpp2_port *port)
    {
    int err, i;
    @@ -6765,7 +6628,6 @@ static void mvpp2_irqs_deinit(struct mvpp2_port *port)
    static int mvpp2_open(struct net_device *dev)
    {
    struct mvpp2_port *port = netdev_priv(dev);
    - struct mvpp2 *priv = port->priv;
    unsigned char mac_bcast[ETH_ALEN] = {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
    int err;
    @@ -6811,7 +6673,16 @@ static int mvpp2_open(struct net_device *dev)
    goto err_cleanup_txqs;
    }

    - if (priv->hw_version == MVPP22 && !port->phy_node && port->link_irq) {
    + /* In default link is down */
    + netif_carrier_off(port->dev);
    +
    + if (port->phylink) {
    + err = phylink_of_phy_connect(port->phylink, port->of_node);
    + if (err) {
    + netdev_err(port->dev, "could not attach PHY (%d)\n", err);
    + goto err_free_irq;
    + }
    + } else if (port->link_irq) {
    err = request_irq(port->link_irq, mvpp2_link_status_isr, 0,
    dev->name, port);
    if (err) {
    @@ -6821,15 +6692,11 @@ static int mvpp2_open(struct net_device *dev)
    }

    mvpp22_gop_setup_irq(port);
    + } else {
    + netdev_err(dev, "cannot use phylink or GoP link IRQ\n");
    + goto err_free_irq;
    }

    - /* In default link is down */
    - netif_carrier_off(port->dev);
    -
    - err = mvpp2_phy_connect(port);
    - if (err < 0)
    - goto err_free_link_irq;
    -
    /* Unmask interrupts on all CPUs */
    on_each_cpu(mvpp2_interrupts_unmask, port, 1);
    mvpp2_shared_interrupt_mask_unmask(port, false);
    @@ -6838,9 +6705,6 @@ static int mvpp2_open(struct net_device *dev)

    return 0;

    -err_free_link_irq:
    - if (priv->hw_version == MVPP22 && !port->phy_node && port->link_irq)
    - free_irq(port->link_irq, port);
    err_free_irq:
    mvpp2_irqs_deinit(port);
    err_cleanup_txqs:
    @@ -6854,17 +6718,17 @@ static int mvpp2_stop(struct net_device *dev)
    {
    struct mvpp2_port *port = netdev_priv(dev);
    struct mvpp2_port_pcpu *port_pcpu;
    - struct mvpp2 *priv = port->priv;
    int cpu;

    mvpp2_stop_dev(port);
    - mvpp2_phy_disconnect(port);
    + if (port->phylink)
    + phylink_disconnect_phy(port->phylink);

    /* Mask interrupts on all CPUs */
    on_each_cpu(mvpp2_interrupts_mask, port, 1);
    mvpp2_shared_interrupt_mask_unmask(port, true);

    - if (priv->hw_version == MVPP22 && !port->phy_node && port->link_irq)
    + if (port->link_irq)
    free_irq(port->link_irq, port);

    mvpp2_irqs_deinit(port);
    @@ -7029,20 +6893,26 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)

    static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
    {
    - int ret;
    + struct mvpp2_port *port = netdev_priv(dev);

    - if (!dev->phydev)
    + if (!port->phylink)
    return -ENOTSUPP;

    - ret = phy_mii_ioctl(dev->phydev, ifr, cmd);
    - if (!ret)
    - mvpp2_link_event(dev);
    -
    - return ret;
    + return phylink_mii_ioctl(port->phylink, ifr, cmd);
    }

    /* Ethtool methods */

    +static int mvpp2_ethtool_nway_reset(struct net_device *dev)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    +
    + if (!port->phylink)
    + return -ENOTSUPP;
    +
    + return phylink_ethtool_nway_reset(port->phylink);
    +}
    +
    /* Set interrupt coalescing for ethtools */
    static int mvpp2_ethtool_set_coalesce(struct net_device *dev,
    struct ethtool_coalesce *c)
    @@ -7170,6 +7040,50 @@ static int mvpp2_ethtool_set_ringparam(struct net_device *dev,
    return err;
    }

    +static void mvpp2_ethtool_get_pause_param(struct net_device *dev,
    + struct ethtool_pauseparam *pause)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    +
    + if (!port->phylink)
    + return;
    +
    + phylink_ethtool_get_pauseparam(port->phylink, pause);
    +}
    +
    +static int mvpp2_ethtool_set_pause_param(struct net_device *dev,
    + struct ethtool_pauseparam *pause)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    +
    + if (!port->phylink)
    + return -ENOTSUPP;
    +
    + return phylink_ethtool_set_pauseparam(port->phylink, pause);
    +}
    +
    +static int mvpp2_ethtool_get_link_ksettings(struct net_device *dev,
    + struct ethtool_link_ksettings *cmd)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    +
    + if (!port->phylink)
    + return -ENOTSUPP;
    +
    + return phylink_ethtool_ksettings_get(port->phylink, cmd);
    +}
    +
    +static int mvpp2_ethtool_set_link_ksettings(struct net_device *dev,
    + const struct ethtool_link_ksettings *cmd)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    +
    + if (!port->phylink)
    + return -ENOTSUPP;
    +
    + return phylink_ethtool_ksettings_set(port->phylink, cmd);
    +}
    +
    /* Device ops */

    static const struct net_device_ops mvpp2_netdev_ops = {
    @@ -7184,15 +7098,17 @@ static const struct net_device_ops mvpp2_netdev_ops = {
    };

    static const struct ethtool_ops mvpp2_eth_tool_ops = {
    - .nway_reset = phy_ethtool_nway_reset,
    + .nway_reset = mvpp2_ethtool_nway_reset,
    .get_link = ethtool_op_get_link,
    .set_coalesce = mvpp2_ethtool_set_coalesce,
    .get_coalesce = mvpp2_ethtool_get_coalesce,
    .get_drvinfo = mvpp2_ethtool_get_drvinfo,
    .get_ringparam = mvpp2_ethtool_get_ringparam,
    .set_ringparam = mvpp2_ethtool_set_ringparam,
    - .get_link_ksettings = phy_ethtool_get_link_ksettings,
    - .set_link_ksettings = phy_ethtool_set_link_ksettings,
    + .get_pauseparam = mvpp2_ethtool_get_pause_param,
    + .set_pauseparam = mvpp2_ethtool_set_pause_param,
    + .get_link_ksettings = mvpp2_ethtool_get_link_ksettings,
    + .set_link_ksettings = mvpp2_ethtool_set_link_ksettings,
    };

    /* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
    @@ -7492,17 +7408,185 @@ static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
    eth_hw_addr_random(dev);
    }

    +static void mvpp2_phylink_validate(struct net_device *dev,
    + unsigned long *supported,
    + struct phylink_link_state *state)
    +{
    + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
    +
    + phylink_set_port_modes(mask);
    +
    + phylink_set(mask, Autoneg);
    + phylink_set(mask, Pause);
    + phylink_set(mask, Asym_Pause);
    +
    + phylink_set(mask, 10baseT_Half);
    + phylink_set(mask, 10baseT_Full);
    + phylink_set(mask, 100baseT_Half);
    + phylink_set(mask, 100baseT_Full);
    + phylink_set(mask, 1000baseT_Half);
    + phylink_set(mask, 1000baseT_Full);
    + phylink_set(mask, 1000baseX_Full);
    + phylink_set(mask, 10000baseKR_Full);
    +
    + bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
    + bitmap_and(state->advertising, state->advertising, mask,
    + __ETHTOOL_LINK_MODE_MASK_NBITS);
    +}
    +
    +static int mvpp2_phylink_mac_link_state(struct net_device *dev,
    + struct phylink_link_state *state)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    + u32 val;
    +
    + if (!phy_interface_mode_is_rgmii(port->phy_interface) &&
    + port->phy_interface != PHY_INTERFACE_MODE_SGMII)
    + return 0;
    +
    + val = readl(port->base + MVPP2_GMAC_STATUS0);
    +
    + state->an_complete = !!(val & MVPP2_GMAC_STATUS0_AN_COMPLETE);
    + state->link = !!(val & MVPP2_GMAC_STATUS0_LINK_UP);
    + state->duplex = !!(val & MVPP2_GMAC_STATUS0_FULL_DUPLEX);
    +
    + if (val & MVPP2_GMAC_STATUS0_GMII_SPEED)
    + state->speed = SPEED_1000;
    + else
    + state->speed = (val & MVPP2_GMAC_STATUS0_MII_SPEED) ?
    + SPEED_100 : SPEED_10;
    +
    + state->pause = 0;
    + if (val & MVPP2_GMAC_STATUS0_RX_PAUSE)
    + state->pause |= MLO_PAUSE_RX;
    + if (val & MVPP2_GMAC_STATUS0_TX_PAUSE)
    + state->pause |= MLO_PAUSE_TX;
    +
    + return 1;
    +}
    +
    +static void mvpp2_mac_an_restart(struct net_device *dev)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    + u32 val;
    +
    + if (!phy_interface_mode_is_rgmii(port->phy_interface) &&
    + port->phy_interface != PHY_INTERFACE_MODE_SGMII)
    + return;
    +
    + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    + val |= MVPP2_GMAC_IN_BAND_RESTART_AN;
    + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    +}
    +
    +static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
    + const struct phylink_link_state *state)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    + u32 val;
    +
    + /* disable current port for reconfiguration */
    + mvpp2_interrupts_disable(port);
    + netif_carrier_off(port->dev);
    + mvpp2_port_disable(port);
    + phy_power_off(port->comphy);
    +
    + /* comphy reconfiguration */
    + port->phy_interface = state->interface;
    + mvpp22_comphy_init(port);
    +
    + /* gop/mac reconfiguration */
    + mvpp22_gop_init(port);
    + mvpp2_port_mii_set(port);
    +
    + if (!phy_interface_mode_is_rgmii(port->phy_interface) &&
    + port->phy_interface != PHY_INTERFACE_MODE_SGMII)
    + return;
    +
    + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    + val &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
    + MVPP2_GMAC_CONFIG_GMII_SPEED |
    + MVPP2_GMAC_CONFIG_FULL_DUPLEX |
    + MVPP2_GMAC_AN_SPEED_EN |
    + MVPP2_GMAC_AN_DUPLEX_EN);
    +
    + if (state->duplex)
    + val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
    +
    + if (state->speed == SPEED_1000)
    + val |= MVPP2_GMAC_CONFIG_GMII_SPEED;
    + else if (state->speed == SPEED_100)
    + val |= MVPP2_GMAC_CONFIG_MII_SPEED;
    +
    + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    +
    + if (port->priv->hw_version == MVPP21 && port->flags & MVPP2_F_LOOPBACK)
    + mvpp2_port_loopback_set(port, state);
    +}
    +
    +static void mvpp2_mac_link_down(struct net_device *dev, unsigned int mode)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    + u32 val;
    +
    + netif_tx_stop_all_queues(dev);
    + netif_carrier_off(dev);
    + mvpp2_ingress_disable(port);
    + mvpp2_egress_disable(port);
    +
    + mvpp2_port_disable(port);
    + mvpp2_interrupts_disable(port);
    +
    + if (!phylink_autoneg_inband(mode)) {
    + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    + val &= ~MVPP2_GMAC_FORCE_LINK_PASS;
    + val |= MVPP2_GMAC_FORCE_LINK_DOWN;
    + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    + }
    +}
    +
    +static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
    + struct phy_device *phy)
    +{
    + struct mvpp2_port *port = netdev_priv(dev);
    + u32 val;
    +
    + if (!phylink_autoneg_inband(mode)) {
    + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    + val &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
    + val |= MVPP2_GMAC_FORCE_LINK_PASS;
    + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
    + }
    +
    + mvpp2_interrupts_enable(port);
    + mvpp2_port_enable(port);
    +
    + mvpp2_egress_enable(port);
    + mvpp2_ingress_enable(port);
    + netif_carrier_on(dev);
    + netif_tx_wake_all_queues(dev);
    +}
    +
    +static const struct phylink_mac_ops mvpp2_phylink_ops = {
    + .validate = mvpp2_phylink_validate,
    + .mac_link_state = mvpp2_phylink_mac_link_state,
    + .mac_an_restart = mvpp2_mac_an_restart,
    + .mac_config = mvpp2_mac_config,
    + .mac_link_down = mvpp2_mac_link_down,
    + .mac_link_up = mvpp2_mac_link_up,
    +};
    +
    /* Ports initialization */
    static int mvpp2_port_probe(struct platform_device *pdev,
    struct device_node *port_node,
    struct mvpp2 *priv)
    {
    - struct device_node *phy_node;
    struct phy *comphy;
    struct mvpp2_port *port;
    struct mvpp2_port_pcpu *port_pcpu;
    struct net_device *dev;
    struct resource *res;
    + struct phylink *phylink;
    char *mac_from = "";
    unsigned int ntxqs, nrxqs;
    bool has_tx_irqs;
    @@ -7526,7 +7610,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    if (!dev)
    return -ENOMEM;

    - phy_node = of_parse_phandle(port_node, "phy", 0);
    phy_mode = of_get_phy_mode(port_node);
    if (phy_mode < 0) {
    dev_err(&pdev->dev, "incorrect phy mode\n");
    @@ -7565,15 +7648,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    if (err)
    goto err_free_netdev;

    - port->link_irq = of_irq_get_byname(port_node, "link");
    - if (port->link_irq == -EPROBE_DEFER) {
    - err = -EPROBE_DEFER;
    - goto err_deinit_qvecs;
    - }
    - if (port->link_irq <= 0)
    - /* the link irq is optional */
    - port->link_irq = 0;
    -
    if (of_property_read_bool(port_node, "marvell,loopback"))
    port->flags |= MVPP2_F_LOOPBACK;

    @@ -7583,7 +7657,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    else
    port->first_rxq = port->id * priv->max_port_rxqs;

    - port->phy_node = phy_node;
    + port->of_node = port_node;
    port->phy_interface = phy_mode;
    port->comphy = comphy;

    @@ -7592,7 +7666,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    port->base = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(port->base)) {
    err = PTR_ERR(port->base);
    - goto err_free_irq;
    + goto err_deinit_qvecs;
    }
    } else {
    if (of_property_read_u32(port_node, "gop-port-id",
    @@ -7609,7 +7683,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats);
    if (!port->stats) {
    err = -ENOMEM;
    - goto err_free_irq;
    + goto err_deinit_qvecs;
    }

    mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
    @@ -7662,16 +7736,47 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    /* 9676 == 9700 - 20 and rounding to 8 */
    dev->max_mtu = 9676;

    + /* The PHY node is optional. If not present the GoP link IRQ will be
    + * used to handle link updates. Otherwise use phylink.
    + */
    + if (of_find_property(port_node, "phy", NULL)) {
    + phylink = phylink_create(dev, port_node, phy_mode,
    + &mvpp2_phylink_ops);
    + if (IS_ERR(phylink)) {
    + err = PTR_ERR(phylink);
    + goto err_free_port_pcpu;
    + }
    + port->phylink = phylink;
    + port->link_irq = 0;
    + } else {
    + port->phylink = NULL;
    + if (priv->hw_version == MVPP22) {
    + port->link_irq = of_irq_get_byname(port_node, "link");
    + if (port->link_irq == -EPROBE_DEFER) {
    + err = -EPROBE_DEFER;
    + goto err_free_port_pcpu;
    + }
    + if (port->link_irq <= 0)
    + /* the link irq is optional */
    + port->link_irq = 0;
    + }
    + }
    +
    err = register_netdev(dev);
    if (err < 0) {
    dev_err(&pdev->dev, "failed to register netdev\n");
    - goto err_free_port_pcpu;
    + goto err_phylink_irq;
    }
    netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);

    priv->port_list[id] = port;
    return 0;

    +err_phylink_irq:
    + if (port->phylink)
    + phylink_destroy(port->phylink);
    + else if (port->link_irq)
    + irq_dispose_mapping(port->link_irq);
    err_free_port_pcpu:
    free_percpu(port->pcpu);
    err_free_txq_pcpu:
    @@ -7679,13 +7784,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
    free_percpu(port->txqs[i]->pcpu);
    err_free_stats:
    free_percpu(port->stats);
    -err_free_irq:
    - if (port->link_irq)
    - irq_dispose_mapping(port->link_irq);
    err_deinit_qvecs:
    mvpp2_queue_vectors_deinit(port);
    err_free_netdev:
    - of_node_put(phy_node);
    free_netdev(dev);
    return err;
    }
    @@ -7696,7 +7797,8 @@ static void mvpp2_port_remove(struct mvpp2_port *port)
    int i;

    unregister_netdev(port->dev);
    - of_node_put(port->phy_node);
    + if (port->phylink)
    + phylink_destroy(port->phylink);
    free_percpu(port->pcpu);
    free_percpu(port->stats);
    for (i = 0; i < port->ntxqs; i++)
    --
    2.13.5
    \
     
     \ /
      Last update: 2017-09-21 19:33    [W:3.372 / U:0.152 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site