From 6be3dfec31dfef9078f1bfc578687902c7af51c0 Mon Sep 17 00:00:00 2001 From: Wenzhuo Lu Date: Fri, 26 Feb 2016 11:05:29 +0800 Subject: [PATCH] ixgbe: support 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 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 Acked-by: Shaopeng He --- doc/guides/rel_notes/release_16_04.rst | 8 ++++++ drivers/net/ixgbe/ixgbe_ethdev.c | 38 ++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_ethdev.h | 1 + 3 files changed, 47 insertions(+) diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst index 40fc215aef..9851dcce06 100644 --- a/doc/guides/rel_notes/release_16_04.rst +++ b/doc/guides/rel_notes/release_16_04.rst @@ -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. diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c index 910b7dbbd2..1402c65041 100644 --- a/drivers/net/ixgbe/ixgbe_ethdev.c +++ b/drivers/net/ixgbe/ixgbe_ethdev.c @@ -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; diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h b/drivers/net/ixgbe/ixgbe_ethdev.h index d26771a7f5..5c3aa16e89 100644 --- a/drivers/net/ixgbe/ixgbe_ethdev.h +++ b/drivers/net/ixgbe/ixgbe_ethdev.h @@ -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 -- 2.20.1