From: Nikita Danilov <ndani...@marvell.com>

This patch adds EEE support on A2.

Signed-off-by: Nikita Danilov <ndani...@marvell.com>
Co-developed-by: Igor Russkikh <irussk...@marvell.com>
Signed-off-by: Igor Russkikh <irussk...@marvell.com>
---
 .../ethernet/aquantia/atlantic/aq_common.h    |  5 ++
 .../ethernet/aquantia/atlantic/aq_ethtool.c   | 11 +--
 .../atlantic/hw_atl2/hw_atl2_utils_fw.c       | 80 +++++++++++++++++++
 3 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index 1587528ca3f6..23b2d390fcdd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -67,5 +67,10 @@
 #define AQ_NIC_RATE_EEE_2G5    BIT(12)
 #define AQ_NIC_RATE_EEE_1G     BIT(13)
 #define AQ_NIC_RATE_EEE_100M   BIT(14)
+#define AQ_NIC_RATE_EEE_MSK     (AQ_NIC_RATE_EEE_10G |\
+                                AQ_NIC_RATE_EEE_5G |\
+                                AQ_NIC_RATE_EEE_2G5 |\
+                                AQ_NIC_RATE_EEE_1G |\
+                                AQ_NIC_RATE_EEE_100M)
 
 #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 ffcdda70265b..8225187eeef2 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -1,7 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/*
- * aQuantia Corporation Network Driver
- * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
+/* Atlantic Network Driver
+ *
+ * Copyright (C) 2014-2019 aQuantia Corporation
+ * Copyright (C) 2019-2020 Marvell International Ltd.
  */
 
 /* File aq_ethtool.c: Definition of ethertool related functions. */
@@ -611,7 +612,7 @@ static int aq_ethtool_get_ts_info(struct net_device *ndev,
        return 0;
 }
 
-static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
+static u32 eee_mask_to_ethtool_mask(u32 speed)
 {
        u32 rate = 0;
 
@@ -653,7 +654,7 @@ static int aq_ethtool_get_eee(struct net_device *ndev, 
struct ethtool_eee *eee)
        eee->eee_enabled = !!eee->advertised;
 
        eee->tx_lpi_enabled = eee->eee_enabled;
-       if (eee->advertised & eee->lp_advertised)
+       if ((supported_rates & rate) & AQ_NIC_RATE_EEE_MSK)
                eee->eee_active = true;
 
        return 0;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
index d64dfae8803e..9216517f6e65 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
@@ -7,6 +7,7 @@
 
 #include "aq_hw.h"
 #include "aq_hw_utils.h"
+#include "aq_nic.h"
 #include "hw_atl/hw_atl_llh.h"
 #include "hw_atl2_utils.h"
 #include "hw_atl2_llh.h"
@@ -141,6 +142,42 @@ static void a2_link_speed_mask2fw(u32 speed,
        link_options->rate_10M_hd = !!(speed & AQ_NIC_RATE_10M_HALF);
 }
 
+static u32 a2_fw_dev_to_eee_mask(struct device_link_caps_s *device_link_caps)
+{
+       u32 rate = 0;
+
+       if (device_link_caps->eee_10G)
+               rate |= AQ_NIC_RATE_EEE_10G;
+       if (device_link_caps->eee_5G)
+               rate |= AQ_NIC_RATE_EEE_5G;
+       if (device_link_caps->eee_2P5G)
+               rate |= AQ_NIC_RATE_EEE_2G5;
+       if (device_link_caps->eee_1G)
+               rate |= AQ_NIC_RATE_EEE_1G;
+       if (device_link_caps->eee_100M)
+               rate |= AQ_NIC_RATE_EEE_100M;
+
+       return rate;
+}
+
+static u32 a2_fw_lkp_to_mask(struct lkp_link_caps_s *lkp_link_caps)
+{
+       u32 rate = 0;
+
+       if (lkp_link_caps->eee_10G)
+               rate |= AQ_NIC_RATE_EEE_10G;
+       if (lkp_link_caps->eee_5G)
+               rate |= AQ_NIC_RATE_EEE_5G;
+       if (lkp_link_caps->eee_2P5G)
+               rate |= AQ_NIC_RATE_EEE_2G5;
+       if (lkp_link_caps->eee_1G)
+               rate |= AQ_NIC_RATE_EEE_1G;
+       if (lkp_link_caps->eee_100M)
+               rate |= AQ_NIC_RATE_EEE_100M;
+
+       return rate;
+}
+
 static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed)
 {
        struct link_options_s link_options;
@@ -153,6 +190,17 @@ static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, 
u32 speed)
        return hw_atl2_shared_buffer_finish_ack(self);
 }
 
+static void aq_a2_fw_upd_eee_rate_bits(struct aq_hw_s *self,
+                                      struct link_options_s *link_options,
+                                      u32 eee_speeds)
+{
+       link_options->eee_10G =  !!(eee_speeds & AQ_NIC_RATE_EEE_10G);
+       link_options->eee_5G = !!(eee_speeds & AQ_NIC_RATE_EEE_5G);
+       link_options->eee_2P5G = !!(eee_speeds & AQ_NIC_RATE_EEE_2G5);
+       link_options->eee_1G = !!(eee_speeds & AQ_NIC_RATE_EEE_1G);
+       link_options->eee_100M = !!(eee_speeds & AQ_NIC_RATE_EEE_100M);
+}
+
 static int aq_a2_fw_set_state(struct aq_hw_s *self,
                              enum hal_atl_utils_fw_state_e state)
 {
@@ -163,6 +211,8 @@ static int aq_a2_fw_set_state(struct aq_hw_s *self,
        switch (state) {
        case MPI_INIT:
                link_options.link_up = 1U;
+               aq_a2_fw_upd_eee_rate_bits(self, &link_options,
+                                          self->aq_nic_cfg->eee_speeds);
                break;
        case MPI_DEINIT:
                link_options.link_up = 0U;
@@ -265,6 +315,34 @@ static int aq_a2_fw_update_stats(struct aq_hw_s *self)
        return 0;
 }
 
+static int aq_a2_fw_set_eee_rate(struct aq_hw_s *self, u32 speed)
+{
+       struct link_options_s link_options;
+
+       hw_atl2_shared_buffer_get(self, link_options, link_options);
+
+       aq_a2_fw_upd_eee_rate_bits(self, &link_options, speed);
+
+       hw_atl2_shared_buffer_write(self, link_options, link_options);
+
+       return hw_atl2_shared_buffer_finish_ack(self);
+}
+
+static int aq_a2_fw_get_eee_rate(struct aq_hw_s *self, u32 *rate,
+                                u32 *supported_rates)
+{
+       struct device_link_caps_s device_link_caps;
+       struct lkp_link_caps_s lkp_link_caps;
+
+       hw_atl2_shared_buffer_read(self, device_link_caps, device_link_caps);
+       hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps);
+
+       *supported_rates = a2_fw_dev_to_eee_mask(&device_link_caps);
+       *rate = a2_fw_lkp_to_mask(&lkp_link_caps);
+
+       return 0;
+}
+
 static int aq_a2_fw_renegotiate(struct aq_hw_s *self)
 {
        struct link_options_s link_options;
@@ -322,4 +400,6 @@ const struct aq_fw_ops aq_a2_fw_ops = {
        .set_state          = aq_a2_fw_set_state,
        .update_link_status = aq_a2_fw_update_link_status,
        .update_stats       = aq_a2_fw_update_stats,
+       .set_eee_rate       = aq_a2_fw_set_eee_rate,
+       .get_eee_rate       = aq_a2_fw_get_eee_rate,
 };
-- 
2.25.1

Reply via email to