net: aquantia: Add renegotiate ethtool operation support
authorAnton Mikaev <amikaev@aquantia.com>
Mon, 2 Jul 2018 14:03:38 +0000 (17:03 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 Jul 2018 14:23:48 +0000 (23:23 +0900)
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.russkikh@aquantia.com>
Signed-off-by: Anton Mikaev <amikaev@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
drivers/net/ethernet/aquantia/atlantic/aq_hw.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c

index 37f8460647ac654e5580b48a1e9acdfbbc8062ec..08c9fa6ca71f273b5695887005ce6a5025fbc9c5 100644 (file)
@@ -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)
 {
@@ -390,6 +403,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,
index 3aa36d5765bc8f318db442d629aa6e39394cc8e7..1a51152029c38da32b0a1ef865340ef272ed5419 100644 (file)
@@ -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);
index cd8f18f39c611f8f709f71c7a1c23da8332a3fa4..b875590efcbddbeb5983f2da99f9785d4298734c 100644 (file)
@@ -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;
index c1b671e604fe93b011d620abbee0ae13e111c3de..e37943760a58b2a88b33de295e73dfbac71fc5bf 100644 (file)
@@ -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,