summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
8fd8aa7)
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>
{
struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct rte_eth_link link, old;
{
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;
int err = 0;
link.link_status = ETH_LINK_DOWN;
if (link.link_status == old.link_status)
return -1;
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");
if (rte_eal_alarm_set(1000 * 1000,
atl_dev_delayed_handler, (void *)dev) < 0)
PMD_DRV_LOG(ERR, "rte_eal_alarm_set fail");
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);
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;
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;
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;
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;
fc_conf->mode = RTE_FC_TX_PAUSE;
return 0;
int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
u32 *supported_rates);
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);
int (*set_flow_control)(struct aq_hw_s *self);
int (*led_control)(struct aq_hw_s *self, u32 mode);
+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;
static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
{
u32 tc = 0U;
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_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,
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,
+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);
static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
{
static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
{
.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_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,
.set_flow_control = aq_fw2x_set_flow_control,
.led_control = aq_fw2x_led_control,
.get_eeprom = aq_fw2x_get_eeprom,