ixgbe: support link speed auto-negotiation on X550em_x
authorWenzhuo Lu <wenzhuo.lu@intel.com>
Fri, 26 Feb 2016 03:05:29 +0000 (11:05 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Wed, 16 Mar 2016 16:10:46 +0000 (17:10 +0100)
Normally the auto-negotiation is supported by FW. SW need not care about
that. But on x550em_x, FW doesn't support auto-neg. As the x550em_x ports
are 10G, if we connect the port will a peer which is 1G, the link will
always be down.
We need support auto-neg by SW to avoid this link down issue. As we already
have the code to handle the link speed setting, what we need is a trigger.
When the advertised link speed changes, a PHY interruption will be
triggered. So, we should handle this interrupt and call ixgbe_handle_lasi
to set the link speed correctly.

Please be aware it's working when auto-neg is on. If the auto-neg of the
peer port is turned off and its speed is indicated manually, we should also
set the speed of our own port manually.

Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
Acked-by: Shaopeng He <shaopeng.he@intel.com>
doc/guides/rel_notes/release_16_04.rst
drivers/net/ixgbe/ixgbe_ethdev.c
drivers/net/ixgbe/ixgbe_ethdev.h

index 40fc215..9851dcc 100644 (file)
@@ -116,6 +116,14 @@ This section should contain new features added in this release. Sample format:
   Only x550em_x V1 was supported before. Now V2 is supported.
   A mask for V1 and V2 is defined and used to support both.
 
+* **Supported link speed auto-negotiation on X550EM_X**
+
+  Normally the auto-negotiation is supported by FW. SW need not care about
+  that. But on x550em_x, FW doesn't support auto-neg. As the ports of x550em_x
+  are 10G, if we connect the port with a peer which is 1G, the link will always
+  be down.
+  We added the support of auto-neg by SW to avoid this link down issue.
+
 * **Added sw-firmware sync on X550EM_a.**
 
   Added support for sw-firmware sync for resource sharing.
index 910b7db..1402c65 100644 (file)
@@ -2030,6 +2030,25 @@ ixgbe_dev_configure(struct rte_eth_dev *dev)
        return 0;
 }
 
+static void
+ixgbe_dev_phy_intr_setup(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_interrupt *intr =
+               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+       uint32_t gpie;
+
+       /* only set up it on X550EM_X */
+       if (hw->mac.type == ixgbe_mac_X550EM_x) {
+               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+               gpie |= IXGBE_SDP0_GPIEN_X550EM_x;
+               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+               if (hw->phy.type == ixgbe_phy_x550em_ext_t)
+                       intr->mask |= IXGBE_EICR_GPI_SDP0_X550EM_x;
+       }
+}
+
 /*
  * Configure device link speed and setup link.
  * It returns 0 on success.
@@ -2078,6 +2097,8 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        /* configure PF module if SRIOV enabled */
        ixgbe_pf_host_configure(dev);
 
+       ixgbe_dev_phy_intr_setup(dev);
+
        /* check and configure queue intr-vector mapping */
        if ((rte_intr_cap_multiple(intr_handle) ||
             !RTE_ETH_DEV_SRIOV(dev).active) &&
@@ -3156,6 +3177,11 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
        if (eicr & IXGBE_EICR_MAILBOX)
                intr->flags |= IXGBE_FLAG_MAILBOX;
 
+       if (hw->mac.type ==  ixgbe_mac_X550EM_x &&
+           hw->phy.type == ixgbe_phy_x550em_ext_t &&
+           (eicr & IXGBE_EICR_GPI_SDP0_X550EM_x))
+               intr->flags |= IXGBE_FLAG_PHY_INTERRUPT;
+
        return 0;
 }
 
@@ -3211,6 +3237,8 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
        int64_t timeout;
        struct rte_eth_link link;
        int intr_enable_delay = false;
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        PMD_DRV_LOG(DEBUG, "intr action type %d", intr->flags);
 
@@ -3219,6 +3247,11 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
                intr->flags &= ~IXGBE_FLAG_MAILBOX;
        }
 
+       if (intr->flags & IXGBE_FLAG_PHY_INTERRUPT) {
+               ixgbe_handle_lasi(hw);
+               intr->flags &= ~IXGBE_FLAG_PHY_INTERRUPT;
+       }
+
        if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
                /* get the link status before link update, for predicting later */
                memset(&link, 0, sizeof(link));
@@ -3282,6 +3315,11 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
        if (eicr & IXGBE_EICR_MAILBOX)
                ixgbe_pf_mbx_process(dev);
 
+       if (intr->flags & IXGBE_FLAG_PHY_INTERRUPT) {
+               ixgbe_handle_lasi(hw);
+               intr->flags &= ~IXGBE_FLAG_PHY_INTERRUPT;
+       }
+
        if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
                ixgbe_dev_link_update(dev, 0);
                intr->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
index d26771a..5c3aa16 100644 (file)
@@ -42,6 +42,7 @@
 /* need update link, bit flag */
 #define IXGBE_FLAG_NEED_LINK_UPDATE (uint32_t)(1 << 0)
 #define IXGBE_FLAG_MAILBOX          (uint32_t)(1 << 1)
+#define IXGBE_FLAG_PHY_INTERRUPT    (uint32_t)(1 << 2)
 
 /*
  * Defines that were not part of ixgbe_type.h as they are not used by the