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:
Nikita Danilov 2019-11-07 22:42:04 +00:00 committed by David S. Miller
parent ddef552632
commit 8009bb1928
7 changed files with 59 additions and 41 deletions

View file

@ -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 */

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;
}