net: atlantic: update flow control logic
authorNikita Danilov <ndanilov@marvell.com>
Thu, 7 Nov 2019 22:42:04 +0000 (22:42 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 Nov 2019 03:54:43 +0000 (19:54 -0800)
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>
drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c

index d02b0d79f68a5e75a51377bbd27fcc24bb9fd473..f0c41f7408e57786e2e5c03508854f36f24ccfde 100644 (file)
 
 /*#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 */
index 8286c77d43a54e5c4697a1e56a324e6057df35b6..6353a5c5ed2700b84997b4b6c1c8c70ccb435aae 100644 (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);
index d3739f21b18e879670980c787b4a06f7d006a696..7ad8eb535d28b6720076ad3077720f32d98914e5 100644 (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);
 
index 98c3182bf1d0520c45fc045bd2de71824f1a9d7a..a752f8bb4b08572da7454a859550ed590510b1be 100644 (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;
index d2fb399f179f5b11f760437b462a850841a6c021..03b62d7d9f1a5042399094d44eb4efc369b02bfb 100644 (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);
index 8686462b32f9aeb0b13949e1ec361b42c323bdfc..c5da60c122623b037e9ef4543e244b10cbb63e97 100644 (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;
index ce3ed86d8c0e8c54e66dc500b6b0ad3c33e0a436..97ebf849695fdb0b9cc386c535b3ff34e7fba3c4 100644 (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;
 }