From: Yana Esina <yana.es...@aquantia.com>

Support of Energy-Efficient Ethernet to aQuantia NIC's via ethtool
(according to the IEEE 802.3az specifications)

We do replace some duplicate speed bits definitions here (HW_ATL_B0_RATE_)
with driver generic constants (AQ_NIC_RATE_)

Signed-off-by: Yana Esina <yana.es...@aquantia.com>
Signed-off-by: Nikita Danilov <nikita.dani...@aquantia.com>
Tested-by: Nikita Danilov <nikita.dani...@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   5 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c    |  76 +++++++++++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h     |   4 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h    |   1 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  32 ++---
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  34 ++---
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   6 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c        |   2 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h        |  13 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 141 +++++++++++++++++----
 11 files changed, 250 insertions(+), 70 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index d52b088..becb578 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -57,4 +57,9 @@
 #define AQ_NIC_RATE_1G         BIT(4)
 #define AQ_NIC_RATE_100M       BIT(5)
 
+#define AQ_NIC_RATE_EEE_10G    BIT(6)
+#define AQ_NIC_RATE_EEE_5G     BIT(7)
+#define AQ_NIC_RATE_EEE_2GS    BIT(8)
+#define AQ_NIC_RATE_EEE_1G     BIT(9)
+
 #endif /* AQ_COMMON_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index f9fe49b..ec12edf 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -315,6 +315,80 @@ static int aq_ethtool_set_wol(struct net_device *ndev,
        return err;
 }
 
+static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
+{
+       u32 rate = 0;
+
+       if (speed & AQ_NIC_RATE_EEE_10G)
+               rate |= SUPPORTED_10000baseT_Full;
+
+       if (speed & AQ_NIC_RATE_EEE_2GS)
+               rate |= SUPPORTED_2500baseX_Full;
+
+       if (speed & AQ_NIC_RATE_EEE_1G)
+               rate |= SUPPORTED_1000baseT_Full;
+
+       return rate;
+}
+
+static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+       int err = 0;
+
+       u32 rate, supported_rates;
+
+       if (!aq_nic->aq_fw_ops->get_eee_rate)
+               return -EOPNOTSUPP;
+
+       err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
+                                             &supported_rates);
+       if (err < 0)
+               return err;
+
+       eee->supported = eee_mask_to_ethtool_mask(supported_rates);
+
+       if (aq_nic->aq_nic_cfg.eee_speeds)
+               eee->advertised = eee->supported;
+
+       eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
+
+       eee->eee_enabled = !!eee->advertised;
+
+       eee->tx_lpi_enabled = eee->eee_enabled;
+       if (eee->advertised & eee->lp_advertised)
+               eee->eee_active = true;
+
+       return 0;
+}
+
+static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+       struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+       u32 rate, supported_rates;
+       int err = 0;
+
+       if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
+                    !aq_nic->aq_fw_ops->set_eee_rate))
+               return -EOPNOTSUPP;
+
+       err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
+                                             &supported_rates);
+       if (err < 0)
+               return err;
+
+       if (eee->eee_enabled) {
+               rate = supported_rates;
+               cfg->eee_speeds = rate;
+       } else {
+               rate = 0;
+               cfg->eee_speeds = 0;
+       }
+
+       return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
        struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -438,6 +512,8 @@ const struct ethtool_ops aq_ethtool_ops = {
        .nway_reset          = aq_ethtool_nway_reset,
        .get_ringparam       = aq_get_ringparam,
        .set_ringparam       = aq_set_ringparam,
+       .get_eee             = aq_ethtool_get_eee,
+       .set_eee             = aq_ethtool_set_eee,
        .get_pauseparam      = aq_ethtool_get_pauseparam,
        .set_pauseparam      = aq_ethtool_set_pauseparam,
        .get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 403d86ea..e868924 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -231,6 +231,10 @@ struct aq_fw_ops {
        int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
                         u8 *mac);
 
+       int (*set_eee_rate)(struct aq_hw_s *self, u32 speed);
+
+       int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
+                           u32 *supported_rates);
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index 2069cbb..c1582f4 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -45,6 +45,7 @@ struct aq_nic_cfg_s {
        bool is_lro;
        u8  tcs;
        struct aq_rss_parameters aq_rss;
+       u32 eee_speeds;
 };
 
 #define AQ_NIC_FLAG_STARTED     0x00000004U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 1dd0ef4..f9d88c7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -49,37 +49,37 @@
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
        DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_FIBRE,
-       .link_speed_msk = HW_ATL_A0_RATE_5G  |
-                         HW_ATL_A0_RATE_2G5 |
-                         HW_ATL_A0_RATE_1G  |
-                         HW_ATL_A0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_5G |
+                         AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = {
        DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_TP,
-       .link_speed_msk = HW_ATL_A0_RATE_10G |
-                         HW_ATL_A0_RATE_5G  |
-                         HW_ATL_A0_RATE_2G5 |
-                         HW_ATL_A0_RATE_1G  |
-                         HW_ATL_A0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_10G |
+                         AQ_NIC_RATE_5G |
+                         AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = {
        DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_TP,
-       .link_speed_msk = HW_ATL_A0_RATE_5G  |
-                         HW_ATL_A0_RATE_2G5 |
-                         HW_ATL_A0_RATE_1G  |
-                         HW_ATL_A0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_5G |
+                         AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = {
        DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_TP,
-       .link_speed_msk = HW_ATL_A0_RATE_2G5 |
-                         HW_ATL_A0_RATE_1G  |
-                         HW_ATL_A0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 static int hw_atl_a0_hw_reset(struct aq_hw_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
index 3c94cff..a021dc4 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
@@ -62,12 +62,6 @@
 #define HW_ATL_A0_MPI_SPEED_MSK       0xFFFFU
 #define HW_ATL_A0_MPI_SPEED_SHIFT     16U
 
-#define HW_ATL_A0_RATE_10G            BIT(0)
-#define HW_ATL_A0_RATE_5G             BIT(1)
-#define HW_ATL_A0_RATE_2G5            BIT(3)
-#define HW_ATL_A0_RATE_1G             BIT(4)
-#define HW_ATL_A0_RATE_100M           BIT(5)
-
 #define HW_ATL_A0_TXBUF_MAX 160U
 #define HW_ATL_A0_RXBUF_MAX 320U
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 6644c96..5092f1b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -51,38 +51,38 @@
 const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = {
        DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_FIBRE,
-       .link_speed_msk = HW_ATL_B0_RATE_10G |
-                         HW_ATL_B0_RATE_5G  |
-                         HW_ATL_B0_RATE_2G5 |
-                         HW_ATL_B0_RATE_1G  |
-                         HW_ATL_B0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_10G |
+                         AQ_NIC_RATE_5G |
+                         AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_b0_caps_aqc107 = {
        DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_TP,
-       .link_speed_msk = HW_ATL_B0_RATE_10G |
-                         HW_ATL_B0_RATE_5G  |
-                         HW_ATL_B0_RATE_2G5 |
-                         HW_ATL_B0_RATE_1G  |
-                         HW_ATL_B0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_10G |
+                         AQ_NIC_RATE_5G |
+                         AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_b0_caps_aqc108 = {
        DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_TP,
-       .link_speed_msk = HW_ATL_B0_RATE_5G  |
-                         HW_ATL_B0_RATE_2G5 |
-                         HW_ATL_B0_RATE_1G  |
-                         HW_ATL_B0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_5G |
+                         AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = {
        DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
        .media_type = AQ_HW_MEDIA_TYPE_TP,
-       .link_speed_msk = HW_ATL_B0_RATE_2G5 |
-                         HW_ATL_B0_RATE_1G  |
-                         HW_ATL_B0_RATE_100M,
+       .link_speed_msk = AQ_NIC_RATE_2GS |
+                         AQ_NIC_RATE_1G |
+                         AQ_NIC_RATE_100M,
 };
 
 static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
index 28568f5..b318eef 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
@@ -67,12 +67,6 @@
 #define HW_ATL_B0_MPI_SPEED_MSK         0xFFFFU
 #define HW_ATL_B0_MPI_SPEED_SHIFT       16U
 
-#define HW_ATL_B0_RATE_10G              BIT(0)
-#define HW_ATL_B0_RATE_5G               BIT(1)
-#define HW_ATL_B0_RATE_2G5              BIT(3)
-#define HW_ATL_B0_RATE_1G               BIT(4)
-#define HW_ATL_B0_RATE_100M             BIT(5)
-
 #define HW_ATL_B0_TXBUF_MAX  160U
 #define HW_ATL_B0_RXBUF_MAX  320U
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index b1a0fb5..436b278 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -912,5 +912,7 @@ const struct aq_fw_ops aq_fw_1x_ops = {
        .update_link_status = hw_atl_utils_mpi_get_link_status,
        .update_stats = hw_atl_utils_update_stats,
        .set_power = aq_fw1x_set_power,
+       .set_eee_rate = NULL,
+       .get_eee_rate = NULL,
        .set_flow_control = NULL,
 };
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 3aceb55..95419e3 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
@@ -171,9 +171,22 @@ struct __packed hw_atl_utils_mbox_header {
        u32 error;
 };
 
+struct __packed hw_aq_info {
+       u8 reserved[6];
+       u16 phy_fault_code;
+       u16 phy_temperature;
+       u8 cable_len;
+       u8 reserved1;
+       u32 cable_diag_data[4];
+       u8 reserved2[32];
+       u32 caps_lo;
+       u32 caps_hi;
+};
+
 struct __packed hw_atl_utils_mbox {
        struct hw_atl_utils_mbox_header header;
        struct hw_atl_stats_s stats;
+       struct hw_aq_info info;
 };
 
 /* fw2x */
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 0ad6ac5..7bd1bea 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
@@ -40,6 +40,11 @@
 #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
 #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT  BIT(CTRL_FORCE_RECONNECT)
 
+#define HW_ATL_FW2X_CAP_EEE_1G_MASK      BIT(CAPS_HI_1000BASET_FD_EEE)
+#define HW_ATL_FW2X_CAP_EEE_2G5_MASK     BIT(CAPS_HI_2P5GBASET_FD_EEE)
+#define HW_ATL_FW2X_CAP_EEE_5G_MASK      BIT(CAPS_HI_5GBASET_FD_EEE)
+#define HW_ATL_FW2X_CAP_EEE_10G_MASK     BIT(CAPS_HI_10GBASET_FD_EEE)
+
 #define HAL_ATLANTIC_WOL_FILTERS_COUNT   8
 #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL  0x0E
 
@@ -115,6 +120,38 @@ static enum hw_atl_fw2x_rate 
link_speed_mask_2fw2x_ratemask(u32 speed)
        return rate;
 }
 
+static u32 fw2x_to_eee_mask(u32 speed)
+{
+       u32 rate = 0;
+
+       if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
+               rate |= AQ_NIC_RATE_EEE_10G;
+       if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
+               rate |= AQ_NIC_RATE_EEE_5G;
+       if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
+               rate |= AQ_NIC_RATE_EEE_2GS;
+       if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
+               rate |= AQ_NIC_RATE_EEE_1G;
+
+       return rate;
+}
+
+static u32 eee_mask_to_fw2x(u32 speed)
+{
+       u32 rate = 0;
+
+       if (speed & AQ_NIC_RATE_EEE_10G)
+               rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
+       if (speed & AQ_NIC_RATE_EEE_5G)
+               rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
+       if (speed & AQ_NIC_RATE_EEE_2GS)
+               rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
+       if (speed & AQ_NIC_RATE_EEE_1G)
+               rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
+
+       return rate;
+}
+
 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
 {
        u32 val = link_speed_mask_2fw2x_ratemask(speed);
@@ -124,31 +161,46 @@ 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);
+       if (fc & AQ_NIC_FC_RX)
+               *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE;
        else
-               *mpi_state &= ~BIT(CAPS_HI_PAUSE);
+               *mpi_state &= ~HW_ATL_FW2X_CTRL_PAUSE;
 
-       if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
-               *mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
+       if (fc & AQ_NIC_FC_TX)
+               *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
        else
-               *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
+               *mpi_state &= ~HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
+}
+
+static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
+                                     u32 eee_speeds)
+{
+       *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
+                      HW_ATL_FW2X_CAP_EEE_2G5_MASK |
+                      HW_ATL_FW2X_CAP_EEE_5G_MASK |
+                      HW_ATL_FW2X_CAP_EEE_10G_MASK);
+
+       *mpi_opts |= eee_mask_to_fw2x(eee_speeds);
 }
 
 static int aq_fw2x_set_state(struct aq_hw_s *self,
                             enum hal_atl_utils_fw_state_e state)
 {
        u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+       struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
 
        switch (state) {
        case MPI_INIT:
-               mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
-               aq_fw2x_set_mpi_flow_control(self, &mpi_state);
+               mpi_state &= ~HW_ATL_FW2X_CTRL_LINK_DROP;
+               aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
+               aq_fw2x_upd_flow_control_bits(self, &mpi_state,
+                                             cfg->flow_control);
                break;
        case MPI_DEINIT:
-               mpi_state |= BIT(CAPS_HI_LINK_DROP);
+               mpi_state |= HW_ATL_FW2X_CTRL_LINK_DROP;
                break;
        case MPI_RESET:
        case MPI_POWER:
@@ -163,7 +215,7 @@ static int aq_fw2x_update_link_status(struct aq_hw_s *self)
 {
        u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
        u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
-                               FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
+                                FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
        struct aq_hw_link_status_s *link_status = &self->aq_link_status;
 
        if (speed) {
@@ -212,9 +264,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, 
u8 *mac)
 
                get_random_bytes(&rnd, sizeof(unsigned int));
 
-               l = 0xE3000000U
-                       | (0xFFFFU & rnd)
-                       | (0x00 << 16);
+               l = 0xE3000000U | (0xFFFFU & rnd) | (0x00 << 16);
                h = 0x8001300EU;
 
                mac[5] = (u8)(0xFFU & l);
@@ -348,11 +398,49 @@ static int aq_fw2x_set_power(struct aq_hw_s *self, 
unsigned int power_state,
        return err;
 }
 
+static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
+{
+       u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+       aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
+
+       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+       return 0;
+}
+
+static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
+                               u32 *supported_rates)
+{
+       int err = 0;
+       u32 caps_hi;
+       u32 mpi_state;
+
+       err =
+       hw_atl_utils_fw_downld_dwords(self,
+                                     self->mbox_addr +
+                                     offsetof(struct hw_atl_utils_mbox,
+                                              info) +
+                                     offsetof(struct hw_aq_info, caps_hi),
+                                     &caps_hi,
+                                     sizeof(caps_hi) / sizeof(u32));
+
+       if (err)
+               return err;
+
+       *supported_rates = fw2x_to_eee_mask(caps_hi);
+
+       mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
+       *rate = fw2x_to_eee_mask(mpi_state);
+
+       return err;
+}
+
 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);
+       mpi_opts |= HW_ATL_FW2X_CTRL_FORCE_RECONNECT;
 
        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 
@@ -363,7 +451,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->flow_control);
 
        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
 
@@ -371,15 +460,17 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 }
 
 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,
+       .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,
        .update_link_status = aq_fw2x_update_link_status,
-       .update_stats = aq_fw2x_update_stats,
-       .set_power = aq_fw2x_set_power,
+       .update_stats       = aq_fw2x_update_stats,
+       .set_power          = aq_fw2x_set_power,
+       .set_eee_rate       = aq_fw2x_set_eee_rate,
+       .get_eee_rate       = aq_fw2x_get_eee_rate,
        .set_flow_control   = aq_fw2x_set_flow_control,
 };
-- 
2.7.4

Reply via email to