]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
net: atlantic: implement phy downshift feature
authorIgor Russkikh <irusskikh@marvell.com>
Mon, 5 Oct 2020 15:39:38 +0000 (18:39 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Oct 2020 13:16:01 +0000 (06:16 -0700)
PHY downshift allows phy to try renegotiate if link is unstable
and can carry higher speed.

AQC devices has integrated PHY which is controlled by MAC firmware.
Thus, driver defines new ethtool callbacks to implement phy tunables
via netdev.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Igor Russkikh <irusskikh@marvell.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/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c

index 1ab5314c4c1b968d1759250841ef68698e237dc1..3f87cc6e2538148dbb5124fd9158a3edd5b991f7 100644 (file)
@@ -917,6 +917,45 @@ static int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags)
        return ret;
 }
 
+static int aq_ethtool_get_phy_tunable(struct net_device *ndev,
+                                     const struct ethtool_tunable *tuna, void *data)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       switch (tuna->id) {
+       case ETHTOOL_PHY_DOWNSHIFT: {
+               u8 *val = data;
+
+               *val = (u8)aq_nic->aq_nic_cfg.downshift_counter;
+               break;
+       }
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int aq_ethtool_set_phy_tunable(struct net_device *ndev,
+                                     const struct ethtool_tunable *tuna, const void *data)
+{
+       int err = -EOPNOTSUPP;
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       switch (tuna->id) {
+       case ETHTOOL_PHY_DOWNSHIFT: {
+               const u8 *val = data;
+
+               err = aq_nic_set_downshift(aq_nic, *val);
+               break;
+       }
+       default:
+               break;
+       }
+
+       return err;
+}
+
 const struct ethtool_ops aq_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES,
@@ -952,4 +991,6 @@ const struct ethtool_ops aq_ethtool_ops = {
        .get_coalesce        = aq_ethtool_get_coalesce,
        .set_coalesce        = aq_ethtool_set_coalesce,
        .get_ts_info         = aq_ethtool_get_ts_info,
+       .get_phy_tunable     = aq_ethtool_get_phy_tunable,
+       .set_phy_tunable     = aq_ethtool_set_phy_tunable,
 };
index 7df74015fbc93e26fbd85d951358b5f79f463e65..a17077b0dd496b9c6323745ea018c315e26fa1bc 100644 (file)
@@ -386,6 +386,8 @@ struct aq_fw_ops {
        int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
                            u32 *supported_rates);
 
+       int (*set_downshift)(struct aq_hw_s *self, u32 counter);
+
        u32 (*get_link_capabilities)(struct aq_hw_s *self);
 
        int (*send_macsec_req)(struct aq_hw_s *self,
index c6bdf1d677d150b896b70cc1500a447721b6ea55..088aa3c3d19c4bf8c1b773f624e1a96a18805621 100644 (file)
@@ -405,6 +405,8 @@ int aq_nic_init(struct aq_nic_s *self)
        mutex_unlock(&self->fwreq_mutex);
        if (err < 0)
                goto err_exit;
+       /* Restore default settings */
+       aq_nic_set_downshift(self, self->aq_nic_cfg.downshift_counter);
 
        err = self->aq_hw_ops->hw_init(self->aq_hw,
                                       aq_nic_get_ndev(self)->dev_addr);
@@ -1398,6 +1400,27 @@ void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type,
        }
 }
 
+int aq_nic_set_downshift(struct aq_nic_s *self, int val)
+{
+       int err = 0;
+       struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
+
+       if (!self->aq_fw_ops->set_downshift)
+               return -EOPNOTSUPP;
+
+       if (val > 15) {
+               netdev_err(self->ndev, "downshift counter should be <= 15\n");
+               return -EINVAL;
+       }
+       cfg->downshift_counter = val;
+
+       mutex_lock(&self->fwreq_mutex);
+       err = self->aq_fw_ops->set_downshift(self->aq_hw, cfg->downshift_counter);
+       mutex_unlock(&self->fwreq_mutex);
+
+       return err;
+}
+
 int aq_nic_setup_tc_mqprio(struct aq_nic_s *self, u32 tcs, u8 *prio_tc_map)
 {
        struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
index eb7d8430f2f58090b3b1182a2063c2f0711fda23..61e0e627e9599eb5bc4744e3f6c2b649823278ee 100644 (file)
@@ -62,6 +62,7 @@ struct aq_nic_cfg_s {
        bool is_lro;
        bool is_qos;
        bool is_ptp;
+       int downshift_counter;
        enum aq_tc_mode tc_mode;
        u32 priv_flags;
        u8  tcs;
@@ -195,6 +196,7 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
 struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
 u32 aq_nic_get_fw_version(struct aq_nic_s *self);
 int aq_nic_set_loopback(struct aq_nic_s *self);
+int aq_nic_set_downshift(struct aq_nic_s *self, int val);
 int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
 void aq_nic_shutdown(struct aq_nic_s *self);
 u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type);
index 93c06dfa6c55400f90229b7c676bd99c9105ecea..09500a95380b818b67c567221af423f8df58b879 100644 (file)
@@ -612,6 +612,27 @@ static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
 }
 
+static int aq_fw2x_set_downshift(struct aq_hw_s *self, u32 counter)
+{
+       int err = 0;
+       u32 mpi_opts;
+       u32 offset;
+
+       offset = offsetof(struct hw_atl_utils_settings, downshift_retry_count);
+       err = hw_atl_write_fwsettings_dwords(self, offset, &counter, 1);
+       if (err)
+               return err;
+
+       mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+       if (counter)
+               mpi_opts |= HW_ATL_FW2X_CTRL_DOWNSHIFT;
+       else
+               mpi_opts &= ~HW_ATL_FW2X_CTRL_DOWNSHIFT;
+       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+       return err;
+}
+
 static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self)
 {
        int err = 0;
@@ -692,6 +713,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
        .enable_ptp         = aq_fw3x_enable_ptp,
        .led_control        = aq_fw2x_led_control,
        .set_phyloopback    = aq_fw2x_set_phyloopback,
+       .set_downshift      = aq_fw2x_set_downshift,
        .adjust_ptp         = aq_fw3x_adjust_ptp,
        .get_link_capabilities = aq_fw2x_get_link_capabilities,
        .send_macsec_req    = aq_fw2x_send_macsec_req,
index 85628acbcc1d66ce7771877b0f7fe784ea03f174..dd259c8f2f4f397adbed0b5ea284bd8881a48735 100644 (file)
@@ -519,6 +519,18 @@ int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self,
        return 0;
 }
 
+static int aq_a2_fw_set_downshift(struct aq_hw_s *self, u32 counter)
+{
+       struct link_options_s link_options;
+
+       hw_atl2_shared_buffer_get(self, link_options, link_options);
+       link_options.downshift = !!counter;
+       link_options.downshift_retry = counter;
+       hw_atl2_shared_buffer_write(self, link_options, link_options);
+
+       return hw_atl2_shared_buffer_finish_ack(self);
+}
+
 const struct aq_fw_ops aq_a2_fw_ops = {
        .init               = aq_a2_fw_init,
        .deinit             = aq_a2_fw_deinit,
@@ -536,4 +548,5 @@ const struct aq_fw_ops aq_a2_fw_ops = {
        .set_flow_control   = aq_a2_fw_set_flow_control,
        .get_flow_control   = aq_a2_fw_get_flow_control,
        .set_phyloopback    = aq_a2_fw_set_phyloopback,
+       .set_downshift      = aq_a2_fw_set_downshift,
 };