net: atlantic: update flow control logic
We now differentiate requested and negotiated flow control modes. Therefore `ethtool -A` now operates on local requested FC values, and regular link settings shows the negotiated FC settings. Signed-off-by: Nikita Danilov <ndanilov@marvell.com> Signed-off-by: Igor Russkikh <irusskikh@marvell.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ddef552632
commit
8009bb1928
|
@ -70,12 +70,6 @@
|
|||
|
||||
/*#define AQ_CFG_MAC_ADDR_PERMANENT {0x30, 0x0E, 0xE3, 0x12, 0x34, 0x56}*/
|
||||
|
||||
#define AQ_NIC_FC_OFF 0U
|
||||
#define AQ_NIC_FC_TX 1U
|
||||
#define AQ_NIC_FC_RX 2U
|
||||
#define AQ_NIC_FC_FULL 3U
|
||||
#define AQ_NIC_FC_AUTO 4U
|
||||
|
||||
#define AQ_CFG_FC_MODE AQ_NIC_FC_FULL
|
||||
|
||||
/* Default WOL modes used on initialization */
|
||||
|
|
|
@ -588,7 +588,7 @@ static void aq_ethtool_get_pauseparam(struct net_device *ndev,
|
|||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct aq_nic_s *aq_nic = netdev_priv(ndev);
|
||||
u32 fc = aq_nic->aq_nic_cfg.flow_control;
|
||||
u32 fc = aq_nic->aq_nic_cfg.fc.req;
|
||||
|
||||
pause->autoneg = 0;
|
||||
|
||||
|
@ -610,14 +610,14 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
if (pause->rx_pause)
|
||||
aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
|
||||
aq_nic->aq_hw->aq_nic_cfg->fc.req |= AQ_NIC_FC_RX;
|
||||
else
|
||||
aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;
|
||||
aq_nic->aq_hw->aq_nic_cfg->fc.req &= ~AQ_NIC_FC_RX;
|
||||
|
||||
if (pause->tx_pause)
|
||||
aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
|
||||
aq_nic->aq_hw->aq_nic_cfg->fc.req |= AQ_NIC_FC_TX;
|
||||
else
|
||||
aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
|
||||
aq_nic->aq_hw->aq_nic_cfg->fc.req &= ~AQ_NIC_FC_TX;
|
||||
|
||||
mutex_lock(&aq_nic->fwreq_mutex);
|
||||
err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
|
||||
|
|
|
@ -79,7 +79,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
|
|||
cfg->is_rss = AQ_CFG_IS_RSS_DEF;
|
||||
cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF;
|
||||
cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF;
|
||||
cfg->flow_control = AQ_CFG_FC_MODE;
|
||||
cfg->fc.req = AQ_CFG_FC_MODE;
|
||||
cfg->wol = AQ_CFG_WOL_MODES;
|
||||
|
||||
cfg->mtu = AQ_CFG_MTU_DEF;
|
||||
|
@ -144,6 +144,10 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (self->aq_fw_ops->get_flow_control)
|
||||
self->aq_fw_ops->get_flow_control(self->aq_hw, &fc);
|
||||
self->aq_nic_cfg.fc.cur = fc;
|
||||
|
||||
if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) {
|
||||
netdev_info(self->ndev, "%s: link change old %d new %d\n",
|
||||
AQ_CFG_DRV_NAME, self->link_status.mbps,
|
||||
|
@ -161,8 +165,6 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
|
|||
* on any link event.
|
||||
* We should query FW whether it negotiated FC.
|
||||
*/
|
||||
if (self->aq_fw_ops->get_flow_control)
|
||||
self->aq_fw_ops->get_flow_control(self->aq_hw, &fc);
|
||||
if (self->aq_hw_ops->hw_set_fc)
|
||||
self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0);
|
||||
}
|
||||
|
@ -862,9 +864,12 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
|
|||
ethtool_link_ksettings_add_link_mode(cmd, supported,
|
||||
100baseT_Full);
|
||||
|
||||
if (self->aq_nic_cfg.aq_hw_caps->flow_control)
|
||||
if (self->aq_nic_cfg.aq_hw_caps->flow_control) {
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported,
|
||||
Pause);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported,
|
||||
Asym_Pause);
|
||||
}
|
||||
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
|
||||
|
||||
|
@ -898,13 +903,13 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
|
|||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
100baseT_Full);
|
||||
|
||||
if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)
|
||||
if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Pause);
|
||||
|
||||
/* Asym is when either RX or TX, but not both */
|
||||
if (!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) ^
|
||||
!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX))
|
||||
if (!!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_TX) ^
|
||||
!!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX))
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
|
||||
|
|
|
@ -20,6 +20,18 @@ struct aq_vec_s;
|
|||
struct aq_ptp_s;
|
||||
enum aq_rx_filter_type;
|
||||
|
||||
enum aq_fc_mode {
|
||||
AQ_NIC_FC_OFF = 0,
|
||||
AQ_NIC_FC_TX,
|
||||
AQ_NIC_FC_RX,
|
||||
AQ_NIC_FC_FULL,
|
||||
};
|
||||
|
||||
struct aq_fc_info {
|
||||
enum aq_fc_mode req;
|
||||
enum aq_fc_mode cur;
|
||||
};
|
||||
|
||||
struct aq_nic_cfg_s {
|
||||
const struct aq_hw_caps_s *aq_hw_caps;
|
||||
u64 features;
|
||||
|
@ -34,7 +46,7 @@ struct aq_nic_cfg_s {
|
|||
u32 rxpageorder;
|
||||
u32 num_rss_queues;
|
||||
u32 mtu;
|
||||
u32 flow_control;
|
||||
struct aq_fc_info fc;
|
||||
u32 link_speed_msk;
|
||||
u32 wol;
|
||||
u8 is_vlan_rx_strip;
|
||||
|
|
|
@ -155,7 +155,7 @@ static int hw_atl_a0_hw_qos_set(struct aq_hw_s *self)
|
|||
|
||||
/* QoS Rx buf size per TC */
|
||||
tc = 0;
|
||||
is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->flow_control);
|
||||
is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->fc.req);
|
||||
buff_size = HW_ATL_A0_RXBUF_MAX;
|
||||
|
||||
hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc);
|
||||
|
|
|
@ -168,7 +168,7 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
|
|||
(1024U / 32U) * 50U) /
|
||||
100U, tc);
|
||||
|
||||
hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc);
|
||||
hw_atl_b0_set_fc(self, self->aq_nic_cfg->fc.req, tc);
|
||||
|
||||
/* Init TC2 for PTP_RX */
|
||||
tc = 2;
|
||||
|
|
|
@ -181,17 +181,26 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
|
||||
static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
|
||||
u32 *mpi_state, u32 fc)
|
||||
{
|
||||
if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
|
||||
*mpi_state |= BIT(CAPS_HI_PAUSE);
|
||||
else
|
||||
*mpi_state &= ~BIT(CAPS_HI_PAUSE);
|
||||
*mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
|
||||
HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
|
||||
|
||||
if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
|
||||
*mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
|
||||
else
|
||||
*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
|
||||
switch (fc) {
|
||||
/* There is not explicit mode of RX only pause frames,
|
||||
* thus, we join this mode with FC full.
|
||||
* FC full is either Rx, either Tx, or both.
|
||||
*/
|
||||
case AQ_NIC_FC_FULL:
|
||||
case AQ_NIC_FC_RX:
|
||||
*mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
|
||||
HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
|
||||
break;
|
||||
case AQ_NIC_FC_TX:
|
||||
*mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
|
||||
|
@ -215,7 +224,8 @@ static int aq_fw2x_set_state(struct aq_hw_s *self,
|
|||
case MPI_INIT:
|
||||
mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
|
||||
aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
|
||||
aq_fw2x_set_mpi_flow_control(self, &mpi_state);
|
||||
aq_fw2x_upd_flow_control_bits(self, &mpi_state,
|
||||
self->aq_nic_cfg->fc.req);
|
||||
break;
|
||||
case MPI_DEINIT:
|
||||
mpi_state |= BIT(CAPS_HI_LINK_DROP);
|
||||
|
@ -525,7 +535,8 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
|
|||
{
|
||||
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
|
||||
|
||||
aq_fw2x_set_mpi_flow_control(self, &mpi_state);
|
||||
aq_fw2x_upd_flow_control_bits(self, &mpi_state,
|
||||
self->aq_nic_cfg->fc.req);
|
||||
|
||||
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
|
||||
|
||||
|
@ -535,17 +546,13 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
|
|||
static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
|
||||
{
|
||||
u32 mpi_state = aq_fw2x_state2_get(self);
|
||||
*fcmode = 0;
|
||||
|
||||
if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
|
||||
if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
|
||||
*fcmode = AQ_NIC_FC_RX;
|
||||
else
|
||||
*fcmode = AQ_NIC_FC_RX | AQ_NIC_FC_TX;
|
||||
else
|
||||
if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
|
||||
*fcmode = AQ_NIC_FC_TX;
|
||||
else
|
||||
*fcmode = 0;
|
||||
*fcmode |= AQ_NIC_FC_RX;
|
||||
|
||||
if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
|
||||
*fcmode |= AQ_NIC_FC_TX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue