]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
net: atlantic: loopback tests via private flags
[linux.git] / drivers / net / ethernet / aquantia / atlantic / aq_ethtool.c
index 24df132384fb613c0fa02719dcc16d821bce3e0e..963bf6e6757395fe365937bea96132f748aa5af2 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
  */
 
 /* File aq_ethtool.c: Definition of ethertool related functions. */
@@ -9,8 +9,11 @@
 #include "aq_ethtool.h"
 #include "aq_nic.h"
 #include "aq_vec.h"
+#include "aq_ptp.h"
 #include "aq_filters.h"
 
+#include <linux/ptp_clock_kernel.h>
+
 static void aq_ethtool_get_regs(struct net_device *ndev,
                                struct ethtool_regs *regs, void *p)
 {
@@ -89,6 +92,14 @@ static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = {
        "Queue[%d] InErrors",
 };
 
+static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = {
+       "DMASystemLoopback",
+       "PKTSystemLoopback",
+       "DMANetworkLoopback",
+       "PHYInternalLoopback",
+       "PHYExternalLoopback",
+};
+
 static void aq_ethtool_stats(struct net_device *ndev,
                             struct ethtool_stats *stats, u64 *data)
 {
@@ -134,7 +145,8 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
        struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
        u8 *p = data;
 
-       if (stringset == ETH_SS_STATS) {
+       switch (stringset) {
+       case ETH_SS_STATS:
                memcpy(p, aq_ethtool_stat_names,
                       sizeof(aq_ethtool_stat_names));
                p = p + sizeof(aq_ethtool_stat_names);
@@ -147,7 +159,41 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
                                p += ETH_GSTRING_LEN;
                        }
                }
+               break;
+       case ETH_SS_PRIV_FLAGS:
+               memcpy(p, aq_ethtool_priv_flag_names,
+                      sizeof(aq_ethtool_priv_flag_names));
+               break;
+       }
+}
+
+static int aq_ethtool_set_phys_id(struct net_device *ndev,
+                                 enum ethtool_phys_id_state state)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+       struct aq_hw_s *hw = aq_nic->aq_hw;
+       int ret = 0;
+
+       if (!aq_nic->aq_fw_ops->led_control)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&aq_nic->fwreq_mutex);
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               ret = aq_nic->aq_fw_ops->led_control(hw, AQ_HW_LED_BLINK |
+                                AQ_HW_LED_BLINK << 2 | AQ_HW_LED_BLINK << 4);
+               break;
+       case ETHTOOL_ID_INACTIVE:
+               ret = aq_nic->aq_fw_ops->led_control(hw, AQ_HW_LED_DEFAULT);
+               break;
+       default:
+               break;
        }
+
+       mutex_unlock(&aq_nic->fwreq_mutex);
+
+       return ret;
 }
 
 static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
@@ -161,6 +207,9 @@ static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
                ret = ARRAY_SIZE(aq_ethtool_stat_names) +
                        cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
                break;
+       case ETH_SS_PRIV_FLAGS:
+               ret = ARRAY_SIZE(aq_ethtool_priv_flag_names);
+               break;
        default:
                ret = -EOPNOTSUPP;
        }
@@ -353,11 +402,8 @@ static void aq_ethtool_get_wol(struct net_device *ndev,
        struct aq_nic_s *aq_nic = netdev_priv(ndev);
        struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
 
-       wol->supported = WAKE_MAGIC;
-       wol->wolopts = 0;
-
-       if (cfg->wol)
-               wol->wolopts |= WAKE_MAGIC;
+       wol->supported = AQ_NIC_WOL_MODES;
+       wol->wolopts = cfg->wol;
 }
 
 static int aq_ethtool_set_wol(struct net_device *ndev,
@@ -368,15 +414,45 @@ static int aq_ethtool_set_wol(struct net_device *ndev,
        struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
        int err = 0;
 
-       if (wol->wolopts & WAKE_MAGIC)
-               cfg->wol |= AQ_NIC_WOL_ENABLED;
-       else
-               cfg->wol &= ~AQ_NIC_WOL_ENABLED;
-       err = device_set_wakeup_enable(&pdev->dev, wol->wolopts);
+       if (wol->wolopts & ~AQ_NIC_WOL_MODES)
+               return -EOPNOTSUPP;
+
+       cfg->wol = wol->wolopts;
+
+       err = device_set_wakeup_enable(&pdev->dev, !!cfg->wol);
 
        return err;
 }
 
+static int aq_ethtool_get_ts_info(struct net_device *ndev,
+                                 struct ethtool_ts_info *info)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       ethtool_op_get_ts_info(ndev, info);
+
+       if (!aq_nic->aq_ptp)
+               return 0;
+
+       info->so_timestamping |=
+               SOF_TIMESTAMPING_TX_HARDWARE |
+               SOF_TIMESTAMPING_RX_HARDWARE |
+               SOF_TIMESTAMPING_RAW_HARDWARE;
+
+       info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+                        BIT(HWTSTAMP_TX_ON);
+
+       info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
+
+       info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+                           BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+                           BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
+
+       info->phc_index = ptp_clock_index(aq_ptp_get_ptp_clock(aq_nic->aq_ptp));
+
+       return 0;
+}
+
 static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
 {
        u32 rate = 0;
@@ -577,12 +653,61 @@ static int aq_set_ringparam(struct net_device *ndev,
        return err;
 }
 
+static u32 aq_get_msg_level(struct net_device *ndev)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       return aq_nic->msg_enable;
+}
+
+static void aq_set_msg_level(struct net_device *ndev, u32 data)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       aq_nic->msg_enable = data;
+}
+
+u32 aq_ethtool_get_priv_flags(struct net_device *ndev)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+       return aq_nic->aq_nic_cfg.priv_flags;
+}
+
+int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags)
+{
+       struct aq_nic_s *aq_nic = netdev_priv(ndev);
+       struct aq_nic_cfg_s *cfg;
+       u32 priv_flags;
+
+       cfg = aq_nic_get_cfg(aq_nic);
+       priv_flags = cfg->priv_flags;
+
+       if (flags & ~AQ_PRIV_FLAGS_MASK)
+               return -EOPNOTSUPP;
+
+       cfg->priv_flags = flags;
+
+       if ((priv_flags ^ flags) & BIT(AQ_HW_LOOPBACK_DMA_NET)) {
+               if (netif_running(ndev)) {
+                       dev_close(ndev);
+
+                       dev_open(ndev, NULL);
+               }
+       } else if ((priv_flags ^ flags) & AQ_HW_LOOPBACK_MASK) {
+               aq_nic_set_loopback(aq_nic);
+       }
+
+       return 0;
+}
+
 const struct ethtool_ops aq_ethtool_ops = {
        .get_link            = aq_ethtool_get_link,
        .get_regs_len        = aq_ethtool_get_regs_len,
        .get_regs            = aq_ethtool_get_regs,
        .get_drvinfo         = aq_ethtool_get_drvinfo,
        .get_strings         = aq_ethtool_get_strings,
+       .set_phys_id         = aq_ethtool_set_phys_id,
        .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
        .get_wol             = aq_ethtool_get_wol,
        .set_wol             = aq_ethtool_set_wol,
@@ -598,10 +723,15 @@ const struct ethtool_ops aq_ethtool_ops = {
        .set_rxfh            = aq_ethtool_set_rss,
        .get_rxnfc           = aq_ethtool_get_rxnfc,
        .set_rxnfc           = aq_ethtool_set_rxnfc,
+       .get_msglevel        = aq_get_msg_level,
+       .set_msglevel        = aq_set_msg_level,
        .get_sset_count      = aq_ethtool_get_sset_count,
        .get_ethtool_stats   = aq_ethtool_stats,
+       .get_priv_flags      = aq_ethtool_get_priv_flags,
+       .set_priv_flags      = aq_ethtool_set_priv_flags,
        .get_link_ksettings  = aq_ethtool_get_link_ksettings,
        .set_link_ksettings  = aq_ethtool_set_link_ksettings,
        .get_coalesce        = aq_ethtool_get_coalesce,
        .set_coalesce        = aq_ethtool_set_coalesce,
+       .get_ts_info         = aq_ethtool_get_ts_info,
 };