From mboxrd@z Thu Jan 1 00:00:00 1970 From: Igor Russkikh Subject: [PATCH net-next 4/5] net: aquantia: implement EEE support Date: Wed, 8 Aug 2018 13:57:14 +0300 Message-ID: <3e548f24d79bc03a14e3b8cdb6708c5db6a61cc4.1533650064.git.igor.russkikh@aquantia.com> References: Mime-Version: 1.0 Content-Type: text/plain Cc: netdev@vger.kernel.org, Igor Russkikh , Yana Esina , Nikita Danilov To: "David S . Miller" Return-path: Received: from mail-bn3nam01on0085.outbound.protection.outlook.com ([104.47.33.85]:19168 "EHLO NAM01-BN3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726733AbeHHNXc (ORCPT ); Wed, 8 Aug 2018 09:23:32 -0400 In-Reply-To: Sender: netdev-owner@vger.kernel.org List-ID: From: Yana Esina 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 Signed-off-by: Nikita Danilov Tested-by: Nikita Danilov Signed-off-by: Igor Russkikh --- 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