Module Name:    src
Committed By:   msaitoh
Date:           Wed Nov  8 08:41:13 UTC 2017

Modified Files:
        src/sys/dev/pci/ixgbe: ixgbe_x550.c

Log Message:
 Fix a bug that Denverton which uses firmware don't linkup if the media is
forced to 100baseTX-FDX or 10baseT-FDX. As I wrote in ixgbe_phy.c rev. 1.13,
popular switches and OSes don't use auto-negotiation if the media is forced to
100BASE-TX or 10BASE-T. Do the same thing. But, if we don't set
FW_PHY_ACT_SETUP_LINK_AN in ixgbe_setup_fw_link(), the firmware wrongly set
BMCR register. Two problems are observed:

        a) FDX may not be set.
        b) BMCR_SPEED1 (bit 6) is always cleard.

        + -------+------+-----------+-----+
        |request | BMCR | BMCR spd | BMCR |
        |        | (HEX)| (in bits)|  FDX |
        +--------+------+----------+------+
        |   10M  | 0000 |  10M(00) |    0 |
        |   10M  | 2100 | 100M(01) |    1 |
        |  100M  | 0000 |  10M(00) |    0 |
        |  100M  | 0100 |  10M(00) |    1 |
        +--------------------------+------+

 To avoid this problem, after sending request to firmware, check BMCR register
and fix the setting if it's required.

 Before this change:

        +------------------+---------------------------------------------+
        |                  |                    denverton                |
        |                  +---------+--------+---------+----------------+
        |                  |   auto  | 1G FDX | 100 FDX |         10 FDX |
        +---------+--------+---------+--------+---------+----------------+
        |         |   auto |  1G FDX | 1G FDX | 100 FDX | 10FDX/down(NG) |
        |         +--------+---------+--------+---------+----------------+
        |         | 1G FDX |  1G FDX | 1G FDX |    down |           down |
        | link    +--------+---------+--------+---------+----------------+
        | partner |100 FDX | down(*1)|   down | down(NG)|           down |
        |         +--------+---------+--------+---------+----------------+
        |         | 10 FDX | down(*1)|   down |    down |       down(NG) |
        +---------+--------+---------+--------+---------+----------------+
        (Observed on: NVM Image Version 0.05 ID 0x8, NVM Map version 1.16,
        OEM NVM Image version 0.06, ETrackID 8000087c)

 After this change:

        +------------------+---------------------------------------------+
        |                  |                    denverton                |
        |                  +---------+--------+---------+----------------+
        |                  |   auto  | 1G FDX | 100 FDX |         10 FDX |
        +---------+--------+---------+--------+---------+----------------+
        |         |   auto |  1G FDX | 1G FDX | 100 FDX |         10 FDX |
        |         +--------+---------+--------+---------+----------------+
        |         | 1G FDX |  1G FDX | 1G FDX |    down |           down |
        | link    +--------+---------+--------+---------+----------------+
        | partner |100 FDX | down(*1)|   down | 100 FDX |           down |
        |         +--------+---------+--------+---------+----------------+
        |         | 10 FDX | down(*1)|   down |    down |         10 FDX |
        +---------+--------+---------+--------+---------+----------------+
        *1): may be correct because ixg doesn't support half duplex.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pci/ixgbe/ixgbe_x550.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/ixgbe/ixgbe_x550.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_x550.c:1.6 src/sys/dev/pci/ixgbe/ixgbe_x550.c:1.7
--- src/sys/dev/pci/ixgbe/ixgbe_x550.c:1.6	Wed Aug 30 08:49:18 2017
+++ src/sys/dev/pci/ixgbe/ixgbe_x550.c	Wed Nov  8 08:41:13 2017
@@ -38,6 +38,7 @@
 #include "ixgbe_api.h"
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
+#include <dev/mii/mii.h>
 
 static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed);
 static s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, u32 mask);
@@ -788,6 +789,8 @@ s32 ixgbe_init_ops_X550EM(struct ixgbe_h
 	return ret_val;
 }
 
+#define IXGBE_DENVERTON_WA 1
+
 /**
  * ixgbe_setup_fw_link - Setup firmware-controlled PHYs
  * @hw: pointer to hardware structure
@@ -796,6 +799,10 @@ static s32 ixgbe_setup_fw_link(struct ix
 {
 	u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 };
 	s32 rc;
+#ifdef IXGBE_DENVERTON_WA
+	s32 ret_val;
+	u16 phydata;
+#endif
 	u16 i;
 
 	if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw))
@@ -833,9 +840,67 @@ static s32 ixgbe_setup_fw_link(struct ix
 	if (hw->phy.eee_speeds_advertised)
 		setup[0] |= FW_PHY_ACT_SETUP_LINK_EEE;
 
+#ifdef IXGBE_DENVERTON_WA
+	/* Don't use auto-nego for 10/100Mbps */
+	if ((hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_100_FULL)
+	    || (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_10_FULL)) {
+		setup[0] &= ~FW_PHY_ACT_SETUP_LINK_AN;
+		setup[0] &= ~FW_PHY_ACT_SETUP_LINK_EEE;
+		setup[0] &= ~(FW_PHY_ACT_SETUP_LINK_PAUSE_RXTX
+		    << FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT);
+	}
+#endif
+
 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup);
 	if (rc)
 		return rc;
+
+#ifdef IXGBE_DENVERTON_WA
+	ret_val = ixgbe_read_phy_reg_x550a(hw, MII_BMCR, 0, &phydata);
+	if (ret_val != 0)
+		goto out;
+
+	/*
+	 *  Broken firmware sets BMCR register incorrectly if
+	 * FW_PHY_ACT_SETUP_LINK_AN isn't set.
+	 * a) FDX may not be set.
+	 * b) BMCR_SPEED1 (bit 6) is always cleard.
+	 * + -------+------+-----------+-----+--------------------------+
+	 * |request | BMCR | BMCR spd | BMCR |                          |
+	 * |        | (HEX)| (in bits)|  FDX |                          |
+	 * +--------+------+----------+------+--------------------------+
+	 * |   10M  | 0000 |  10M(00) |    0 |                          |
+	 * |   10M  | 2000 | 100M(01) |    0 |(I've never observed this)|
+	 * |   10M  | 2100 | 100M(01) |    1 |                          |
+	 * |  100M  | 0000 |  10M(00) |    0 |                          |
+	 * |  100M  | 0100 |  10M(00) |    1 |                          |
+	 * +--------------------------+------+--------------------------+
+	 */
+	if (((hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_100_FULL)
+		&& (((phydata & BMCR_FDX) == 0) || (BMCR_SPEED(phydata) == 0)))
+	    || ((hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_10_FULL)
+		&& (((phydata & BMCR_FDX) == 0)
+		    || (BMCR_SPEED(phydata) != BMCR_S10)))) {
+		phydata = BMCR_FDX;
+		switch (hw->phy.autoneg_advertised) {
+		case IXGBE_LINK_SPEED_10_FULL:
+			phydata |= BMCR_S10;
+			break;
+		case IXGBE_LINK_SPEED_100_FULL:
+			phydata |= BMCR_S100;
+			break;
+		case IXGBE_LINK_SPEED_1GB_FULL:
+			panic("%s: 1GB_FULL is set", __func__);
+			break;
+		default:
+			break;
+		}
+		ret_val = ixgbe_write_phy_reg_x550a(hw, MII_BMCR, 0, phydata);
+		if (ret_val != 0)
+			return ret_val;
+	}
+out:
+#endif
 	if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN)
 		return IXGBE_ERR_OVERTEMP;
 	return IXGBE_SUCCESS;

Reply via email to