From: Anton Mikaev <amik...@aquantia.com>

Adds ethtool -r|--negotiate operation support. It triggers special
control bit on FW interface causing FW to restart link negotiation.

Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
Signed-off-by: Anton Mikaev <amik...@aquantia.com>
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c    | 14 +++++++++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h     |  2 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h        | 35 ++++++++++++++++++++++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 12 ++++++++
 4 files changed, 63 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index c679203..ad6c504 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,19 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
        return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static int aq_ethtool_nway_reset(struct net_device *ndev)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
+               return -EOPNOTSUPP;
+
+       if (netif_running(ndev))
+               return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
+
+       return 0;
+}
+
 static void aq_ethtool_get_pauseparam(struct net_device *ndev,
                                      struct ethtool_pauseparam *pause)
 {
@@ -391,6 +404,7 @@ const struct ethtool_ops aq_ethtool_ops = {
        .get_drvinfo         = aq_ethtool_get_drvinfo,
        .get_strings         = aq_ethtool_get_strings,
        .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+       .nway_reset          = aq_ethtool_nway_reset,
        .get_ringparam       = aq_get_ringparam,
        .set_ringparam       = aq_set_ringparam,
        .get_pauseparam      = aq_ethtool_get_pauseparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 3aa36d5..1a51152 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -212,6 +212,8 @@ struct aq_fw_ops {
 
        int (*reset)(struct aq_hw_s *self);
 
+       int (*renegotiate)(struct aq_hw_s *self);
+
        int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
        int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index cd8f18f..b875590 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -239,6 +239,41 @@ enum hw_atl_fw2x_caps_hi {
        CAPS_HI_TRANSACTION_ID,
 };
 
+enum hw_atl_fw2x_ctrl {
+       CTRL_RESERVED1 = 0x00,
+       CTRL_RESERVED2,
+       CTRL_RESERVED3,
+       CTRL_PAUSE,
+       CTRL_ASYMMETRIC_PAUSE,
+       CTRL_RESERVED4,
+       CTRL_RESERVED5,
+       CTRL_RESERVED6,
+       CTRL_1GBASET_FD_EEE,
+       CTRL_2P5GBASET_FD_EEE,
+       CTRL_5GBASET_FD_EEE,
+       CTRL_10GBASET_FD_EEE,
+       CTRL_THERMAL_SHUTDOWN,
+       CTRL_PHY_LOGS,
+       CTRL_EEE_AUTO_DISABLE,
+       CTRL_PFC,
+       CTRL_WAKE_ON_LINK,
+       CTRL_CABLE_DIAG,
+       CTRL_TEMPERATURE,
+       CTRL_DOWNSHIFT,
+       CTRL_PTP_AVB,
+       CTRL_RESERVED7,
+       CTRL_LINK_DROP,
+       CTRL_SLEEP_PROXY,
+       CTRL_WOL,
+       CTRL_MAC_STOP,
+       CTRL_EXT_LOOPBACK,
+       CTRL_INT_LOOPBACK,
+       CTRL_RESERVED8,
+       CTRL_WOL_TIMER,
+       CTRL_STATISTICS,
+       CTRL_FORCE_RECONNECT,
+};
+
 struct aq_hw_s;
 struct aq_fw_ops;
 struct aq_hw_caps_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index d2d030a..1935fd6 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -215,6 +215,17 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
        return hw_atl_utils_update_stats(self);
 }
 
+static int aq_fw2x_renegotiate(struct aq_hw_s *self)
+{
+       u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+       mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
+
+       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+       return 0;
+}
+
 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);
@@ -230,6 +241,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
        .init = aq_fw2x_init,
        .deinit = aq_fw2x_deinit,
        .reset = NULL,
+       .renegotiate = aq_fw2x_renegotiate,
        .get_mac_permanent = aq_fw2x_get_mac_permanent,
        .set_link_speed = aq_fw2x_set_link_speed,
        .set_state = aq_fw2x_set_state,
-- 
2.7.4

Reply via email to