From e636c8d336489bf3eed5878299e6cc045bbad077 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:17:29 +0000
Subject: [PATCH] debug lk
---
kernel/drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 678 ++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 458 insertions(+), 220 deletions(-)
diff --git a/kernel/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/kernel/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index 19652cd..db104e0 100644
--- a/kernel/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/kernel/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -1,34 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
/* QLogic qede NIC Driver
* Copyright (c) 2015-2017 QLogic Corporation
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and /or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
+ * Copyright (c) 2019-2020 Marvell International Ltd.
*/
+
#include <linux/version.h>
#include <linux/types.h>
#include <linux/netdevice.h>
@@ -38,6 +13,8 @@
#include <linux/pci.h>
#include <linux/capability.h>
#include <linux/vmalloc.h>
+#include <linux/phylink.h>
+
#include "qede.h"
#include "qede_ptp.h"
@@ -48,6 +25,8 @@
{QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)}
#define QEDE_SELFTEST_POLL_COUNT 100
+#define QEDE_DUMP_VERSION 0x1
+#define QEDE_DUMP_NVM_ARG_COUNT 2
static const struct {
u64 offset;
@@ -73,6 +52,7 @@
} qede_tqstats_arr[] = {
QEDE_TQSTAT(xmit_pkts),
QEDE_TQSTAT(stopped_cnt),
+ QEDE_TQSTAT(tx_mem_alloc_err),
};
#define QEDE_STAT_OFFSET(stat_name, type, base) \
@@ -173,6 +153,7 @@
QEDE_STAT(coalesced_bytes),
QEDE_STAT(link_change_count),
+ QEDE_STAT(ptp_skip_txts),
};
#define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr)
@@ -185,11 +166,15 @@
enum {
QEDE_PRI_FLAG_CMT,
+ QEDE_PRI_FLAG_SMART_AN_SUPPORT, /* MFW supports SmartAN */
+ QEDE_PRI_FLAG_RECOVER_ON_ERROR,
QEDE_PRI_FLAG_LEN,
};
static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
"Coupled-Function",
+ "SmartAN capable",
+ "Recover on error",
};
enum qede_ethtool_tests {
@@ -210,6 +195,96 @@
"Clock (online)\t\t",
"Nvram (online)\t\t",
};
+
+/* Forced speed capabilities maps */
+
+struct qede_forced_speed_map {
+ u32 speed;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(caps);
+
+ const u32 *cap_arr;
+ u32 arr_size;
+};
+
+#define QEDE_FORCED_SPEED_MAP(value) \
+{ \
+ .speed = SPEED_##value, \
+ .cap_arr = qede_forced_speed_##value, \
+ .arr_size = ARRAY_SIZE(qede_forced_speed_##value), \
+}
+
+static const u32 qede_forced_speed_1000[] __initconst = {
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+};
+
+static const u32 qede_forced_speed_10000[] __initconst = {
+ ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
+ ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+};
+
+static const u32 qede_forced_speed_20000[] __initconst = {
+ ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
+};
+
+static const u32 qede_forced_speed_25000[] __initconst = {
+ ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+};
+
+static const u32 qede_forced_speed_40000[] __initconst = {
+ ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
+ ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+ ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+ ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
+};
+
+static const u32 qede_forced_speed_50000[] __initconst = {
+ ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+};
+
+static const u32 qede_forced_speed_100000[] __initconst = {
+ ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+};
+
+static struct qede_forced_speed_map qede_forced_speed_maps[] __ro_after_init = {
+ QEDE_FORCED_SPEED_MAP(1000),
+ QEDE_FORCED_SPEED_MAP(10000),
+ QEDE_FORCED_SPEED_MAP(20000),
+ QEDE_FORCED_SPEED_MAP(25000),
+ QEDE_FORCED_SPEED_MAP(40000),
+ QEDE_FORCED_SPEED_MAP(50000),
+ QEDE_FORCED_SPEED_MAP(100000),
+};
+
+void __init qede_forced_speed_maps_init(void)
+{
+ struct qede_forced_speed_map *map;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) {
+ map = qede_forced_speed_maps + i;
+
+ linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps);
+ map->cap_arr = NULL;
+ map->arr_size = 0;
+ }
+}
+
+/* Ethtool callbacks */
static void qede_get_strings_stats_txq(struct qede_dev *edev,
struct qede_tx_queue *txq, u8 **buf)
@@ -351,6 +426,8 @@
}
}
+ spin_lock(&edev->stats_lock);
+
for (i = 0; i < QEDE_NUM_STATS; i++) {
if (qede_is_irrelevant_stat(edev, i))
continue;
@@ -359,6 +436,8 @@
buf++;
}
+
+ spin_unlock(&edev->stats_lock);
__qede_unlock(edev);
}
@@ -403,55 +482,42 @@
static u32 qede_get_priv_flags(struct net_device *dev)
{
struct qede_dev *edev = netdev_priv(dev);
+ u32 flags = 0;
- return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT;
+ if (edev->dev_info.common.num_hwfns > 1)
+ flags |= BIT(QEDE_PRI_FLAG_CMT);
+
+ if (edev->dev_info.common.smart_an)
+ flags |= BIT(QEDE_PRI_FLAG_SMART_AN_SUPPORT);
+
+ if (edev->err_flags & BIT(QEDE_ERR_IS_RECOVERABLE))
+ flags |= BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR);
+
+ return flags;
}
-struct qede_link_mode_mapping {
- u32 qed_link_mode;
- u32 ethtool_link_mode;
-};
+static int qede_set_priv_flags(struct net_device *dev, u32 flags)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+ u32 cflags = qede_get_priv_flags(dev);
+ u32 dflags = flags ^ cflags;
-static const struct qede_link_mode_mapping qed_lm_map[] = {
- {QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
- {QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
- {QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
- {QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
- {QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
- {QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
- {QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
- {QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
- {QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
- {QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
- {QED_LM_100000baseKR4_Full_BIT,
- ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
-};
+ /* can only change RECOVER_ON_ERROR flag */
+ if (dflags & ~BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR))
+ return -EINVAL;
-#define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name) \
-{ \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) { \
- if ((caps) & (qed_lm_map[i].qed_link_mode)) \
- __set_bit(qed_lm_map[i].ethtool_link_mode,\
- lk_ksettings->link_modes.name); \
- } \
-}
+ if (flags & BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR))
+ set_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags);
+ else
+ clear_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags);
-#define QEDE_ETHTOOL_TO_DRV_CAPS(caps, lk_ksettings, name) \
-{ \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) { \
- if (test_bit(qed_lm_map[i].ethtool_link_mode, \
- lk_ksettings->link_modes.name)) \
- caps |= qed_lm_map[i].qed_link_mode; \
- } \
+ return 0;
}
static int qede_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
+ typeof(cmd->link_modes) *link_modes = &cmd->link_modes;
struct ethtool_link_settings *base = &cmd->base;
struct qede_dev *edev = netdev_priv(dev);
struct qed_link_output current_link;
@@ -461,14 +527,9 @@
memset(¤t_link, 0, sizeof(current_link));
edev->ops->common->get_link(edev->cdev, ¤t_link);
- ethtool_link_ksettings_zero_link_mode(cmd, supported);
- QEDE_DRV_TO_ETHTOOL_CAPS(current_link.supported_caps, cmd, supported)
-
- ethtool_link_ksettings_zero_link_mode(cmd, advertising);
- QEDE_DRV_TO_ETHTOOL_CAPS(current_link.advertised_caps, cmd, advertising)
-
- ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
- QEDE_DRV_TO_ETHTOOL_CAPS(current_link.lp_caps, cmd, lp_advertising)
+ linkmode_copy(link_modes->supported, current_link.supported_caps);
+ linkmode_copy(link_modes->advertising, current_link.advertised_caps);
+ linkmode_copy(link_modes->lp_advertising, current_link.lp_caps);
if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) {
base->speed = current_link.speed;
@@ -492,8 +553,10 @@
{
const struct ethtool_link_settings *base = &cmd->base;
struct qede_dev *edev = netdev_priv(dev);
+ const struct qede_forced_speed_map *map;
struct qed_link_output current_link;
struct qed_link_params params;
+ u32 i;
if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
DP_INFO(edev, "Link settings are not allowed to be changed\n");
@@ -505,74 +568,40 @@
params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS;
params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG;
+
if (base->autoneg == AUTONEG_ENABLE) {
- if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
+ if (!phylink_test(current_link.supported_caps, Autoneg)) {
DP_INFO(edev, "Auto negotiation is not supported\n");
return -EOPNOTSUPP;
}
params.autoneg = true;
params.forced_speed = 0;
- QEDE_ETHTOOL_TO_DRV_CAPS(params.adv_speeds, cmd, advertising)
+
+ linkmode_copy(params.adv_speeds, cmd->link_modes.advertising);
} else { /* forced speed */
params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED;
params.autoneg = false;
params.forced_speed = base->speed;
- switch (base->speed) {
- case SPEED_1000:
- if (!(current_link.supported_caps &
- QED_LM_1000baseT_Full_BIT)) {
- DP_INFO(edev, "1G speed not supported\n");
- return -EINVAL;
- }
- params.adv_speeds = QED_LM_1000baseT_Full_BIT;
- break;
- case SPEED_10000:
- if (!(current_link.supported_caps &
- QED_LM_10000baseKR_Full_BIT)) {
- DP_INFO(edev, "10G speed not supported\n");
- return -EINVAL;
- }
- params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
- break;
- case SPEED_25000:
- if (!(current_link.supported_caps &
- QED_LM_25000baseKR_Full_BIT)) {
- DP_INFO(edev, "25G speed not supported\n");
- return -EINVAL;
- }
- params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
- break;
- case SPEED_40000:
- if (!(current_link.supported_caps &
- QED_LM_40000baseLR4_Full_BIT)) {
- DP_INFO(edev, "40G speed not supported\n");
- return -EINVAL;
- }
- params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
- break;
- case SPEED_50000:
- if (!(current_link.supported_caps &
- QED_LM_50000baseKR2_Full_BIT)) {
- DP_INFO(edev, "50G speed not supported\n");
- return -EINVAL;
- }
- params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
- break;
- case SPEED_100000:
- if (!(current_link.supported_caps &
- QED_LM_100000baseKR4_Full_BIT)) {
- DP_INFO(edev, "100G speed not supported\n");
- return -EINVAL;
- }
- params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
- break;
- default:
- DP_INFO(edev, "Unsupported speed %u\n", base->speed);
- return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) {
+ map = qede_forced_speed_maps + i;
+
+ if (base->speed != map->speed ||
+ !linkmode_intersects(current_link.supported_caps,
+ map->caps))
+ continue;
+
+ linkmode_and(params.adv_speeds,
+ current_link.supported_caps, map->caps);
+ goto set_link;
}
+
+ DP_INFO(edev, "Unsupported speed %u\n", base->speed);
+ return -EINVAL;
}
+set_link:
params.link_up = true;
edev->ops->common->set_link(edev->cdev, ¶ms);
@@ -584,9 +613,9 @@
{
char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN];
struct qede_dev *edev = netdev_priv(ndev);
+ char mbi[ETHTOOL_FWVERS_LEN];
strlcpy(info->driver, "qede", sizeof(info->driver));
- strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
edev->dev_info.common.fw_major,
@@ -600,13 +629,27 @@
(edev->dev_info.common.mfw_rev >> 8) & 0xFF,
edev->dev_info.common.mfw_rev & 0xFF);
- if ((strlen(storm) + strlen(mfw) + strlen("mfw storm ")) <
- sizeof(info->fw_version)) {
+ if ((strlen(storm) + strlen(DRV_MODULE_VERSION) + strlen("[storm] ")) <
+ sizeof(info->version))
+ snprintf(info->version, sizeof(info->version),
+ "%s [storm %s]", DRV_MODULE_VERSION, storm);
+ else
+ snprintf(info->version, sizeof(info->version),
+ "%s %s", DRV_MODULE_VERSION, storm);
+
+ if (edev->dev_info.common.mbi_version) {
+ snprintf(mbi, ETHTOOL_FWVERS_LEN, "%d.%d.%d",
+ (edev->dev_info.common.mbi_version &
+ QED_MBI_VERSION_2_MASK) >> QED_MBI_VERSION_2_OFFSET,
+ (edev->dev_info.common.mbi_version &
+ QED_MBI_VERSION_1_MASK) >> QED_MBI_VERSION_1_OFFSET,
+ (edev->dev_info.common.mbi_version &
+ QED_MBI_VERSION_0_MASK) >> QED_MBI_VERSION_0_OFFSET);
snprintf(info->fw_version, sizeof(info->fw_version),
- "mfw %s storm %s", mfw, storm);
+ "mbi %s [mfw %s]", mbi, mfw);
} else {
snprintf(info->fw_version, sizeof(info->fw_version),
- "%s %s", mfw, storm);
+ "mfw %s", mfw);
}
strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info));
@@ -776,6 +819,7 @@
coal->rx_coalesce_usecs = rx_coal;
coal->tx_coalesce_usecs = tx_coal;
+ coal->stats_block_coalesce_usecs = edev->stats_coal_usecs;
return rc;
}
@@ -787,6 +831,19 @@
struct qede_fastpath *fp;
int i, rc = 0;
u16 rxc, txc;
+
+ if (edev->stats_coal_usecs != coal->stats_block_coalesce_usecs) {
+ edev->stats_coal_usecs = coal->stats_block_coalesce_usecs;
+ if (edev->stats_coal_usecs) {
+ edev->stats_coal_ticks = usecs_to_jiffies(edev->stats_coal_usecs);
+ schedule_delayed_work(&edev->periodic_task, 0);
+
+ DP_INFO(edev, "Configured stats coal ticks=%lu jiffies\n",
+ edev->stats_coal_ticks);
+ } else {
+ cancel_delayed_work_sync(&edev->periodic_task);
+ }
+ }
if (!netif_running(dev)) {
DP_INFO(edev, "Interface is down\n");
@@ -922,13 +979,16 @@
memset(¶ms, 0, sizeof(params));
params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG;
+
if (epause->autoneg) {
- if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
+ if (!phylink_test(current_link.supported_caps, Autoneg)) {
DP_INFO(edev, "autoneg not supported\n");
return -EINVAL;
}
+
params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
}
+
if (epause->rx_pause)
params.pause_config |= QED_LINK_PAUSE_RX_ENABLE;
if (epause->tx_pause)
@@ -984,7 +1044,9 @@
args.u.mtu = new_mtu;
args.func = &qede_update_mtu;
qede_reload(edev, &args, false);
-
+#if IS_ENABLED(CONFIG_QED_RDMA)
+ qede_rdma_event_change_mtu(edev);
+#endif
edev->ops->common->update_mtu(edev->cdev, new_mtu);
return 0;
@@ -1458,14 +1520,6 @@
barrier();
writel(txq->tx_db.raw, txq->doorbell_addr);
- /* mmiowb is needed to synchronize doorbell writes from more than one
- * processor. It guarantees that the write arrives to the device before
- * the queue lock is released and another start_xmit is called (possibly
- * on another CPU). Without this barrier, the next doorbell can bypass
- * this doorbell. This is applicable to IA64/Altix systems.
- */
- mmiowb();
-
for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
if (qede_txq_has_work(txq))
break;
@@ -1488,7 +1542,7 @@
static int qede_selftest_receive_traffic(struct qede_dev *edev)
{
- u16 hw_comp_cons, sw_comp_cons, sw_rx_index, len;
+ u16 sw_rx_index, len;
struct eth_fast_path_rx_reg_cqe *fp_cqe;
struct qede_rx_queue *rxq = NULL;
struct sw_rx_data *sw_rx_data;
@@ -1517,17 +1571,6 @@
usleep_range(100, 200);
continue;
}
-
- hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
- sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
-
- /* Memory barrier to prevent the CPU from doing speculative
- * reads of CQE/BD before reading hw_comp_cons. If the CQE is
- * read before it is written by FW, then FW writes CQE and SB,
- * and then the CPU reads the hw_comp_cons, it will use an old
- * CQE.
- */
- rmb();
/* Get the CQE from the completion ring */
cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
@@ -1595,8 +1638,11 @@
/* Wait for loopback configuration to apply */
msleep_interruptible(500);
- /* prepare the loopback packet */
- pkt_size = edev->ndev->mtu + ETH_HLEN;
+ /* Setting max packet size to 1.5K to avoid data being split over
+ * multiple BDs in cases where MTU > PAGE_SIZE.
+ */
+ pkt_size = (((edev->ndev->mtu < ETH_DATA_LEN) ?
+ edev->ndev->mtu : ETH_DATA_LEN) + ETH_HLEN);
skb = netdev_alloc_skb(edev->ndev, pkt_size);
if (!skb) {
@@ -1808,6 +1854,78 @@
return 0;
}
+static u32 qede_link_to_ethtool_fec(u32 link_fec)
+{
+ u32 eth_fec = 0;
+
+ if (link_fec & QED_FEC_MODE_NONE)
+ eth_fec |= ETHTOOL_FEC_OFF;
+ if (link_fec & QED_FEC_MODE_FIRECODE)
+ eth_fec |= ETHTOOL_FEC_BASER;
+ if (link_fec & QED_FEC_MODE_RS)
+ eth_fec |= ETHTOOL_FEC_RS;
+ if (link_fec & QED_FEC_MODE_AUTO)
+ eth_fec |= ETHTOOL_FEC_AUTO;
+ if (link_fec & QED_FEC_MODE_UNSUPPORTED)
+ eth_fec |= ETHTOOL_FEC_NONE;
+
+ return eth_fec;
+}
+
+static u32 qede_ethtool_to_link_fec(u32 eth_fec)
+{
+ u32 link_fec = 0;
+
+ if (eth_fec & ETHTOOL_FEC_OFF)
+ link_fec |= QED_FEC_MODE_NONE;
+ if (eth_fec & ETHTOOL_FEC_BASER)
+ link_fec |= QED_FEC_MODE_FIRECODE;
+ if (eth_fec & ETHTOOL_FEC_RS)
+ link_fec |= QED_FEC_MODE_RS;
+ if (eth_fec & ETHTOOL_FEC_AUTO)
+ link_fec |= QED_FEC_MODE_AUTO;
+ if (eth_fec & ETHTOOL_FEC_NONE)
+ link_fec |= QED_FEC_MODE_UNSUPPORTED;
+
+ return link_fec;
+}
+
+static int qede_get_fecparam(struct net_device *dev,
+ struct ethtool_fecparam *fecparam)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+ struct qed_link_output curr_link;
+
+ memset(&curr_link, 0, sizeof(curr_link));
+ edev->ops->common->get_link(edev->cdev, &curr_link);
+
+ fecparam->active_fec = qede_link_to_ethtool_fec(curr_link.active_fec);
+ fecparam->fec = qede_link_to_ethtool_fec(curr_link.sup_fec);
+
+ return 0;
+}
+
+static int qede_set_fecparam(struct net_device *dev,
+ struct ethtool_fecparam *fecparam)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+ struct qed_link_params params;
+
+ if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
+ DP_INFO(edev, "Link settings are not allowed to be changed\n");
+ return -EOPNOTSUPP;
+ }
+
+ memset(¶ms, 0, sizeof(params));
+ params.override_flags |= QED_LINK_OVERRIDE_FEC_CONFIG;
+ params.fec = qede_ethtool_to_link_fec(fecparam->fec);
+ params.link_up = true;
+
+ edev->ops->common->set_link(edev->cdev, ¶ms);
+
+ return 0;
+}
+
static int qede_get_module_info(struct net_device *dev,
struct ethtool_modinfo *modinfo)
{
@@ -1894,73 +2012,193 @@
return rc;
}
-static const struct ethtool_ops qede_ethtool_ops = {
- .get_link_ksettings = qede_get_link_ksettings,
- .set_link_ksettings = qede_set_link_ksettings,
- .get_drvinfo = qede_get_drvinfo,
- .get_regs_len = qede_get_regs_len,
- .get_regs = qede_get_regs,
- .get_wol = qede_get_wol,
- .set_wol = qede_set_wol,
- .get_msglevel = qede_get_msglevel,
- .set_msglevel = qede_set_msglevel,
- .nway_reset = qede_nway_reset,
- .get_link = qede_get_link,
- .get_coalesce = qede_get_coalesce,
- .set_coalesce = qede_set_coalesce,
- .get_ringparam = qede_get_ringparam,
- .set_ringparam = qede_set_ringparam,
- .get_pauseparam = qede_get_pauseparam,
- .set_pauseparam = qede_set_pauseparam,
- .get_strings = qede_get_strings,
- .set_phys_id = qede_set_phys_id,
- .get_ethtool_stats = qede_get_ethtool_stats,
- .get_priv_flags = qede_get_priv_flags,
- .get_sset_count = qede_get_sset_count,
- .get_rxnfc = qede_get_rxnfc,
- .set_rxnfc = qede_set_rxnfc,
- .get_rxfh_indir_size = qede_get_rxfh_indir_size,
- .get_rxfh_key_size = qede_get_rxfh_key_size,
- .get_rxfh = qede_get_rxfh,
- .set_rxfh = qede_set_rxfh,
- .get_ts_info = qede_get_ts_info,
- .get_channels = qede_get_channels,
- .set_channels = qede_set_channels,
- .self_test = qede_self_test,
- .get_module_info = qede_get_module_info,
- .get_module_eeprom = qede_get_module_eeprom,
- .get_eee = qede_get_eee,
- .set_eee = qede_set_eee,
+static int qede_set_dump(struct net_device *dev, struct ethtool_dump *val)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+ int rc = 0;
- .get_tunable = qede_get_tunable,
- .set_tunable = qede_set_tunable,
- .flash_device = qede_flash_device,
+ if (edev->dump_info.cmd == QEDE_DUMP_CMD_NONE) {
+ if (val->flag > QEDE_DUMP_CMD_MAX) {
+ DP_ERR(edev, "Invalid command %d\n", val->flag);
+ return -EINVAL;
+ }
+ edev->dump_info.cmd = val->flag;
+ edev->dump_info.num_args = 0;
+ return 0;
+ }
+
+ if (edev->dump_info.num_args == QEDE_DUMP_MAX_ARGS) {
+ DP_ERR(edev, "Arg count = %d\n", edev->dump_info.num_args);
+ return -EINVAL;
+ }
+
+ switch (edev->dump_info.cmd) {
+ case QEDE_DUMP_CMD_NVM_CFG:
+ edev->dump_info.args[edev->dump_info.num_args] = val->flag;
+ edev->dump_info.num_args++;
+ break;
+ case QEDE_DUMP_CMD_GRCDUMP:
+ rc = edev->ops->common->set_grc_config(edev->cdev,
+ val->flag, 1);
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static int qede_get_dump_flag(struct net_device *dev,
+ struct ethtool_dump *dump)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+
+ if (!edev->ops || !edev->ops->common) {
+ DP_ERR(edev, "Edev ops not populated\n");
+ return -EINVAL;
+ }
+
+ dump->version = QEDE_DUMP_VERSION;
+ switch (edev->dump_info.cmd) {
+ case QEDE_DUMP_CMD_NVM_CFG:
+ dump->flag = QEDE_DUMP_CMD_NVM_CFG;
+ dump->len = edev->ops->common->read_nvm_cfg_len(edev->cdev,
+ edev->dump_info.args[0]);
+ break;
+ case QEDE_DUMP_CMD_GRCDUMP:
+ dump->flag = QEDE_DUMP_CMD_GRCDUMP;
+ dump->len = edev->ops->common->dbg_all_data_size(edev->cdev);
+ break;
+ default:
+ DP_ERR(edev, "Invalid cmd = %d\n", edev->dump_info.cmd);
+ return -EINVAL;
+ }
+
+ DP_VERBOSE(edev, QED_MSG_DEBUG,
+ "dump->version = 0x%x dump->flag = %d dump->len = %d\n",
+ dump->version, dump->flag, dump->len);
+ return 0;
+}
+
+static int qede_get_dump_data(struct net_device *dev,
+ struct ethtool_dump *dump, void *buf)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+ int rc = 0;
+
+ if (!edev->ops || !edev->ops->common) {
+ DP_ERR(edev, "Edev ops not populated\n");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ switch (edev->dump_info.cmd) {
+ case QEDE_DUMP_CMD_NVM_CFG:
+ if (edev->dump_info.num_args != QEDE_DUMP_NVM_ARG_COUNT) {
+ DP_ERR(edev, "Arg count = %d required = %d\n",
+ edev->dump_info.num_args,
+ QEDE_DUMP_NVM_ARG_COUNT);
+ rc = -EINVAL;
+ goto err;
+ }
+ rc = edev->ops->common->read_nvm_cfg(edev->cdev, (u8 **)&buf,
+ edev->dump_info.args[0],
+ edev->dump_info.args[1]);
+ break;
+ case QEDE_DUMP_CMD_GRCDUMP:
+ memset(buf, 0, dump->len);
+ rc = edev->ops->common->dbg_all_data(edev->cdev, buf);
+ break;
+ default:
+ DP_ERR(edev, "Invalid cmd = %d\n", edev->dump_info.cmd);
+ rc = -EINVAL;
+ break;
+ }
+
+err:
+ edev->dump_info.cmd = QEDE_DUMP_CMD_NONE;
+ edev->dump_info.num_args = 0;
+ memset(edev->dump_info.args, 0, sizeof(edev->dump_info.args));
+
+ return rc;
+}
+
+static const struct ethtool_ops qede_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_STATS_BLOCK_USECS,
+ .get_link_ksettings = qede_get_link_ksettings,
+ .set_link_ksettings = qede_set_link_ksettings,
+ .get_drvinfo = qede_get_drvinfo,
+ .get_regs_len = qede_get_regs_len,
+ .get_regs = qede_get_regs,
+ .get_wol = qede_get_wol,
+ .set_wol = qede_set_wol,
+ .get_msglevel = qede_get_msglevel,
+ .set_msglevel = qede_set_msglevel,
+ .nway_reset = qede_nway_reset,
+ .get_link = qede_get_link,
+ .get_coalesce = qede_get_coalesce,
+ .set_coalesce = qede_set_coalesce,
+ .get_ringparam = qede_get_ringparam,
+ .set_ringparam = qede_set_ringparam,
+ .get_pauseparam = qede_get_pauseparam,
+ .set_pauseparam = qede_set_pauseparam,
+ .get_strings = qede_get_strings,
+ .set_phys_id = qede_set_phys_id,
+ .get_ethtool_stats = qede_get_ethtool_stats,
+ .get_priv_flags = qede_get_priv_flags,
+ .set_priv_flags = qede_set_priv_flags,
+ .get_sset_count = qede_get_sset_count,
+ .get_rxnfc = qede_get_rxnfc,
+ .set_rxnfc = qede_set_rxnfc,
+ .get_rxfh_indir_size = qede_get_rxfh_indir_size,
+ .get_rxfh_key_size = qede_get_rxfh_key_size,
+ .get_rxfh = qede_get_rxfh,
+ .set_rxfh = qede_set_rxfh,
+ .get_ts_info = qede_get_ts_info,
+ .get_channels = qede_get_channels,
+ .set_channels = qede_set_channels,
+ .self_test = qede_self_test,
+ .get_module_info = qede_get_module_info,
+ .get_module_eeprom = qede_get_module_eeprom,
+ .get_eee = qede_get_eee,
+ .set_eee = qede_set_eee,
+ .get_fecparam = qede_get_fecparam,
+ .set_fecparam = qede_set_fecparam,
+ .get_tunable = qede_get_tunable,
+ .set_tunable = qede_set_tunable,
+ .flash_device = qede_flash_device,
+ .get_dump_flag = qede_get_dump_flag,
+ .get_dump_data = qede_get_dump_data,
+ .set_dump = qede_set_dump,
};
static const struct ethtool_ops qede_vf_ethtool_ops = {
- .get_link_ksettings = qede_get_link_ksettings,
- .get_drvinfo = qede_get_drvinfo,
- .get_msglevel = qede_get_msglevel,
- .set_msglevel = qede_set_msglevel,
- .get_link = qede_get_link,
- .get_coalesce = qede_get_coalesce,
- .set_coalesce = qede_set_coalesce,
- .get_ringparam = qede_get_ringparam,
- .set_ringparam = qede_set_ringparam,
- .get_strings = qede_get_strings,
- .get_ethtool_stats = qede_get_ethtool_stats,
- .get_priv_flags = qede_get_priv_flags,
- .get_sset_count = qede_get_sset_count,
- .get_rxnfc = qede_get_rxnfc,
- .set_rxnfc = qede_set_rxnfc,
- .get_rxfh_indir_size = qede_get_rxfh_indir_size,
- .get_rxfh_key_size = qede_get_rxfh_key_size,
- .get_rxfh = qede_get_rxfh,
- .set_rxfh = qede_set_rxfh,
- .get_channels = qede_get_channels,
- .set_channels = qede_set_channels,
- .get_tunable = qede_get_tunable,
- .set_tunable = qede_set_tunable,
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_STATS_BLOCK_USECS,
+ .get_link_ksettings = qede_get_link_ksettings,
+ .get_drvinfo = qede_get_drvinfo,
+ .get_msglevel = qede_get_msglevel,
+ .set_msglevel = qede_set_msglevel,
+ .get_link = qede_get_link,
+ .get_coalesce = qede_get_coalesce,
+ .set_coalesce = qede_set_coalesce,
+ .get_ringparam = qede_get_ringparam,
+ .set_ringparam = qede_set_ringparam,
+ .get_strings = qede_get_strings,
+ .get_ethtool_stats = qede_get_ethtool_stats,
+ .get_priv_flags = qede_get_priv_flags,
+ .get_sset_count = qede_get_sset_count,
+ .get_rxnfc = qede_get_rxnfc,
+ .set_rxnfc = qede_set_rxnfc,
+ .get_rxfh_indir_size = qede_get_rxfh_indir_size,
+ .get_rxfh_key_size = qede_get_rxfh_key_size,
+ .get_rxfh = qede_get_rxfh,
+ .set_rxfh = qede_set_rxfh,
+ .get_channels = qede_get_channels,
+ .set_channels = qede_set_channels,
+ .get_tunable = qede_get_tunable,
+ .set_tunable = qede_set_tunable,
};
void qede_set_ethtool_ops(struct net_device *dev)
--
Gitblit v1.6.2