Commit 8009bb19 authored by Nikita Danilov's avatar Nikita Danilov Committed by David S. Miller

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: default avatarNikita Danilov <ndanilov@marvell.com>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ddef5526
...@@ -70,12 +70,6 @@ ...@@ -70,12 +70,6 @@
/*#define AQ_CFG_MAC_ADDR_PERMANENT {0x30, 0x0E, 0xE3, 0x12, 0x34, 0x56}*/ /*#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 #define AQ_CFG_FC_MODE AQ_NIC_FC_FULL
/* Default WOL modes used on initialization */ /* Default WOL modes used on initialization */
......
...@@ -588,7 +588,7 @@ static void aq_ethtool_get_pauseparam(struct net_device *ndev, ...@@ -588,7 +588,7 @@ static void aq_ethtool_get_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *pause) struct ethtool_pauseparam *pause)
{ {
struct aq_nic_s *aq_nic = netdev_priv(ndev); 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; pause->autoneg = 0;
...@@ -610,14 +610,14 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev, ...@@ -610,14 +610,14 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (pause->rx_pause) 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 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) 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 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); mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw); 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) ...@@ -79,7 +79,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->is_rss = AQ_CFG_IS_RSS_DEF; cfg->is_rss = AQ_CFG_IS_RSS_DEF;
cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_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->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->wol = AQ_CFG_WOL_MODES;
cfg->mtu = AQ_CFG_MTU_DEF; cfg->mtu = AQ_CFG_MTU_DEF;
...@@ -144,6 +144,10 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) ...@@ -144,6 +144,10 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
if (err) if (err)
return 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) { if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) {
netdev_info(self->ndev, "%s: link change old %d new %d\n", netdev_info(self->ndev, "%s: link change old %d new %d\n",
AQ_CFG_DRV_NAME, self->link_status.mbps, AQ_CFG_DRV_NAME, self->link_status.mbps,
...@@ -161,8 +165,6 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) ...@@ -161,8 +165,6 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
* on any link event. * on any link event.
* We should query FW whether it negotiated FC. * 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) if (self->aq_hw_ops->hw_set_fc)
self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0); 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, ...@@ -862,9 +864,12 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, supported, ethtool_link_ksettings_add_link_mode(cmd, supported,
100baseT_Full); 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, ethtool_link_ksettings_add_link_mode(cmd, supported,
Pause); Pause);
ethtool_link_ksettings_add_link_mode(cmd, supported,
Asym_Pause);
}
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
...@@ -898,13 +903,13 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ...@@ -898,13 +903,13 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
100baseT_Full); 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, ethtool_link_ksettings_add_link_mode(cmd, advertising,
Pause); Pause);
/* Asym is when either RX or TX, but not both */ /* Asym is when either RX or TX, but not both */
if (!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) ^ if (!!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_TX) ^
!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)) !!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX))
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
Asym_Pause); Asym_Pause);
......
...@@ -20,6 +20,18 @@ struct aq_vec_s; ...@@ -20,6 +20,18 @@ struct aq_vec_s;
struct aq_ptp_s; struct aq_ptp_s;
enum aq_rx_filter_type; 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 { struct aq_nic_cfg_s {
const struct aq_hw_caps_s *aq_hw_caps; const struct aq_hw_caps_s *aq_hw_caps;
u64 features; u64 features;
...@@ -34,7 +46,7 @@ struct aq_nic_cfg_s { ...@@ -34,7 +46,7 @@ struct aq_nic_cfg_s {
u32 rxpageorder; u32 rxpageorder;
u32 num_rss_queues; u32 num_rss_queues;
u32 mtu; u32 mtu;
u32 flow_control; struct aq_fc_info fc;
u32 link_speed_msk; u32 link_speed_msk;
u32 wol; u32 wol;
u8 is_vlan_rx_strip; u8 is_vlan_rx_strip;
......
...@@ -155,7 +155,7 @@ static int hw_atl_a0_hw_qos_set(struct aq_hw_s *self) ...@@ -155,7 +155,7 @@ static int hw_atl_a0_hw_qos_set(struct aq_hw_s *self)
/* QoS Rx buf size per TC */ /* QoS Rx buf size per TC */
tc = 0; 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; buff_size = HW_ATL_A0_RXBUF_MAX;
hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc); 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) ...@@ -168,7 +168,7 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
(1024U / 32U) * 50U) / (1024U / 32U) * 50U) /
100U, tc); 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 */ /* Init TC2 for PTP_RX */
tc = 2; tc = 2;
......
...@@ -181,17 +181,26 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) ...@@ -181,17 +181,26 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
return 0; 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 &= ~(HW_ATL_FW2X_CTRL_PAUSE |
*mpi_state |= BIT(CAPS_HI_PAUSE); HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
else
*mpi_state &= ~BIT(CAPS_HI_PAUSE);
if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX) switch (fc) {
*mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE); /* There is not explicit mode of RX only pause frames,
else * thus, we join this mode with FC full.
*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE); * 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, 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, ...@@ -215,7 +224,8 @@ static int aq_fw2x_set_state(struct aq_hw_s *self,
case MPI_INIT: case MPI_INIT:
mpi_state &= ~BIT(CAPS_HI_LINK_DROP); mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds); 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; break;
case MPI_DEINIT: case MPI_DEINIT:
mpi_state |= BIT(CAPS_HI_LINK_DROP); mpi_state |= BIT(CAPS_HI_LINK_DROP);
...@@ -525,7 +535,8 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self) ...@@ -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); 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); 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) ...@@ -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) static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
{ {
u32 mpi_state = aq_fw2x_state2_get(self); 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_PAUSE)
if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) *fcmode |= AQ_NIC_FC_RX;
*fcmode = AQ_NIC_FC_RX;
else if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
*fcmode = AQ_NIC_FC_RX | AQ_NIC_FC_TX; *fcmode |= AQ_NIC_FC_TX;
else
if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
*fcmode = AQ_NIC_FC_TX;
else
*fcmode = 0;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment