Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ecc061d authored by Peter P Waskiewicz Jr's avatar Peter P Waskiewicz Jr Committed by David S. Miller
Browse files

ixgbe: Update flow control state machine in link setup



The flow control handling is overly complicated and difficult to maintain.
This patch cleans up the flow control handling and makes it much more
explicit.  It also adds 1G flow control autonegotiation, for 1G copper
links, 1G KX links, and 1G fiber links.

Signed-off-by: default avatarPeter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 39482791
Loading
Loading
Loading
Loading
+113 −64
Original line number Diff line number Diff line
@@ -255,104 +255,75 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
}

/**
 *  ixgbe_setup_fc_82598 - Configure flow control settings
 *  ixgbe_fc_enable_82598 - Enable flow control
 *  @hw: pointer to hardware structure
 *  @packetbuf_num: packet buffer number (0-7)
 *
 *  Configures the flow control settings based on SW configuration.  This
 *  function is used for 802.3x flow control configuration only.
 *  Enable flow control according to the current settings.
 **/
static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
{
	u32 frctl_reg;
	s32 ret_val = 0;
	u32 fctrl_reg;
	u32 rmcs_reg;
	u32 reg;

	if (packetbuf_num < 0 || packetbuf_num > 7) {
		hw_dbg(hw, "Invalid packet buffer number [%d], expected range is"
		          " 0-7\n", packetbuf_num);
	}

	frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
	frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
	fctrl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
	fctrl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);

	rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
	rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X);

	/*
	 * 10 gig parts do not have a word in the EEPROM to determine the
	 * default flow control setting, so we explicitly set it to full.
	 */
	if (hw->fc.type == ixgbe_fc_default)
		hw->fc.type = ixgbe_fc_full;

	/*
	 * We want to save off the original Flow Control configuration just in
	 * case we get disconnected and then reconnected into a different hub
	 * or switch with different Flow Control capabilities.
	 */
	hw->fc.original_type = hw->fc.type;

	/*
	 * The possible values of the "flow_control" parameter are:
	 * The possible values of fc.current_mode are:
	 * 0: Flow control is completely disabled
	 * 1: Rx flow control is enabled (we can receive pause frames but not
	 *    send pause frames).
	 * 2: Tx flow control is enabled (we can send pause frames but we do not
	 *    support receiving pause frames)
	 * 1: Rx flow control is enabled (we can receive pause frames,
	 *    but not send pause frames).
	 * 2:  Tx flow control is enabled (we can send pause frames but
	 *     we do not support receiving pause frames).
	 * 3: Both Rx and Tx flow control (symmetric) are enabled.
	 * other: Invalid.
	 */
	switch (hw->fc.type) {
	switch (hw->fc.current_mode) {
	case ixgbe_fc_none:
		/* Flow control completely disabled by software override. */
		break;
	case ixgbe_fc_rx_pause:
		/*
		 * Rx Flow control is enabled,
		 * and Tx Flow control is disabled.
		 * Rx Flow control is enabled and Tx Flow control is
		 * disabled by software override. Since there really
		 * isn't a way to advertise that we are capable of RX
		 * Pause ONLY, we will advertise that we support both
		 * symmetric and asymmetric Rx PAUSE.  Later, we will
		 * disable the adapter's ability to send PAUSE frames.
		 */
		frctl_reg |= IXGBE_FCTRL_RFCE;
		fctrl_reg |= IXGBE_FCTRL_RFCE;
		break;
	case ixgbe_fc_tx_pause:
		/*
		 * Tx Flow control is enabled, and Rx Flow control is disabled,
		 * by a software over-ride.
		 * Tx Flow control is enabled, and Rx Flow control is
		 * disabled by software override.
		 */
		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
		break;
	case ixgbe_fc_full:
		/*
		 * Flow control (both Rx and Tx) is enabled by a software
		 * over-ride.
		 */
		frctl_reg |= IXGBE_FCTRL_RFCE;
		/* Flow control (both Rx and Tx) is enabled by SW override. */
		fctrl_reg |= IXGBE_FCTRL_RFCE;
		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
		break;
	default:
		/* We should never get here.  The value should be 0-3. */
		hw_dbg(hw, "Flow control param set incorrectly\n");
		ret_val = -IXGBE_ERR_CONFIG;
		goto out;
		break;
	}

	/* Enable 802.3x based flow control settings. */
	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg);
	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg);
	IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);

	/*
	 * Check for invalid software configuration, zeros are completely
	 * invalid for all parameters used past this point, and if we enable
	 * flow control with zero water marks, we blast flow control packets.
	 */
	if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
		hw_dbg(hw, "Flow control structure initialized incorrectly\n");
		return IXGBE_ERR_INVALID_LINK_SETTINGS;
	}

	/*
	 * We need to set up the Receive Threshold high and low water
	 * marks as well as (optionally) enabling the transmission of
	 * XON frames.
	 */
	if (hw->fc.type & ixgbe_fc_tx_pause) {
	/* Set up and enable Rx high/low water mark thresholds, enable XON. */
	if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
		if (hw->fc.send_xon) {
			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
			                (hw->fc.low_water | IXGBE_FCRTL_XONE));
@@ -360,14 +331,93 @@ static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
			                hw->fc.low_water);
		}

		IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
		                (hw->fc.high_water)|IXGBE_FCRTH_FCEN);
		                (hw->fc.high_water | IXGBE_FCRTH_FCEN));
	}

	IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time);
	/* Configure pause time (2 TCs per register) */
	reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num));
	if ((packetbuf_num & 1) == 0)
		reg = (reg & 0xFFFF0000) | hw->fc.pause_time;
	else
		reg = (reg & 0x0000FFFF) | (hw->fc.pause_time << 16);
	IXGBE_WRITE_REG(hw, IXGBE_FCTTV(packetbuf_num / 2), reg);

	IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));

	return 0;
out:
	return ret_val;
}

/**
 *  ixgbe_setup_fc_82598 - Configure flow control settings
 *  @hw: pointer to hardware structure
 *  @packetbuf_num: packet buffer number (0-7)
 *
 *  Configures the flow control settings based on SW configuration.  This
 *  function is used for 802.3x flow control configuration only.
 **/
static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
{
	s32 ret_val = 0;
	ixgbe_link_speed speed;
	bool link_up;

	/* Validate the packetbuf configuration */
	if (packetbuf_num < 0 || packetbuf_num > 7) {
		hw_dbg(hw, "Invalid packet buffer number [%d], expected range is"
		          " 0-7\n", packetbuf_num);
		ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
		goto out;
	}

	/*
	 * Validate the water mark configuration.  Zero water marks are invalid
	 * because it causes the controller to just blast out fc packets.
	 */
	if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
		hw_dbg(hw, "Invalid water mark configuration\n");
		ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
		goto out;
	}

	/*
	 * Validate the requested mode.  Strict IEEE mode does not allow
	 * ixgbe_fc_rx_pause because it will cause testing anomalies.
	 */
	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
		hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
		ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
		goto out;
	}

	/*
	 * 10gig parts do not have a word in the EEPROM to determine the
	 * default flow control setting, so we explicitly set it to full.
	 */
	if (hw->fc.requested_mode == ixgbe_fc_default)
		hw->fc.requested_mode = ixgbe_fc_full;

	/*
	 * Save off the requested flow control mode for use later.  Depending
	 * on the link partner's capabilities, we may or may not use this mode.
	 */

	hw->fc.current_mode = hw->fc.requested_mode;

	/* Decide whether to use autoneg or not. */
	hw->mac.ops.check_link(hw, &speed, &link_up, false);
	if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL))
		ret_val = ixgbe_fc_autoneg(hw);

	if (ret_val)
		goto out;

	ret_val = ixgbe_fc_enable_82598(hw, packetbuf_num);

out:
	return ret_val;
}

/**
@@ -414,7 +464,6 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
	 * case we get disconnected and then reconnected into a different hub
	 * or switch with different Flow Control capabilities.
	 */
	hw->fc.original_type = hw->fc.type;
	ixgbe_setup_fc_82598(hw, 0);

	/* Add delay to filter out noises during initial link setup */
+138 −0
Original line number Diff line number Diff line
@@ -1486,6 +1486,144 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw)
	return 0;
}

/**
 *  ixgbe_fc_autoneg - Configure flow control
 *  @hw: pointer to hardware structure
 *
 *  Negotiates flow control capabilities with link partner using autoneg and
 *  applies the results.
 **/
s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw)
{
	s32 ret_val = 0;
	u32 i, reg, pcs_anadv_reg, pcs_lpab_reg;

	reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);

	/*
	 * The possible values of fc.current_mode are:
	 * 0:  Flow control is completely disabled
	 * 1:  Rx flow control is enabled (we can receive pause frames,
	 *     but not send pause frames).
	 * 2:  Tx flow control is enabled (we can send pause frames but
	 *     we do not support receiving pause frames).
	 * 3:  Both Rx and Tx flow control (symmetric) are enabled.
	 * other: Invalid.
	 */
	switch (hw->fc.current_mode) {
	case ixgbe_fc_none:
		/* Flow control completely disabled by software override. */
		reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
		break;
	case ixgbe_fc_rx_pause:
		/*
		 * Rx Flow control is enabled and Tx Flow control is
		 * disabled by software override. Since there really
		 * isn't a way to advertise that we are capable of RX
		 * Pause ONLY, we will advertise that we support both
		 * symmetric and asymmetric Rx PAUSE.  Later, we will
		 * disable the adapter's ability to send PAUSE frames.
		 */
		reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
		break;
	case ixgbe_fc_tx_pause:
		/*
		 * Tx Flow control is enabled, and Rx Flow control is
		 * disabled by software override.
		 */
		reg |= (IXGBE_PCS1GANA_ASM_PAUSE);
		reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE);
		break;
	case ixgbe_fc_full:
		/* Flow control (both Rx and Tx) is enabled by SW override. */
		reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
		break;
	default:
		hw_dbg(hw, "Flow control param set incorrectly\n");
		ret_val = -IXGBE_ERR_CONFIG;
		goto out;
		break;
	}

	IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg);
	reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);

	/* Set PCS register for autoneg */
	/* Enable and restart autoneg */
	reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART;

	/* Disable AN timeout */
	if (hw->fc.strict_ieee)
		reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN;

	hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg);
	IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg);

	/* See if autonegotiation has succeeded */
	hw->mac.autoneg_succeeded = 0;
	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
		msleep(10);
		reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
		if ((reg & (IXGBE_PCS1GLSTA_LINK_OK |
		     IXGBE_PCS1GLSTA_AN_COMPLETE)) ==
		    (IXGBE_PCS1GLSTA_LINK_OK |
		     IXGBE_PCS1GLSTA_AN_COMPLETE)) {
			if (!(reg & IXGBE_PCS1GLSTA_AN_TIMED_OUT))
				hw->mac.autoneg_succeeded = 1;
			break;
		}
	}

	if (!hw->mac.autoneg_succeeded) {
		/* Autoneg failed to achieve a link, so we turn fc off */
		hw->fc.current_mode = ixgbe_fc_none;
		hw_dbg(hw, "Flow Control = NONE.\n");
		goto out;
	}

	/*
	 * Read the AN advertisement and LP ability registers and resolve
	 * local flow control settings accordingly
	 */
	pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
	pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
	if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) &&
		(pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE)) {
		/*
		 * Now we need to check if the user selected Rx ONLY
		 * of pause frames.  In this case, we had to advertise
		 * FULL flow control because we could not advertise RX
		 * ONLY. Hence, we must now check to see if we need to
		 * turn OFF the TRANSMISSION of PAUSE frames.
		 */
		if (hw->fc.requested_mode == ixgbe_fc_full) {
			hw->fc.current_mode = ixgbe_fc_full;
			hw_dbg(hw, "Flow Control = FULL.\n");
		} else {
			hw->fc.current_mode = ixgbe_fc_rx_pause;
			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n");
		}
	} else if (!(pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) &&
		   (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) &&
		   (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) &&
		   (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) {
		hw->fc.current_mode = ixgbe_fc_tx_pause;
		hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n");
	} else if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) &&
		   (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) &&
		   !(pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) &&
		   (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) {
		hw->fc.current_mode = ixgbe_fc_rx_pause;
		hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n");
	} else {
		hw->fc.current_mode = ixgbe_fc_none;
		hw_dbg(hw, "Flow Control = NONE.\n");
	}

out:
	return ret_val;
}

/**
 *  ixgbe_disable_pcie_master - Disable PCI-express master access
 *  @hw: pointer to hardware structure
+3 −0
Original line number Diff line number Diff line
@@ -61,6 +61,9 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
                                      u32 addr_count, ixgbe_mc_addr_itr func);
s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw);
s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num);
s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packtetbuf_num);
s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw);

s32 ixgbe_validate_mac_addr(u8 *mac_addr);
s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+1 −1
Original line number Diff line number Diff line
@@ -298,7 +298,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw,
	reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
	reg &= ~IXGBE_RMCS_TFCE_802_3X;
	/* correct the reporting of our flow control status */
	hw->fc.type = ixgbe_fc_none;
	hw->fc.current_mode = ixgbe_fc_none;
	reg |= IXGBE_RMCS_TFCE_PRIORITY;
	IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg);

+9 −14
Original line number Diff line number Diff line
@@ -224,13 +224,13 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
	struct ixgbe_adapter *adapter = netdev_priv(netdev);
	struct ixgbe_hw *hw = &adapter->hw;

	pause->autoneg = (hw->fc.type == ixgbe_fc_full ? 1 : 0);
	pause->autoneg = (hw->fc.current_mode == ixgbe_fc_full ? 1 : 0);

	if (hw->fc.type == ixgbe_fc_rx_pause) {
	if (hw->fc.current_mode == ixgbe_fc_rx_pause) {
		pause->rx_pause = 1;
	} else if (hw->fc.type == ixgbe_fc_tx_pause) {
	} else if (hw->fc.current_mode == ixgbe_fc_tx_pause) {
		pause->tx_pause = 1;
	} else if (hw->fc.type == ixgbe_fc_full) {
	} else if (hw->fc.current_mode == ixgbe_fc_full) {
		pause->rx_pause = 1;
		pause->tx_pause = 1;
	}
@@ -244,22 +244,17 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,

	if ((pause->autoneg == AUTONEG_ENABLE) ||
	    (pause->rx_pause && pause->tx_pause))
		hw->fc.type = ixgbe_fc_full;
		hw->fc.requested_mode = ixgbe_fc_full;
	else if (pause->rx_pause && !pause->tx_pause)
		hw->fc.type = ixgbe_fc_rx_pause;
		hw->fc.requested_mode = ixgbe_fc_rx_pause;
	else if (!pause->rx_pause && pause->tx_pause)
		hw->fc.type = ixgbe_fc_tx_pause;
		hw->fc.requested_mode = ixgbe_fc_tx_pause;
	else if (!pause->rx_pause && !pause->tx_pause)
		hw->fc.type = ixgbe_fc_none;
		hw->fc.requested_mode = ixgbe_fc_none;
	else
		return -EINVAL;

	hw->fc.original_type = hw->fc.type;

	if (netif_running(netdev))
		ixgbe_reinit_locked(adapter);
	else
		ixgbe_reset(adapter);
	hw->mac.ops.setup_fc(hw, 0);

	return 0;
}
Loading