qed/qede: make devlink survive recovery
authorIgor Russkikh <irusskikh@marvell.com>
Sun, 23 Aug 2020 11:19:26 +0000 (14:19 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 Aug 2020 01:01:32 +0000 (18:01 -0700)
Devlink instance lifecycle was linked to qed_dev object,
that caused devlink to be recreated on each recovery.

Changing it by making higher level driver (qede) responsible for its
life. This way devlink now survives recoveries.

qede now stores devlink structure pointer as a part of its device
object, devlink private data contains a linkage structure,
qed_devlink.

Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: Alexander Lobakin <alobakin@marvell.com>
Signed-off-by: Michal Kalderon <michal.kalderon@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed.h
drivers/net/ethernet/qlogic/qed/qed_devlink.c
drivers/net/ethernet/qlogic/qed/qed_devlink.h
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_main.c
include/linux/qed/qed_if.h

index b2a7b53ee7602209559812d89a7f0bfa4bef2be7..b6ce1488abcc61595ad0b8d4e124cf7323683123 100644 (file)
@@ -849,7 +849,6 @@ struct qed_dev {
        u32 rdma_max_srq_sge;
        u16 tunn_feature_mask;
 
-       struct devlink                  *dl;
        bool                            iwarp_cmt;
 };
 
index eb693787c99e9a307d0b0f8d2a1ee0cbb2457d9d..a62c47c61edf5b056a60eb8dbd4696f4d8c87d6f 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/qed/qed_if.h>
 #include "qed.h"
 #include "qed_devlink.h"
 
@@ -13,17 +14,12 @@ enum qed_devlink_param_id {
        QED_DEVLINK_PARAM_ID_IWARP_CMT,
 };
 
-struct qed_devlink {
-       struct qed_dev *cdev;
-};
-
 static int qed_dl_param_get(struct devlink *dl, u32 id,
                            struct devlink_param_gset_ctx *ctx)
 {
-       struct qed_devlink *qed_dl;
+       struct qed_devlink *qed_dl = devlink_priv(dl);
        struct qed_dev *cdev;
 
-       qed_dl = devlink_priv(dl);
        cdev = qed_dl->cdev;
        ctx->val.vbool = cdev->iwarp_cmt;
 
@@ -33,10 +29,9 @@ static int qed_dl_param_get(struct devlink *dl, u32 id,
 static int qed_dl_param_set(struct devlink *dl, u32 id,
                            struct devlink_param_gset_ctx *ctx)
 {
-       struct qed_devlink *qed_dl;
+       struct qed_devlink *qed_dl = devlink_priv(dl);
        struct qed_dev *cdev;
 
-       qed_dl = devlink_priv(dl);
        cdev = qed_dl->cdev;
        cdev->iwarp_cmt = ctx->val.vbool;
 
@@ -52,21 +47,19 @@ static const struct devlink_param qed_devlink_params[] = {
 
 static const struct devlink_ops qed_dl_ops;
 
-int qed_devlink_register(struct qed_dev *cdev)
+struct devlink *qed_devlink_register(struct qed_dev *cdev)
 {
        union devlink_param_value value;
-       struct qed_devlink *qed_dl;
+       struct qed_devlink *qdevlink;
        struct devlink *dl;
        int rc;
 
-       dl = devlink_alloc(&qed_dl_ops, sizeof(*qed_dl));
+       dl = devlink_alloc(&qed_dl_ops, sizeof(struct qed_devlink));
        if (!dl)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
-       qed_dl = devlink_priv(dl);
-
-       cdev->dl = dl;
-       qed_dl->cdev = cdev;
+       qdevlink = devlink_priv(dl);
+       qdevlink->cdev = cdev;
 
        rc = devlink_register(dl, &cdev->pdev->dev);
        if (rc)
@@ -85,26 +78,25 @@ int qed_devlink_register(struct qed_dev *cdev)
        devlink_params_publish(dl);
        cdev->iwarp_cmt = false;
 
-       return 0;
+       return dl;
 
 err_unregister:
        devlink_unregister(dl);
 
 err_free:
-       cdev->dl = NULL;
        devlink_free(dl);
 
-       return rc;
+       return ERR_PTR(rc);
 }
 
-void qed_devlink_unregister(struct qed_dev *cdev)
+void qed_devlink_unregister(struct devlink *devlink)
 {
-       if (!cdev->dl)
+       if (!devlink)
                return;
 
-       devlink_params_unregister(cdev->dl, qed_devlink_params,
+       devlink_params_unregister(devlink, qed_devlink_params,
                                  ARRAY_SIZE(qed_devlink_params));
 
-       devlink_unregister(cdev->dl);
-       devlink_free(cdev->dl);
+       devlink_unregister(devlink);
+       devlink_free(devlink);
 }
index b94c40e9b7c1d8b4536239d90b73b1270847da69..c79dc6bfa194251a8494130d2105f7137c5c94b7 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/qed/qed_if.h>
 #include <net/devlink.h>
 
-int qed_devlink_register(struct qed_dev *cdev);
-void qed_devlink_unregister(struct qed_dev *cdev);
+struct devlink *qed_devlink_register(struct qed_dev *cdev);
+void qed_devlink_unregister(struct devlink *devlink);
 
 #endif
index 8751355d9ef7f4084b3e8ca7b25e40151d6d35bb..d6f76421379b260b91f4904a3303cc22f138fdbe 100644 (file)
@@ -539,12 +539,6 @@ 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");
@@ -574,8 +568,6 @@ static void qed_remove(struct qed_dev *cdev)
 
        qed_set_power_state(cdev, PCI_D3hot);
 
-       qed_devlink_unregister(cdev);
-
        qed_free_cdev(cdev);
 }
 
@@ -3012,6 +3004,8 @@ 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,
        .dbg_all_data = &qed_dbg_all_data,
        .dbg_all_data_size = &qed_dbg_all_data_size,
        .chain_alloc = &qed_chain_alloc,
index 803c1fcca8ad1cb7864cb68cd4f280d193c001a4..1f0e7505a9738af35ad9efe9a5eaacde4dcbada5 100644 (file)
@@ -172,6 +172,7 @@ struct qede_dev {
        struct qed_dev                  *cdev;
        struct net_device               *ndev;
        struct pci_dev                  *pdev;
+       struct devlink                  *devlink;
 
        u32                             dp_module;
        u8                              dp_level;
index 140a392a81bbd6aeb1564d027bc27d79ad914834..4cd8412e5ed02beef28ed8c4bfca12cf60285adc 100644 (file)
@@ -1170,10 +1170,23 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level,
                        rc = -ENOMEM;
                        goto err2;
                }
+
+               edev->devlink = qed_ops->common->devlink_register(cdev);
+               if (IS_ERR(edev->devlink)) {
+                       DP_NOTICE(edev, "Cannot register devlink\n");
+                       edev->devlink = NULL;
+                       /* Go on, we can live without devlink */
+               }
        } else {
                struct net_device *ndev = pci_get_drvdata(pdev);
 
                edev = netdev_priv(ndev);
+
+               if (edev->devlink) {
+                       struct qed_devlink *qdl = devlink_priv(edev->devlink);
+
+                       qdl->cdev = cdev;
+               }
                edev->cdev = cdev;
                memset(&edev->stats, 0, sizeof(edev->stats));
                memcpy(&edev->dev_info, &dev_info, sizeof(dev_info));
@@ -1296,6 +1309,11 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode)
        qed_ops->common->slowpath_stop(cdev);
        if (system_state == SYSTEM_POWER_OFF)
                return;
+
+       if (mode != QEDE_REMOVE_RECOVERY && edev->devlink) {
+               qed_ops->common->devlink_unregister(edev->devlink);
+               edev->devlink = NULL;
+       }
        qed_ops->common->remove(cdev);
        edev->cdev = NULL;
 
index cd6a5c7e56ebaa918bc6854f2ba3469374c03164..d8368e1770dfe232238d01bb62ac4aa22127f5cb 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/qed/common_hsi.h>
 #include <linux/qed/qed_chain.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <net/devlink.h>
 
 enum dcbx_protocol_type {
        DCBX_PROTOCOL_ISCSI,
@@ -779,6 +780,10 @@ enum qed_nvm_flash_cmd {
        QED_NVM_FLASH_CMD_NVM_MAX,
 };
 
+struct qed_devlink {
+       struct qed_dev *cdev;
+};
+
 struct qed_common_cb_ops {
        void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc);
        void (*link_update)(void *dev, struct qed_link_output *link);
@@ -1137,6 +1142,10 @@ struct qed_common_ops {
  *
  */
        int (*set_grc_config)(struct qed_dev *cdev, u32 cfg_id, u32 val);
+
+       struct devlink* (*devlink_register)(struct qed_dev *cdev);
+
+       void (*devlink_unregister)(struct devlink *devlink);
 };
 
 #define MASK_FIELD(_name, _value) \