Commit a17aafa3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bcmgenet-flow-control'

Florian Fainelli says:

====================
net: bcmgenet: support for flow control

This patch series adds support for flow control to the GENET driver, the
first 2 patches remove superfluous code, the 3rd one does re-organize
code a little bit and the 4th one ads the support for flow control
proper.
====================
parents 13807ded 2d8bdf52
Loading
Loading
Loading
Loading
+51 −5
Original line number Diff line number Diff line
@@ -935,6 +935,48 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
	return 0;
}

static void bcmgenet_get_pauseparam(struct net_device *dev,
				    struct ethtool_pauseparam *epause)
{
	struct bcmgenet_priv *priv;
	u32 umac_cmd;

	priv = netdev_priv(dev);

	epause->autoneg = priv->autoneg_pause;

	if (netif_carrier_ok(dev)) {
		/* report active state when link is up */
		umac_cmd = bcmgenet_umac_readl(priv, UMAC_CMD);
		epause->tx_pause = !(umac_cmd & CMD_TX_PAUSE_IGNORE);
		epause->rx_pause = !(umac_cmd & CMD_RX_PAUSE_IGNORE);
	} else {
		/* otherwise report stored settings */
		epause->tx_pause = priv->tx_pause;
		epause->rx_pause = priv->rx_pause;
	}
}

static int bcmgenet_set_pauseparam(struct net_device *dev,
				   struct ethtool_pauseparam *epause)
{
	struct bcmgenet_priv *priv = netdev_priv(dev);

	if (!dev->phydev)
		return -ENODEV;

	if (!phy_validate_pause(dev->phydev, epause))
		return -EINVAL;

	priv->autoneg_pause = !!epause->autoneg;
	priv->tx_pause = !!epause->tx_pause;
	priv->rx_pause = !!epause->rx_pause;

	bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);

	return 0;
}

/* standard ethtool support functions. */
enum bcmgenet_stat_type {
	BCMGENET_STAT_NETDEV = -1,
@@ -1587,6 +1629,8 @@ static const struct ethtool_ops bcmgenet_ethtool_ops = {
	.get_ts_info		= ethtool_op_get_ts_info,
	.get_rxnfc		= bcmgenet_get_rxnfc,
	.set_rxnfc		= bcmgenet_set_rxnfc,
	.get_pauseparam		= bcmgenet_get_pauseparam,
	.set_pauseparam		= bcmgenet_set_pauseparam,
};

/* Power down the unimac, based on mode. */
@@ -3364,6 +3408,8 @@ static int bcmgenet_open(struct net_device *dev)
		goto err_irq1;
	}

	bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);

	bcmgenet_netif_start(dev);

	netif_tx_start_all_queues(dev);
@@ -3408,11 +3454,6 @@ static void bcmgenet_netif_stop(struct net_device *dev)
	 */
	cancel_work_sync(&priv->bcmgenet_irq_work);

	priv->old_link = -1;
	priv->old_speed = -1;
	priv->old_duplex = -1;
	priv->old_pause = -1;

	/* tx reclaim */
	bcmgenet_tx_reclaim_all(dev);
	bcmgenet_fini_dma(priv);
@@ -3950,6 +3991,11 @@ static int bcmgenet_probe(struct platform_device *pdev)

	spin_lock_init(&priv->lock);

	/* Set default pause parameters */
	priv->autoneg_pause = 1;
	priv->tx_pause = 1;
	priv->rx_pause = 1;

	SET_NETDEV_DEV(dev, &pdev->dev);
	dev_set_drvdata(&pdev->dev, dev);
	dev->watchdog_timeo = 2 * HZ;
+4 −4
Original line number Diff line number Diff line
@@ -594,6 +594,9 @@ struct bcmgenet_priv {

	/* other misc variables */
	struct bcmgenet_hw_params *hw_params;
	unsigned autoneg_pause:1;
	unsigned tx_pause:1;
	unsigned rx_pause:1;

	/* MDIO bus variables */
	wait_queue_head_t wq;
@@ -606,10 +609,6 @@ struct bcmgenet_priv {
	bool clk_eee_enabled;

	/* PHY device variables */
	int old_link;
	int old_speed;
	int old_duplex;
	int old_pause;
	phy_interface_t phy_interface;
	int phy_addr;
	int ext_phy;
@@ -690,6 +689,7 @@ int bcmgenet_mii_init(struct net_device *dev);
int bcmgenet_mii_config(struct net_device *dev, bool init);
int bcmgenet_mii_probe(struct net_device *dev);
void bcmgenet_mii_exit(struct net_device *dev);
void bcmgenet_phy_pause_set(struct net_device *dev, bool rx, bool tx);
void bcmgenet_phy_power_set(struct net_device *dev, bool enable);
void bcmgenet_mii_setup(struct net_device *dev);

+75 −80
Original line number Diff line number Diff line
@@ -25,41 +25,11 @@

#include "bcmgenet.h"

/* setup netdev link state when PHY link status change and
 * update UMAC and RGMII block when link up
 */
void bcmgenet_mii_setup(struct net_device *dev)
static void bcmgenet_mac_config(struct net_device *dev)
{
	struct bcmgenet_priv *priv = netdev_priv(dev);
	struct phy_device *phydev = dev->phydev;
	u32 reg, cmd_bits = 0;
	bool status_changed = false;

	if (priv->old_link != phydev->link) {
		status_changed = true;
		priv->old_link = phydev->link;
	}

	if (phydev->link) {
		/* check speed/duplex/pause changes */
		if (priv->old_speed != phydev->speed) {
			status_changed = true;
			priv->old_speed = phydev->speed;
		}

		if (priv->old_duplex != phydev->duplex) {
			status_changed = true;
			priv->old_duplex = phydev->duplex;
		}

		if (priv->old_pause != phydev->pause) {
			status_changed = true;
			priv->old_pause = phydev->pause;
		}

		/* done if nothing has changed */
		if (!status_changed)
			return;

	/* speed */
	if (phydev->speed == SPEED_1000)
@@ -71,15 +41,31 @@ void bcmgenet_mii_setup(struct net_device *dev)
	cmd_bits <<= CMD_SPEED_SHIFT;

	/* duplex */
		if (phydev->duplex != DUPLEX_FULL)
			cmd_bits |= CMD_HD_EN;
	if (phydev->duplex != DUPLEX_FULL) {
		cmd_bits |= CMD_HD_EN |
			CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
	} else {
		/* pause capability defaults to Symmetric */
		if (priv->autoneg_pause) {
			bool tx_pause = 0, rx_pause = 0;

		/* pause capability */
		if (!phydev->pause)
			cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
			if (phydev->autoneg)
				phy_get_pause(phydev, &tx_pause, &rx_pause);

		/*
		 * Program UMAC and RGMII block based on established
			if (!tx_pause)
				cmd_bits |= CMD_TX_PAUSE_IGNORE;
			if (!rx_pause)
				cmd_bits |= CMD_RX_PAUSE_IGNORE;
		}

		/* Manual override */
		if (!priv->rx_pause)
			cmd_bits |= CMD_RX_PAUSE_IGNORE;
		if (!priv->tx_pause)
			cmd_bits |= CMD_TX_PAUSE_IGNORE;
	}

	/* Program UMAC and RGMII block based on established
	 * link speed, duplex, and pause. The speed set in
	 * umac->cmd tell RGMII block which clock to use for
	 * transmit -- 25MHz(100Mbps) or 125MHz(1Gbps).
@@ -102,15 +88,17 @@ void bcmgenet_mii_setup(struct net_device *dev)
		reg |= CMD_TX_EN | CMD_RX_EN;
	}
	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
	} else {
		/* done if nothing has changed */
		if (!status_changed)
			return;

		/* needed for MoCA fixed PHY to reflect correct link status */
		netif_carrier_off(dev);
}

/* setup netdev link state when PHY link status change and
 * update UMAC and RGMII block when link up
 */
void bcmgenet_mii_setup(struct net_device *dev)
{
	struct phy_device *phydev = dev->phydev;

	if (phydev->link)
		bcmgenet_mac_config(dev);
	phy_print_status(phydev);
}

@@ -130,6 +118,21 @@ static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
	return 0;
}

void bcmgenet_phy_pause_set(struct net_device *dev, bool rx, bool tx)
{
	struct phy_device *phydev = dev->phydev;

	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising, rx);
	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising,
			 rx | tx);
	phy_start_aneg(phydev);

	mutex_lock(&phydev->lock);
	if (phydev->link)
		bcmgenet_mac_config(dev);
	mutex_unlock(&phydev->lock);
}

void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
{
	struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -297,12 +300,6 @@ int bcmgenet_mii_probe(struct net_device *dev)
	if (priv->internal_phy)
		phy_flags = priv->gphy_rev;

	/* Initialize link state variables that bcmgenet_mii_setup() uses */
	priv->old_link = -1;
	priv->old_speed = -1;
	priv->old_duplex = -1;
	priv->old_pause = -1;

	/* This is an ugly quirk but we have not been correctly interpreting
	 * the phy_interface values and we have done that across different
	 * drivers, so at least we are consistent in our mistakes.
@@ -386,8 +383,6 @@ int bcmgenet_mii_probe(struct net_device *dev)
		return ret;
	}

	linkmode_copy(phydev->advertising, phydev->supported);

	/* The internal PHY has its link interrupts routed to the
	 * Ethernet MAC ISRs. On GENETv5 there is a hardware issue
	 * that prevents the signaling of link UP interrupts when