aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/qed/qed_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/qlogic/qed/qed_main.c')
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_main.c1130
1 files changed, 763 insertions, 367 deletions
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index 2c189c637cca..c91898be7c03 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -1,33 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
/* QLogic qed 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/stddef.h>
@@ -49,6 +23,8 @@
#include <linux/qed/qed_if.h>
#include <linux/qed/qed_ll2_if.h>
#include <net/devlink.h>
+#include <linux/aer.h>
+#include <linux/phylink.h>
#include "qed.h"
#include "qed_sriov.h"
@@ -63,6 +39,7 @@
#include "qed_hw.h"
#include "qed_selftest.h"
#include "qed_debug.h"
+#include "qed_devlink.h"
#define QED_ROCE_QPS (8192)
#define QED_ROCE_DPIS (8)
@@ -72,11 +49,10 @@
#define QED_NVM_CFG_MAX_ATTRS 50
static char version[] =
- "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n";
+ "QLogic FastLinQ 4xxxx Core Module qed\n";
MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module");
MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_MODULE_VERSION);
#define FW_FILE_VERSION \
__stringify(FW_MAJOR_VERSION) "." \
@@ -89,46 +65,202 @@ MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_FIRMWARE(QED_FW_FILE_NAME);
-static int __init qed_init(void)
-{
- pr_info("%s", version);
+/* MFW speed capabilities maps */
- return 0;
+struct qed_mfw_speed_map {
+ u32 mfw_val;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(caps);
+
+ const u32 *cap_arr;
+ u32 arr_size;
+};
+
+#define QED_MFW_SPEED_MAP(type, arr) \
+{ \
+ .mfw_val = (type), \
+ .cap_arr = (arr), \
+ .arr_size = ARRAY_SIZE(arr), \
}
-static void __exit qed_cleanup(void)
+static const u32 qed_mfw_ext_1g[] __initconst = {
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+};
+
+static const u32 qed_mfw_ext_10g[] __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 qed_mfw_ext_25g[] __initconst = {
+ ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+};
+
+static const u32 qed_mfw_ext_40g[] __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 qed_mfw_ext_50g_base_r[] __initconst = {
+ ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
+};
+
+static const u32 qed_mfw_ext_50g_base_r2[] __initconst = {
+ ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+};
+
+static const u32 qed_mfw_ext_100g_base_r2[] __initconst = {
+ ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
+};
+
+static const u32 qed_mfw_ext_100g_base_r4[] __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 qed_mfw_speed_map qed_mfw_ext_maps[] __ro_after_init = {
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_1G, qed_mfw_ext_1g),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_10G, qed_mfw_ext_10g),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_25G, qed_mfw_ext_25g),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_40G, qed_mfw_ext_40g),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R,
+ qed_mfw_ext_50g_base_r),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R2,
+ qed_mfw_ext_50g_base_r2),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R2,
+ qed_mfw_ext_100g_base_r2),
+ QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R4,
+ qed_mfw_ext_100g_base_r4),
+};
+
+static const u32 qed_mfw_legacy_1g[] __initconst = {
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+};
+
+static const u32 qed_mfw_legacy_10g[] __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 qed_mfw_legacy_20g[] __initconst = {
+ ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
+};
+
+static const u32 qed_mfw_legacy_25g[] __initconst = {
+ ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+};
+
+static const u32 qed_mfw_legacy_40g[] __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 qed_mfw_legacy_50g[] __initconst = {
+ ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+};
+
+static const u32 qed_mfw_legacy_bb_100g[] __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 qed_mfw_speed_map qed_mfw_legacy_maps[] __ro_after_init = {
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G,
+ qed_mfw_legacy_1g),
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G,
+ qed_mfw_legacy_10g),
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G,
+ qed_mfw_legacy_20g),
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G,
+ qed_mfw_legacy_25g),
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G,
+ qed_mfw_legacy_40g),
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G,
+ qed_mfw_legacy_50g),
+ QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G,
+ qed_mfw_legacy_bb_100g),
+};
+
+static void __init qed_mfw_speed_map_populate(struct qed_mfw_speed_map *map)
{
- pr_notice("qed_cleanup called\n");
+ linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps);
+
+ map->cap_arr = NULL;
+ map->arr_size = 0;
}
-module_init(qed_init);
-module_exit(qed_cleanup);
+static void __init qed_mfw_speed_maps_init(void)
+{
+ u32 i;
-/* Check if the DMA controller on the machine can properly handle the DMA
- * addressing required by the device.
-*/
-static int qed_set_coherency_mask(struct qed_dev *cdev)
+ for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++)
+ qed_mfw_speed_map_populate(qed_mfw_ext_maps + i);
+
+ for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++)
+ qed_mfw_speed_map_populate(qed_mfw_legacy_maps + i);
+}
+
+static int __init qed_init(void)
{
- struct device *dev = &cdev->pdev->dev;
+ pr_info("%s", version);
- if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) {
- if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) {
- DP_NOTICE(cdev,
- "Can't request 64-bit consistent allocations\n");
- return -EIO;
- }
- } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) {
- DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n");
- return -EIO;
- }
+ qed_mfw_speed_maps_init();
return 0;
}
+module_init(qed_init);
+
+static void __exit qed_exit(void)
+{
+ /* To prevent marking this module as "permanent" */
+}
+module_exit(qed_exit);
static void qed_free_pci(struct qed_dev *cdev)
{
struct pci_dev *pdev = cdev->pdev;
+ pci_disable_pcie_error_reporting(pdev);
+
if (cdev->doorbells && cdev->db_size)
iounmap(cdev->doorbells);
if (cdev->regview)
@@ -198,9 +330,12 @@ static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev)
if (IS_PF(cdev) && !cdev->pci_params.pm_cap)
DP_NOTICE(cdev, "Cannot find power management capability\n");
- rc = qed_set_coherency_mask(cdev);
- if (rc)
+ rc = dma_set_mask_and_coherent(&cdev->pdev->dev, DMA_BIT_MASK(64));
+ if (rc) {
+ DP_NOTICE(cdev, "Can't request DMA addresses\n");
+ rc = -EIO;
goto err2;
+ }
cdev->pci_params.mem_start = pci_resource_start(pdev, 0);
cdev->pci_params.mem_end = pci_resource_end(pdev, 0);
@@ -231,6 +366,12 @@ static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev)
return -ENOMEM;
}
+ /* AER (Advanced Error reporting) configuration */
+ rc = pci_enable_pcie_error_reporting(pdev);
+ if (rc)
+ DP_VERBOSE(cdev, NETIF_MSG_DRV,
+ "Failed to configure PCIe AER [%d]\n", rc);
+
return 0;
err2:
@@ -280,13 +421,15 @@ int qed_fill_dev_info(struct qed_dev *cdev,
dev_info->fw_eng = FW_ENGINEERING_VERSION;
dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH,
&cdev->mf_bits);
+ if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits))
+ dev_info->b_arfs_capable = true;
dev_info->tx_switching = true;
if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME)
dev_info->wol_support = true;
dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn);
-
+ dev_info->esl = qed_mcp_is_esl_supported(p_hwfn);
dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id;
} else {
qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major,
@@ -314,6 +457,7 @@ int qed_fill_dev_info(struct qed_dev *cdev,
}
dev_info->mtu = hw_info->mtu;
+ cdev->common_dev_info = *dev_info;
return 0;
}
@@ -346,107 +490,6 @@ static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state)
return 0;
}
-struct qed_devlink {
- struct qed_dev *cdev;
-};
-
-enum qed_devlink_param_id {
- QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
- QED_DEVLINK_PARAM_ID_IWARP_CMT,
-};
-
-static int qed_dl_param_get(struct devlink *dl, u32 id,
- struct devlink_param_gset_ctx *ctx)
-{
- struct qed_devlink *qed_dl;
- struct qed_dev *cdev;
-
- qed_dl = devlink_priv(dl);
- cdev = qed_dl->cdev;
- ctx->val.vbool = cdev->iwarp_cmt;
-
- return 0;
-}
-
-static int qed_dl_param_set(struct devlink *dl, u32 id,
- struct devlink_param_gset_ctx *ctx)
-{
- struct qed_devlink *qed_dl;
- struct qed_dev *cdev;
-
- qed_dl = devlink_priv(dl);
- cdev = qed_dl->cdev;
- cdev->iwarp_cmt = ctx->val.vbool;
-
- return 0;
-}
-
-static const struct devlink_param qed_devlink_params[] = {
- DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT,
- "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL,
- BIT(DEVLINK_PARAM_CMODE_RUNTIME),
- qed_dl_param_get, qed_dl_param_set, NULL),
-};
-
-static const struct devlink_ops qed_dl_ops;
-
-static int qed_devlink_register(struct qed_dev *cdev)
-{
- union devlink_param_value value;
- struct qed_devlink *qed_dl;
- struct devlink *dl;
- int rc;
-
- dl = devlink_alloc(&qed_dl_ops, sizeof(*qed_dl));
- if (!dl)
- return -ENOMEM;
-
- qed_dl = devlink_priv(dl);
-
- cdev->dl = dl;
- qed_dl->cdev = cdev;
-
- rc = devlink_register(dl, &cdev->pdev->dev);
- if (rc)
- goto err_free;
-
- rc = devlink_params_register(dl, qed_devlink_params,
- ARRAY_SIZE(qed_devlink_params));
- if (rc)
- goto err_unregister;
-
- value.vbool = false;
- devlink_param_driverinit_value_set(dl,
- QED_DEVLINK_PARAM_ID_IWARP_CMT,
- value);
-
- devlink_params_publish(dl);
- cdev->iwarp_cmt = false;
-
- return 0;
-
-err_unregister:
- devlink_unregister(dl);
-
-err_free:
- cdev->dl = NULL;
- devlink_free(dl);
-
- return rc;
-}
-
-static void qed_devlink_unregister(struct qed_dev *cdev)
-{
- if (!cdev->dl)
- return;
-
- devlink_params_unregister(cdev->dl, qed_devlink_params,
- ARRAY_SIZE(qed_devlink_params));
-
- devlink_unregister(cdev->dl);
- devlink_free(cdev->dl);
-}
-
/* probing */
static struct qed_dev *qed_probe(struct pci_dev *pdev,
struct qed_probe_params *params)
@@ -475,19 +518,13 @@ static struct qed_dev *qed_probe(struct pci_dev *pdev,
}
DP_INFO(cdev, "PCI init completed successfully\n");
- rc = qed_devlink_register(cdev);
- if (rc) {
- DP_INFO(cdev, "Failed to register devlink.\n");
- goto err2;
- }
-
rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT);
if (rc) {
DP_ERR(cdev, "hw prepare failed\n");
goto err2;
}
- DP_INFO(cdev, "qed_probe completed successfully\n");
+ DP_INFO(cdev, "%s completed successfully\n", __func__);
return cdev;
@@ -510,8 +547,6 @@ static void qed_remove(struct qed_dev *cdev)
qed_set_power_state(cdev, PCI_D3hot);
- qed_devlink_unregister(cdev);
-
qed_free_cdev(cdev);
}
@@ -557,7 +592,12 @@ static int qed_enable_msix(struct qed_dev *cdev,
rc = cnt;
}
- if (rc > 0) {
+ /* For VFs, we should return with an error in case we didn't get the
+ * exact number of msix vectors as we requested.
+ * Not doing that will lead to a crash when starting queues for
+ * this VF.
+ */
+ if ((IS_PF(cdev) && rc > 0) || (IS_VF(cdev) && rc == cnt)) {
/* MSI-x configuration was achieved */
int_params->out.int_mode = QED_INT_MODE_MSIX;
int_params->out.num_vectors = rc;
@@ -597,7 +637,7 @@ static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode)
kfree(int_params->msix_table);
if (force_mode)
goto out;
- /* Fallthrough */
+ fallthrough;
case QED_INT_MODE_MSI:
if (cdev->num_hwfns == 1) {
@@ -611,7 +651,7 @@ static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode)
if (force_mode)
goto out;
}
- /* Fallthrough */
+ fallthrough;
case QED_INT_MODE_INTA:
int_params->out.int_mode = QED_INT_MODE_INTA;
@@ -677,7 +717,7 @@ static irqreturn_t qed_single_int(int irq, void *dev_instance)
/* Slowpath interrupt */
if (unlikely(status & 0x1)) {
- tasklet_schedule(hwfn->sp_dpc);
+ tasklet_schedule(&hwfn->sp_dpc);
status &= ~0x1;
rc = IRQ_HANDLED;
}
@@ -723,7 +763,7 @@ int qed_slowpath_irq_req(struct qed_hwfn *hwfn)
id, cdev->pdev->bus->number,
PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id);
rc = request_irq(cdev->int_params.msix_table[id].vector,
- qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc);
+ qed_msix_sp_int, 0, hwfn->name, &hwfn->sp_dpc);
} else {
unsigned long flags = 0;
@@ -755,8 +795,8 @@ static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn)
* enable function makes this sequence a flush-like operation.
*/
if (p_hwfn->b_sp_dpc_enabled) {
- tasklet_disable(p_hwfn->sp_dpc);
- tasklet_enable(p_hwfn->sp_dpc);
+ tasklet_disable(&p_hwfn->sp_dpc);
+ tasklet_enable(&p_hwfn->sp_dpc);
}
}
@@ -783,9 +823,8 @@ static void qed_slowpath_irq_free(struct qed_dev *cdev)
for_each_hwfn(cdev, i) {
if (!cdev->hwfns[i].b_int_requested)
break;
- synchronize_irq(cdev->int_params.msix_table[i].vector);
free_irq(cdev->int_params.msix_table[i].vector,
- cdev->hwfns[i].sp_dpc);
+ &cdev->hwfns[i].sp_dpc);
}
} else {
if (QED_LEADING_HWFN(cdev)->b_int_requested)
@@ -804,11 +843,11 @@ static int qed_nic_stop(struct qed_dev *cdev)
struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
if (p_hwfn->b_sp_dpc_enabled) {
- tasklet_disable(p_hwfn->sp_dpc);
+ tasklet_disable(&p_hwfn->sp_dpc);
p_hwfn->b_sp_dpc_enabled = false;
DP_VERBOSE(cdev, NETIF_MSG_IFDOWN,
"Disabled sp tasklet [hwfn %d] at %p\n",
- i, p_hwfn->sp_dpc);
+ i, &p_hwfn->sp_dpc);
}
}
@@ -917,7 +956,7 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev,
rc = qed_set_int_mode(cdev, false);
if (rc) {
- DP_ERR(cdev, "qed_slowpath_setup_int ERR\n");
+ DP_ERR(cdev, "%s ERR\n", __func__);
return rc;
}
@@ -1087,9 +1126,6 @@ static void qed_update_pf_params(struct qed_dev *cdev,
#define QED_PERIODIC_DB_REC_INTERVAL_MS 100
#define QED_PERIODIC_DB_REC_INTERVAL \
msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS)
-#define QED_PERIODIC_DB_REC_WAIT_COUNT 10
-#define QED_PERIODIC_DB_REC_WAIT_INTERVAL \
- (QED_PERIODIC_DB_REC_INTERVAL_MS / QED_PERIODIC_DB_REC_WAIT_COUNT)
static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn,
enum qed_slowpath_wq_flag wq_flag,
@@ -1101,6 +1137,7 @@ static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn,
/* Memory barrier for setting atomic bit */
smp_mb__before_atomic();
set_bit(wq_flag, &hwfn->slowpath_task_flags);
+ /* Memory barrier after setting atomic bit */
smp_mb__after_atomic();
queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay);
@@ -1123,7 +1160,7 @@ void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn)
static void qed_slowpath_wq_stop(struct qed_dev *cdev)
{
- int i, sleep_count = QED_PERIODIC_DB_REC_WAIT_COUNT;
+ int i;
if (IS_VF(cdev))
return;
@@ -1135,13 +1172,7 @@ static void qed_slowpath_wq_stop(struct qed_dev *cdev)
/* Stop queuing new delayed works */
cdev->hwfns[i].slowpath_wq_active = false;
- /* Wait until the last periodic doorbell recovery is executed */
- while (test_bit(QED_SLOWPATH_PERIODIC_DB_REC,
- &cdev->hwfns[i].slowpath_task_flags) &&
- sleep_count--)
- msleep(QED_PERIODIC_DB_REC_WAIT_INTERVAL);
-
- flush_workqueue(cdev->hwfns[i].slowpath_wq);
+ cancel_delayed_work(&cdev->hwfns[i].slowpath_task);
destroy_workqueue(cdev->hwfns[i].slowpath_wq);
}
}
@@ -1166,6 +1197,10 @@ static void qed_slowpath_task(struct work_struct *work)
if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC,
&hwfn->slowpath_task_flags)) {
+ /* skip qed_db_rec_handler during recovery/unload */
+ if (hwfn->cdev->recov_in_prog || !hwfn->slowpath_wq_active)
+ goto out;
+
qed_db_rec_handler(hwfn, ptt);
if (hwfn->periodic_db_rec_count--)
qed_slowpath_delayed_work(hwfn,
@@ -1173,6 +1208,7 @@ static void qed_slowpath_task(struct work_struct *work)
QED_PERIODIC_DB_REC_INTERVAL);
}
+out:
qed_ptt_release(hwfn, ptt);
}
@@ -1240,6 +1276,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
} else {
DP_NOTICE(cdev,
"Failed to acquire PTT for aRFS\n");
+ rc = -EINVAL;
goto err;
}
}
@@ -1322,7 +1359,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
(params->drv_minor << 16) |
(params->drv_rev << 8) |
(params->drv_eng);
- strlcpy(drv_version.name, params->name,
+ strscpy(drv_version.name, params->name,
MCP_DRV_VER_STR_SIZE - 4);
rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt,
&drv_version);
@@ -1480,13 +1517,156 @@ static bool qed_can_link_change(struct qed_dev *cdev)
return true;
}
+static void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params,
+ const struct qed_link_params *params)
+{
+ struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed;
+ const struct qed_mfw_speed_map *map;
+ u32 i;
+
+ if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG)
+ ext_speed->autoneg = !!params->autoneg;
+
+ if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) {
+ ext_speed->advertised_speeds = 0;
+
+ for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) {
+ map = qed_mfw_ext_maps + i;
+
+ if (linkmode_intersects(params->adv_speeds, map->caps))
+ ext_speed->advertised_speeds |= map->mfw_val;
+ }
+ }
+
+ if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) {
+ switch (params->forced_speed) {
+ case SPEED_1000:
+ ext_speed->forced_speed = QED_EXT_SPEED_1G;
+ break;
+ case SPEED_10000:
+ ext_speed->forced_speed = QED_EXT_SPEED_10G;
+ break;
+ case SPEED_20000:
+ ext_speed->forced_speed = QED_EXT_SPEED_20G;
+ break;
+ case SPEED_25000:
+ ext_speed->forced_speed = QED_EXT_SPEED_25G;
+ break;
+ case SPEED_40000:
+ ext_speed->forced_speed = QED_EXT_SPEED_40G;
+ break;
+ case SPEED_50000:
+ ext_speed->forced_speed = QED_EXT_SPEED_50G_R |
+ QED_EXT_SPEED_50G_R2;
+ break;
+ case SPEED_100000:
+ ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 |
+ QED_EXT_SPEED_100G_R4 |
+ QED_EXT_SPEED_100G_P4;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG))
+ return;
+
+ switch (params->forced_speed) {
+ case SPEED_25000:
+ switch (params->fec) {
+ case FEC_FORCE_MODE_NONE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE;
+ break;
+ case FEC_FORCE_MODE_FIRECODE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R;
+ break;
+ case FEC_FORCE_MODE_RS:
+ link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528;
+ break;
+ case FEC_FORCE_MODE_AUTO:
+ link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 |
+ ETH_EXT_FEC_25G_BASE_R |
+ ETH_EXT_FEC_25G_NONE;
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case SPEED_40000:
+ switch (params->fec) {
+ case FEC_FORCE_MODE_NONE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE;
+ break;
+ case FEC_FORCE_MODE_FIRECODE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R;
+ break;
+ case FEC_FORCE_MODE_AUTO:
+ link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R |
+ ETH_EXT_FEC_40G_NONE;
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case SPEED_50000:
+ switch (params->fec) {
+ case FEC_FORCE_MODE_NONE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE;
+ break;
+ case FEC_FORCE_MODE_FIRECODE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R;
+ break;
+ case FEC_FORCE_MODE_RS:
+ link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528;
+ break;
+ case FEC_FORCE_MODE_AUTO:
+ link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 |
+ ETH_EXT_FEC_50G_BASE_R |
+ ETH_EXT_FEC_50G_NONE;
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case SPEED_100000:
+ switch (params->fec) {
+ case FEC_FORCE_MODE_NONE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE;
+ break;
+ case FEC_FORCE_MODE_FIRECODE:
+ link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R;
+ break;
+ case FEC_FORCE_MODE_RS:
+ link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528;
+ break;
+ case FEC_FORCE_MODE_AUTO:
+ link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 |
+ ETH_EXT_FEC_100G_BASE_R |
+ ETH_EXT_FEC_100G_NONE;
+ break;
+ default:
+ break;
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
{
- struct qed_hwfn *hwfn;
struct qed_mcp_link_params *link_params;
+ struct qed_mcp_link_speed_params *speed;
+ const struct qed_mfw_speed_map *map;
+ struct qed_hwfn *hwfn;
struct qed_ptt *ptt;
- u32 sup_caps;
int rc;
+ u32 i;
if (!cdev)
return -ENODEV;
@@ -1508,59 +1688,31 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
return -EBUSY;
link_params = qed_mcp_get_link_params(hwfn);
+ if (!link_params)
+ return -ENODATA;
+
+ speed = &link_params->speed;
+
if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG)
- link_params->speed.autoneg = params->autoneg;
+ speed->autoneg = !!params->autoneg;
+
if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) {
- link_params->speed.advertised_speeds = 0;
- sup_caps = QED_LM_1000baseT_Full_BIT |
- QED_LM_1000baseKX_Full_BIT |
- QED_LM_1000baseX_Full_BIT;
- if (params->adv_speeds & sup_caps)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
- sup_caps = QED_LM_10000baseT_Full_BIT |
- QED_LM_10000baseKR_Full_BIT |
- QED_LM_10000baseKX4_Full_BIT |
- QED_LM_10000baseR_FEC_BIT |
- QED_LM_10000baseCR_Full_BIT |
- QED_LM_10000baseSR_Full_BIT |
- QED_LM_10000baseLR_Full_BIT |
- QED_LM_10000baseLRM_Full_BIT;
- if (params->adv_speeds & sup_caps)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
- if (params->adv_speeds & QED_LM_20000baseKR2_Full_BIT)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G;
- sup_caps = QED_LM_25000baseKR_Full_BIT |
- QED_LM_25000baseCR_Full_BIT |
- QED_LM_25000baseSR_Full_BIT;
- if (params->adv_speeds & sup_caps)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
- sup_caps = QED_LM_40000baseLR4_Full_BIT |
- QED_LM_40000baseKR4_Full_BIT |
- QED_LM_40000baseCR4_Full_BIT |
- QED_LM_40000baseSR4_Full_BIT;
- if (params->adv_speeds & sup_caps)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
- sup_caps = QED_LM_50000baseKR2_Full_BIT |
- QED_LM_50000baseCR2_Full_BIT |
- QED_LM_50000baseSR2_Full_BIT;
- if (params->adv_speeds & sup_caps)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G;
- sup_caps = QED_LM_100000baseKR4_Full_BIT |
- QED_LM_100000baseSR4_Full_BIT |
- QED_LM_100000baseCR4_Full_BIT |
- QED_LM_100000baseLR4_ER4_Full_BIT;
- if (params->adv_speeds & sup_caps)
- link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G;
+ speed->advertised_speeds = 0;
+
+ for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) {
+ map = qed_mfw_legacy_maps + i;
+
+ if (linkmode_intersects(params->adv_speeds, map->caps))
+ speed->advertised_speeds |= map->mfw_val;
+ }
}
+
if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED)
- link_params->speed.forced_speed = params->forced_speed;
+ speed->forced_speed = params->forced_speed;
+
+ if (qed_mcp_is_ext_speed_supported(hwfn))
+ qed_set_ext_speed_params(link_params, params);
+
if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) {
if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
link_params->pause.autoneg = true;
@@ -1575,6 +1727,7 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
else
link_params->pause.forced_tx = false;
}
+
if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) {
switch (params->loopback_mode) {
case QED_LINK_LOOPBACK_INT_PHY:
@@ -1589,6 +1742,25 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
case QED_LINK_LOOPBACK_MAC:
link_params->loopback_mode = ETH_LOOPBACK_MAC;
break;
+ case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123:
+ link_params->loopback_mode =
+ ETH_LOOPBACK_CNIG_AH_ONLY_0123;
+ break;
+ case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301:
+ link_params->loopback_mode =
+ ETH_LOOPBACK_CNIG_AH_ONLY_2301;
+ break;
+ case QED_LINK_LOOPBACK_PCS_AH_ONLY:
+ link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY;
+ break;
+ case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY:
+ link_params->loopback_mode =
+ ETH_LOOPBACK_REVERSE_MAC_AH_ONLY;
+ break;
+ case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY:
+ link_params->loopback_mode =
+ ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY;
+ break;
default:
link_params->loopback_mode = ETH_LOOPBACK_NONE;
break;
@@ -1599,6 +1771,9 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
memcpy(&link_params->eee, &params->eee,
sizeof(link_params->eee));
+ if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)
+ link_params->fec = params->fec;
+
rc = qed_mcp_set_link(hwfn, ptt, params->link_up);
qed_ptt_release(hwfn, ptt);
@@ -1615,7 +1790,6 @@ static int qed_get_port_type(u32 media_type)
case MEDIA_SFP_1G_FIBER:
case MEDIA_XFP_FIBER:
case MEDIA_MODULE_FIBER:
- case MEDIA_KR:
port_type = PORT_FIBRE;
break;
case MEDIA_DA_TWINAX:
@@ -1624,6 +1798,7 @@ static int qed_get_port_type(u32 media_type)
case MEDIA_BASE_T:
port_type = PORT_TP;
break;
+ case MEDIA_KR:
case MEDIA_NOT_PRESENT:
port_type = PORT_NONE;
break;
@@ -1670,7 +1845,7 @@ static int qed_get_link_data(struct qed_hwfn *hwfn,
static void qed_fill_link_capability(struct qed_hwfn *hwfn,
struct qed_ptt *ptt, u32 capability,
- u32 *if_capability)
+ unsigned long *if_caps)
{
u32 media_type, tcvr_state, tcvr_type;
u32 speed_mask, board_cfg;
@@ -1693,122 +1868,215 @@ static void qed_fill_link_capability(struct qed_hwfn *hwfn,
switch (media_type) {
case MEDIA_DA_TWINAX:
- *if_capability |= QED_LM_FIBRE_BIT;
+ phylink_set(if_caps, FIBRE);
+
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
- *if_capability |= QED_LM_20000baseKR2_Full_BIT;
- /* For DAC media multiple speed capabilities are supported*/
- capability = capability & speed_mask;
+ phylink_set(if_caps, 20000baseKR2_Full);
+
+ /* For DAC media multiple speed capabilities are supported */
+ capability |= speed_mask;
+
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
- *if_capability |= QED_LM_1000baseKX_Full_BIT;
+ phylink_set(if_caps, 1000baseKX_Full);
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
- *if_capability |= QED_LM_10000baseCR_Full_BIT;
+ phylink_set(if_caps, 10000baseCR_Full);
+
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
- *if_capability |= QED_LM_40000baseCR4_Full_BIT;
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_40G_CR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR:
+ phylink_set(if_caps, 40000baseCR4_Full);
+ break;
+ default:
+ break;
+ }
+
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
- *if_capability |= QED_LM_25000baseCR_Full_BIT;
+ phylink_set(if_caps, 25000baseCR_Full);
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
- *if_capability |= QED_LM_50000baseCR2_Full_BIT;
+ phylink_set(if_caps, 50000baseCR2_Full);
+
if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
- *if_capability |= QED_LM_100000baseCR4_Full_BIT;
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_100G_CR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR:
+ phylink_set(if_caps, 100000baseCR4_Full);
+ break;
+ default:
+ break;
+ }
+
break;
case MEDIA_BASE_T:
- *if_capability |= QED_LM_TP_BIT;
+ phylink_set(if_caps, TP);
+
if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) {
if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) {
- *if_capability |= QED_LM_1000baseT_Full_BIT;
- }
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
+ phylink_set(if_caps, 1000baseT_Full);
if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) {
- *if_capability |= QED_LM_10000baseT_Full_BIT;
- }
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
+ phylink_set(if_caps, 10000baseT_Full);
}
+
if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) {
- *if_capability |= QED_LM_FIBRE_BIT;
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_1000BASET)
- *if_capability |= QED_LM_1000baseT_Full_BIT;
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_BASET)
- *if_capability |= QED_LM_10000baseT_Full_BIT;
+ phylink_set(if_caps, FIBRE);
+
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_1000BASET:
+ phylink_set(if_caps, 1000baseT_Full);
+ break;
+ case ETH_TRANSCEIVER_TYPE_10G_BASET:
+ phylink_set(if_caps, 10000baseT_Full);
+ break;
+ default:
+ break;
+ }
}
+
break;
case MEDIA_SFP_1G_FIBER:
case MEDIA_SFPP_10G_FIBER:
case MEDIA_XFP_FIBER:
case MEDIA_MODULE_FIBER:
- *if_capability |= QED_LM_FIBRE_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) {
- if ((tcvr_type == ETH_TRANSCEIVER_TYPE_1G_LX) ||
- (tcvr_type == ETH_TRANSCEIVER_TYPE_1G_SX))
- *if_capability |= QED_LM_1000baseKX_Full_BIT;
- }
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) {
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_SR)
- *if_capability |= QED_LM_10000baseSR_Full_BIT;
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LR)
- *if_capability |= QED_LM_10000baseLR_Full_BIT;
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LRM)
- *if_capability |= QED_LM_10000baseLRM_Full_BIT;
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_ER)
- *if_capability |= QED_LM_10000baseR_FEC_BIT;
- }
+ phylink_set(if_caps, FIBRE);
+ capability |= speed_mask;
+
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_1G_LX:
+ case ETH_TRANSCEIVER_TYPE_1G_SX:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR:
+ phylink_set(if_caps, 1000baseKX_Full);
+ break;
+ default:
+ break;
+ }
+
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_10G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR:
+ phylink_set(if_caps, 10000baseSR_Full);
+ break;
+ case ETH_TRANSCEIVER_TYPE_10G_LR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR:
+ phylink_set(if_caps, 10000baseLR_Full);
+ break;
+ case ETH_TRANSCEIVER_TYPE_10G_LRM:
+ phylink_set(if_caps, 10000baseLRM_Full);
+ break;
+ case ETH_TRANSCEIVER_TYPE_10G_ER:
+ phylink_set(if_caps, 10000baseR_FEC);
+ break;
+ default:
+ break;
+ }
+
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
- *if_capability |= QED_LM_20000baseKR2_Full_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) {
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_25G_SR)
- *if_capability |= QED_LM_25000baseSR_Full_BIT;
- }
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) {
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_LR4)
- *if_capability |= QED_LM_40000baseLR4_Full_BIT;
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_SR4)
- *if_capability |= QED_LM_40000baseSR4_Full_BIT;
- }
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
- *if_capability |= QED_LM_50000baseKR2_Full_BIT;
+ phylink_set(if_caps, 20000baseKR2_Full);
+
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_25G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR:
+ phylink_set(if_caps, 25000baseSR_Full);
+ break;
+ default:
+ break;
+ }
+
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_40G_LR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR:
+ phylink_set(if_caps, 40000baseLR4_Full);
+ break;
+ case ETH_TRANSCEIVER_TYPE_40G_SR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR:
+ phylink_set(if_caps, 40000baseSR4_Full);
+ break;
+ default:
+ break;
+ }
+
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
+ phylink_set(if_caps, 50000baseKR2_Full);
+
if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) {
- if (tcvr_type == ETH_TRANSCEIVER_TYPE_100G_SR4)
- *if_capability |= QED_LM_100000baseSR4_Full_BIT;
- }
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
+ switch (tcvr_type) {
+ case ETH_TRANSCEIVER_TYPE_100G_SR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR:
+ phylink_set(if_caps, 100000baseSR4_Full);
+ break;
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR:
+ phylink_set(if_caps, 100000baseLR4_ER4_Full);
+ break;
+ default:
+ break;
+ }
break;
case MEDIA_KR:
- *if_capability |= QED_LM_Backplane_BIT;
+ phylink_set(if_caps, Backplane);
+
if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
- *if_capability |= QED_LM_20000baseKR2_Full_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
- *if_capability |= QED_LM_1000baseKX_Full_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
- *if_capability |= QED_LM_10000baseKR_Full_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
- *if_capability |= QED_LM_25000baseKR_Full_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
- *if_capability |= QED_LM_40000baseKR4_Full_BIT;
- if (capability &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
- *if_capability |= QED_LM_50000baseKR2_Full_BIT;
+ phylink_set(if_caps, 20000baseKR2_Full);
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
+ phylink_set(if_caps, 1000baseKX_Full);
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
+ phylink_set(if_caps, 10000baseKR_Full);
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
+ phylink_set(if_caps, 25000baseKR_Full);
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
+ phylink_set(if_caps, 40000baseKR4_Full);
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
+ phylink_set(if_caps, 50000baseKR2_Full);
if (capability &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
- *if_capability |= QED_LM_100000baseKR4_Full_BIT;
+ phylink_set(if_caps, 100000baseKR4_Full);
+
break;
case MEDIA_UNSPECIFIED:
case MEDIA_NOT_PRESENT:
+ default:
DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG,
"Unknown media and transceiver type;\n");
break;
}
}
+static void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask)
+{
+ *speed_mask = 0;
+
+ if (caps &
+ (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD))
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
+ if (caps & QED_LINK_PARTNER_SPEED_10G)
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
+ if (caps & QED_LINK_PARTNER_SPEED_20G)
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G;
+ if (caps & QED_LINK_PARTNER_SPEED_25G)
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
+ if (caps & QED_LINK_PARTNER_SPEED_40G)
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
+ if (caps & QED_LINK_PARTNER_SPEED_50G)
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G;
+ if (caps & QED_LINK_PARTNER_SPEED_100G)
+ *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G;
+}
+
static void qed_fill_link(struct qed_hwfn *hwfn,
struct qed_ptt *ptt,
struct qed_link_output *if_link)
@@ -1816,7 +2084,7 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
struct qed_mcp_link_capabilities link_caps;
struct qed_mcp_link_params params;
struct qed_mcp_link_state link;
- u32 media_type;
+ u32 media_type, speed_mask;
memset(if_link, 0, sizeof(*if_link));
@@ -1830,28 +2098,53 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
if (link.link_up)
if_link->link_up = true;
- /* TODO - at the moment assume supported and advertised speed equal */
- if (link_caps.default_speed_autoneg)
- if_link->supported_caps |= QED_LM_Autoneg_BIT;
+ if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) {
+ if (link_caps.default_ext_autoneg)
+ phylink_set(if_link->supported_caps, Autoneg);
+
+ linkmode_copy(if_link->advertised_caps, if_link->supported_caps);
+
+ if (params.ext_speed.autoneg)
+ phylink_set(if_link->advertised_caps, Autoneg);
+ else
+ phylink_clear(if_link->advertised_caps, Autoneg);
+
+ qed_fill_link_capability(hwfn, ptt,
+ params.ext_speed.advertised_speeds,
+ if_link->advertised_caps);
+ } else {
+ if (link_caps.default_speed_autoneg)
+ phylink_set(if_link->supported_caps, Autoneg);
+
+ linkmode_copy(if_link->advertised_caps, if_link->supported_caps);
+
+ if (params.speed.autoneg)
+ phylink_set(if_link->advertised_caps, Autoneg);
+ else
+ phylink_clear(if_link->advertised_caps, Autoneg);
+ }
+
if (params.pause.autoneg ||
(params.pause.forced_rx && params.pause.forced_tx))
- if_link->supported_caps |= QED_LM_Asym_Pause_BIT;
+ phylink_set(if_link->supported_caps, Asym_Pause);
if (params.pause.autoneg || params.pause.forced_rx ||
params.pause.forced_tx)
- if_link->supported_caps |= QED_LM_Pause_BIT;
+ phylink_set(if_link->supported_caps, Pause);
- if_link->advertised_caps = if_link->supported_caps;
- if (params.speed.autoneg)
- if_link->advertised_caps |= QED_LM_Autoneg_BIT;
- else
- if_link->advertised_caps &= ~QED_LM_Autoneg_BIT;
+ if_link->sup_fec = link_caps.fec_default;
+ if_link->active_fec = params.fec;
- /* Fill link advertised capability*/
+ /* Fill link advertised capability */
qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds,
- &if_link->advertised_caps);
- /* Fill link supported capability*/
+ if_link->advertised_caps);
+
+ /* Fill link supported capability */
qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities,
- &if_link->supported_caps);
+ if_link->supported_caps);
+
+ /* Fill partner advertised capability */
+ qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask);
+ qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps);
if (link.link_up)
if_link->speed = link.speed;
@@ -1870,31 +2163,13 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
if (params.pause.forced_tx)
if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE;
- /* Link partner capabilities */
- if (link.partner_adv_speed &
- QED_LINK_PARTNER_SPEED_1G_FD)
- if_link->lp_caps |= QED_LM_1000baseT_Full_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G)
- if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_20G)
- if_link->lp_caps |= QED_LM_20000baseKR2_Full_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G)
- if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G)
- if_link->lp_caps |= QED_LM_40000baseLR4_Full_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_50G)
- if_link->lp_caps |= QED_LM_50000baseKR2_Full_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_100G)
- if_link->lp_caps |= QED_LM_100000baseKR4_Full_BIT;
-
if (link.an_complete)
- if_link->lp_caps |= QED_LM_Autoneg_BIT;
-
+ phylink_set(if_link->lp_caps, Autoneg);
if (link.partner_adv_pause)
- if_link->lp_caps |= QED_LM_Pause_BIT;
+ phylink_set(if_link->lp_caps, Pause);
if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE ||
link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE)
- if_link->lp_caps |= QED_LM_Asym_Pause_BIT;
+ phylink_set(if_link->lp_caps, Asym_Pause);
if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) {
if_link->eee_supported = false;
@@ -1949,6 +2224,15 @@ void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt)
op->link_update(cookie, &if_link);
}
+void qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt)
+{
+ void *cookie = hwfn->cdev->ops_cookie;
+ struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common;
+
+ if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update)
+ op->bw_update(cookie);
+}
+
static int qed_drain(struct qed_dev *cdev)
{
struct qed_hwfn *hwfn;
@@ -1979,8 +2263,7 @@ static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev,
u32 *crc)
{
u8 *buf = NULL;
- int rc, j;
- u32 val;
+ int rc;
/* Allocate a buffer for holding the nvram image */
buf = kzalloc(nvm_image->length, GFP_KERNEL);
@@ -1998,15 +2281,14 @@ static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev,
/* Convert the buffer into big-endian format (excluding the
* closing 4 bytes of CRC).
*/
- for (j = 0; j < nvm_image->length - 4; j += 4) {
- val = cpu_to_be32(*(u32 *)&buf[j]);
- *(u32 *)&buf[j] = val;
- }
+ cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf,
+ DIV_ROUND_UP(nvm_image->length - 4, 4));
/* Calc CRC for the "actual" image buffer, i.e. not including
* the last 4 CRC bytes.
*/
- *crc = (~cpu_to_be32(crc32(0xffffffff, buf, nvm_image->length - 4)));
+ *crc = ~crc32(~0U, buf, nvm_image->length - 4);
+ *crc = (__force u32)cpu_to_be32p(crc);
out:
kfree(buf);
@@ -2468,6 +2750,39 @@ void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn)
ops->schedule_recovery_handler(cookie);
}
+static const char * const qed_hw_err_type_descr[] = {
+ [QED_HW_ERR_FAN_FAIL] = "Fan Failure",
+ [QED_HW_ERR_MFW_RESP_FAIL] = "MFW Response Failure",
+ [QED_HW_ERR_HW_ATTN] = "HW Attention",
+ [QED_HW_ERR_DMAE_FAIL] = "DMAE Failure",
+ [QED_HW_ERR_RAMROD_FAIL] = "Ramrod Failure",
+ [QED_HW_ERR_FW_ASSERT] = "FW Assertion",
+ [QED_HW_ERR_LAST] = "Unknown",
+};
+
+void qed_hw_error_occurred(struct qed_hwfn *p_hwfn,
+ enum qed_hw_err_type err_type)
+{
+ struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common;
+ void *cookie = p_hwfn->cdev->ops_cookie;
+ const char *err_str;
+
+ if (err_type > QED_HW_ERR_LAST)
+ err_type = QED_HW_ERR_LAST;
+ err_str = qed_hw_err_type_descr[err_type];
+
+ DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str);
+
+ /* Call the HW error handler of the protocol driver.
+ * If it is not available - perform a minimal handling of preventing
+ * HW attentions from being reasserted.
+ */
+ if (ops && ops->schedule_hw_err_handler)
+ ops->schedule_hw_err_handler(cookie, err_type);
+ else
+ qed_int_attn_clr_enable(p_hwfn->cdev, true);
+}
+
static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal,
void *handle)
{
@@ -2491,7 +2806,7 @@ static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
return status;
}
-static int qed_recovery_process(struct qed_dev *cdev)
+int qed_recovery_process(struct qed_dev *cdev)
{
struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
struct qed_ptt *p_ptt;
@@ -2554,7 +2869,7 @@ static int qed_update_drv_state(struct qed_dev *cdev, bool active)
return status;
}
-static int qed_update_mac(struct qed_dev *cdev, u8 *mac)
+static int qed_update_mac(struct qed_dev *cdev, const u8 *mac)
{
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
struct qed_ptt *ptt;
@@ -2602,6 +2917,30 @@ out:
return status;
}
+static int
+qed_get_sb_info(struct qed_dev *cdev, struct qed_sb_info *sb,
+ u16 qid, struct qed_sb_info_dbg *sb_dbg)
+{
+ struct qed_hwfn *hwfn = &cdev->hwfns[qid % cdev->num_hwfns];
+ struct qed_ptt *ptt;
+ int rc;
+
+ if (IS_VF(cdev))
+ return -EINVAL;
+
+ ptt = qed_ptt_acquire(hwfn);
+ if (!ptt) {
+ DP_NOTICE(hwfn, "Can't acquire PTT\n");
+ return -EAGAIN;
+ }
+
+ memset(sb_dbg, 0, sizeof(*sb_dbg));
+ rc = qed_int_get_sb_dbg(hwfn, ptt, sb, sb_dbg);
+
+ qed_ptt_release(hwfn, ptt);
+ return rc;
+}
+
static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf,
u8 dev_addr, u32 offset, u32 len)
{
@@ -2644,11 +2983,54 @@ static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val)
return rc;
}
+static __printf(2, 3) void qed_mfw_report(struct qed_dev *cdev, char *fmt, ...)
+{
+ char buf[QED_MFW_REPORT_STR_SIZE];
+ struct qed_hwfn *p_hwfn;
+ struct qed_ptt *p_ptt;
+ va_list vl;
+
+ va_start(vl, fmt);
+ vsnprintf(buf, QED_MFW_REPORT_STR_SIZE, fmt, vl);
+ va_end(vl);
+
+ if (IS_PF(cdev)) {
+ p_hwfn = QED_LEADING_HWFN(cdev);
+ p_ptt = qed_ptt_acquire(p_hwfn);
+ if (p_ptt) {
+ qed_mcp_send_raw_debug_data(p_hwfn, p_ptt, buf, strlen(buf));
+ qed_ptt_release(p_hwfn, p_ptt);
+ }
+ }
+}
+
static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev)
{
return QED_AFFIN_HWFN_IDX(cdev);
}
+static int qed_get_esl_status(struct qed_dev *cdev, bool *esl_active)
+{
+ struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *ptt;
+ int rc = 0;
+
+ *esl_active = false;
+
+ if (IS_VF(cdev))
+ return 0;
+
+ ptt = qed_ptt_acquire(hwfn);
+ if (!ptt)
+ return -EAGAIN;
+
+ rc = qed_mcp_get_esl_status(hwfn, ptt, esl_active);
+
+ qed_ptt_release(hwfn, ptt);
+
+ return rc;
+}
+
static struct qed_selftest_ops qed_selftest_ops_pass = {
.selftest_memory = &qed_selftest_memory,
.selftest_interrupt = &qed_selftest_interrupt,
@@ -2679,6 +3061,9 @@ const struct qed_common_ops qed_common_ops_pass = {
.get_link = &qed_get_current_link,
.drain = &qed_drain,
.update_msglvl = &qed_init_dp,
+ .devlink_register = qed_devlink_register,
+ .devlink_unregister = qed_devlink_unregister,
+ .report_fatal_error = qed_report_fatal_error,
.dbg_all_data = &qed_dbg_all_data,
.dbg_all_data_size = &qed_dbg_all_data_size,
.chain_alloc = &qed_chain_alloc,
@@ -2689,6 +3074,7 @@ const struct qed_common_ops qed_common_ops_pass = {
.set_led = &qed_set_led,
.recovery_process = &qed_recovery_process,
.recovery_prolog = &qed_recovery_prolog,
+ .attn_clr_enable = &qed_int_attn_clr_enable,
.update_drv_state = &qed_update_drv_state,
.update_mac = &qed_update_mac,
.update_mtu = &qed_update_mtu,
@@ -2700,6 +3086,9 @@ const struct qed_common_ops qed_common_ops_pass = {
.read_nvm_cfg = &qed_nvm_flash_cfg_read,
.read_nvm_cfg_len = &qed_nvm_flash_cfg_len,
.set_grc_config = &qed_set_grc_config,
+ .mfw_report = &qed_mfw_report,
+ .get_sb_info = &qed_get_sb_info,
+ .get_esl_status = &qed_get_esl_status,
};
void qed_get_protocol_stats(struct qed_dev *cdev,
@@ -2737,8 +3126,10 @@ int qed_mfw_tlv_req(struct qed_hwfn *hwfn)
DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV,
"Scheduling slowpath task [Flag: %d]\n",
QED_SLOWPATH_MFW_TLV_REQ);
+ /* Memory barrier for setting atomic bit */
smp_mb__before_atomic();
set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags);
+ /* Memory barrier after setting atomic bit */
smp_mb__after_atomic();
queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0);
@@ -2817,3 +3208,8 @@ int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type,
return 0;
}
+
+unsigned long qed_get_epoch_time(void)
+{
+ return ktime_get_real_seconds();
+}