]> git.droids-corp.org - dpdk.git/commitdiff
net/atlantic: fix flow control by sync settings on Rx
authorPavel Belous <pavel.belous@aquantia.com>
Mon, 29 Apr 2019 08:20:23 +0000 (08:20 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 3 May 2019 16:45:23 +0000 (18:45 +0200)
Driver should track negotiated PHY flow control settings during
link state changes and update MAC level flow control configuration.

Otherwise there could be unexpected pause frames generation which
could lockup the datapath.

Fixes: 4c1c8f76463f ("net/atlantic: add flow control configuration")
Cc: stable@dpdk.org
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: Pavel Belous <pavel.belous@aquantia.com>
drivers/net/atlantic/atl_ethdev.c
drivers/net/atlantic/atl_types.h
drivers/net/atlantic/hw_atl/hw_atl_b0.c
drivers/net/atlantic/hw_atl/hw_atl_b0.h
drivers/net/atlantic/hw_atl/hw_atl_utils_fw2x.c

index d7572734cb5f13c3580d78925d08ad1352e0566c..e15173f5ff398f6be90ffba3130418b14c25e268 100644 (file)
@@ -1160,6 +1160,7 @@ atl_dev_link_update(struct rte_eth_dev *dev, int wait __rte_unused)
 {
        struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct rte_eth_link link, old;
+       u32 fc = AQ_NIC_FC_OFF;
        int err = 0;
 
        link.link_status = ETH_LINK_DOWN;
@@ -1194,6 +1195,15 @@ atl_dev_link_update(struct rte_eth_dev *dev, int wait __rte_unused)
        if (link.link_status == old.link_status)
                return -1;
 
+       /* Driver has to update flow control settings on RX block
+        * on any link event.
+        * We should query FW whether it negotiated FC.
+        */
+       if (hw->aq_fw_ops->get_flow_control) {
+               hw->aq_fw_ops->get_flow_control(hw, &fc);
+               hw_atl_b0_set_fc(hw, fc, 0U);
+       }
+
        if (rte_eal_alarm_set(1000 * 1000,
                              atl_dev_delayed_handler, (void *)dev) < 0)
                PMD_DRV_LOG(ERR, "rte_eal_alarm_set fail");
@@ -1496,14 +1506,20 @@ static int
 atl_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
 {
        struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       u32 fc = AQ_NIC_FC_OFF;
+
+       if (hw->aq_fw_ops->get_flow_control == NULL)
+               return -ENOTSUP;
+
+       hw->aq_fw_ops->get_flow_control(hw, &fc);
 
-       if (hw->aq_nic_cfg->flow_control == AQ_NIC_FC_OFF)
+       if (fc == AQ_NIC_FC_OFF)
                fc_conf->mode = RTE_FC_NONE;
-       else if (hw->aq_nic_cfg->flow_control & (AQ_NIC_FC_RX | AQ_NIC_FC_TX))
+       else if (fc & (AQ_NIC_FC_RX | AQ_NIC_FC_TX))
                fc_conf->mode = RTE_FC_FULL;
-       else if (hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
+       else if (fc & AQ_NIC_FC_RX)
                fc_conf->mode = RTE_FC_RX_PAUSE;
-       else if (hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
+       else if (fc & AQ_NIC_FC_RX)
                fc_conf->mode = RTE_FC_TX_PAUSE;
 
        return 0;
index 84a4776951db140acd8ec5ff23554fde9026908c..19aaf37673cd64930f252a25ca1839ca574e7d0b 100644 (file)
@@ -169,6 +169,7 @@ struct aq_fw_ops {
        int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
                        u32 *supported_rates);
 
+       int (*get_flow_control)(struct aq_hw_s *self, u32 *fc);
        int (*set_flow_control)(struct aq_hw_s *self);
 
        int (*led_control)(struct aq_hw_s *self, u32 mode);
index dc8229bfcd3d4314e75398e70604059ede416c15..7d0e72401937396bd5ac37082e7911af127f9451 100644 (file)
@@ -26,6 +26,12 @@ int hw_atl_b0_hw_reset(struct aq_hw_s *self)
        return err;
 }
 
+int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc)
+{
+       hw_atl_rpb_rx_xoff_en_per_tc_set(self, !!(fc & AQ_NIC_FC_RX), tc);
+       return 0;
+}
+
 static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
 {
        u32 tc = 0U;
index 06feb56c16209336f0c042bac22f9479427f5cd2..d1ba2aceb390d1ef90f33a7187466cfd39a736d2 100644 (file)
@@ -11,6 +11,8 @@
 int hw_atl_b0_hw_reset(struct aq_hw_s *self);
 int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr);
 
+int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc);
+
 int hw_atl_b0_hw_ring_tx_init(struct aq_hw_s *self, uint64_t base_addr,
                int index, int size, int cpu, int vec);
 int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self, uint64_t base_addr,
index de4189441fad0ef67942d41826eabf3e90b3a6d9..e07ed5e3a8c9abf8f9040b77379549003be557b3 100644 (file)
@@ -473,7 +473,15 @@ static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
        return err;
 }
 
+static int aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fc)
+{
+       u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+       *fc = ((mpi_state & BIT(CAPS_HI_PAUSE)) ? AQ_NIC_FC_RX : 0) |
+             ((mpi_state & BIT(CAPS_HI_ASYMMETRIC_PAUSE)) ? AQ_NIC_FC_TX : 0);
 
+       return 0;
+}
 
 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 {
@@ -714,6 +722,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
        .get_cable_len = aq_fw2x_get_cable_len,
        .set_eee_rate = aq_fw2x_set_eee_rate,
        .get_eee_rate = aq_fw2x_get_eee_rate,
+       .get_flow_control = aq_fw2x_get_flow_control,
        .set_flow_control = aq_fw2x_set_flow_control,
        .led_control = aq_fw2x_led_control,
        .get_eeprom = aq_fw2x_get_eeprom,