cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

qed_devlink.c (6151B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Marvell/Qlogic FastLinQ NIC driver
      3 *
      4 * Copyright (C) 2020 Marvell International Ltd.
      5 */
      6
      7#include <linux/kernel.h>
      8#include <linux/qed/qed_if.h>
      9#include <linux/vmalloc.h>
     10#include "qed.h"
     11#include "qed_devlink.h"
     12
     13enum qed_devlink_param_id {
     14	QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
     15	QED_DEVLINK_PARAM_ID_IWARP_CMT,
     16};
     17
     18struct qed_fw_fatal_ctx {
     19	enum qed_hw_err_type err_type;
     20};
     21
     22int qed_report_fatal_error(struct devlink *devlink, enum qed_hw_err_type err_type)
     23{
     24	struct qed_devlink *qdl = devlink_priv(devlink);
     25	struct qed_fw_fatal_ctx fw_fatal_ctx = {
     26		.err_type = err_type,
     27	};
     28
     29	if (qdl->fw_reporter)
     30		devlink_health_report(qdl->fw_reporter,
     31				      "Fatal error occurred", &fw_fatal_ctx);
     32
     33	return 0;
     34}
     35
     36static int
     37qed_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
     38			   struct devlink_fmsg *fmsg, void *priv_ctx,
     39			   struct netlink_ext_ack *extack)
     40{
     41	struct qed_devlink *qdl = devlink_health_reporter_priv(reporter);
     42	struct qed_fw_fatal_ctx *fw_fatal_ctx = priv_ctx;
     43	struct qed_dev *cdev = qdl->cdev;
     44	u32 dbg_data_buf_size;
     45	u8 *p_dbg_data_buf;
     46	int err;
     47
     48	/* Having context means that was a dump request after fatal,
     49	 * so we enable extra debugging while gathering the dump,
     50	 * just in case
     51	 */
     52	cdev->print_dbg_data = fw_fatal_ctx ? true : false;
     53
     54	dbg_data_buf_size = qed_dbg_all_data_size(cdev);
     55	p_dbg_data_buf = vzalloc(dbg_data_buf_size);
     56	if (!p_dbg_data_buf) {
     57		DP_NOTICE(cdev,
     58			  "Failed to allocate memory for a debug data buffer\n");
     59		return -ENOMEM;
     60	}
     61
     62	err = qed_dbg_all_data(cdev, p_dbg_data_buf);
     63	if (err) {
     64		DP_NOTICE(cdev, "Failed to obtain debug data\n");
     65		vfree(p_dbg_data_buf);
     66		return err;
     67	}
     68
     69	err = devlink_fmsg_binary_pair_put(fmsg, "dump_data",
     70					   p_dbg_data_buf, dbg_data_buf_size);
     71
     72	vfree(p_dbg_data_buf);
     73
     74	return err;
     75}
     76
     77static int
     78qed_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
     79			      void *priv_ctx,
     80			      struct netlink_ext_ack *extack)
     81{
     82	struct qed_devlink *qdl = devlink_health_reporter_priv(reporter);
     83	struct qed_dev *cdev = qdl->cdev;
     84
     85	qed_recovery_process(cdev);
     86
     87	return 0;
     88}
     89
     90static const struct devlink_health_reporter_ops qed_fw_fatal_reporter_ops = {
     91		.name = "fw_fatal",
     92		.recover = qed_fw_fatal_reporter_recover,
     93		.dump = qed_fw_fatal_reporter_dump,
     94};
     95
     96#define QED_REPORTER_FW_GRACEFUL_PERIOD 0
     97
     98void qed_fw_reporters_create(struct devlink *devlink)
     99{
    100	struct qed_devlink *dl = devlink_priv(devlink);
    101
    102	dl->fw_reporter = devlink_health_reporter_create(devlink, &qed_fw_fatal_reporter_ops,
    103							 QED_REPORTER_FW_GRACEFUL_PERIOD, dl);
    104	if (IS_ERR(dl->fw_reporter)) {
    105		DP_NOTICE(dl->cdev, "Failed to create fw reporter, err = %ld\n",
    106			  PTR_ERR(dl->fw_reporter));
    107		dl->fw_reporter = NULL;
    108	}
    109}
    110
    111void qed_fw_reporters_destroy(struct devlink *devlink)
    112{
    113	struct qed_devlink *dl = devlink_priv(devlink);
    114	struct devlink_health_reporter *rep;
    115
    116	rep = dl->fw_reporter;
    117
    118	if (!IS_ERR_OR_NULL(rep))
    119		devlink_health_reporter_destroy(rep);
    120}
    121
    122static int qed_dl_param_get(struct devlink *dl, u32 id,
    123			    struct devlink_param_gset_ctx *ctx)
    124{
    125	struct qed_devlink *qed_dl = devlink_priv(dl);
    126	struct qed_dev *cdev;
    127
    128	cdev = qed_dl->cdev;
    129	ctx->val.vbool = cdev->iwarp_cmt;
    130
    131	return 0;
    132}
    133
    134static int qed_dl_param_set(struct devlink *dl, u32 id,
    135			    struct devlink_param_gset_ctx *ctx)
    136{
    137	struct qed_devlink *qed_dl = devlink_priv(dl);
    138	struct qed_dev *cdev;
    139
    140	cdev = qed_dl->cdev;
    141	cdev->iwarp_cmt = ctx->val.vbool;
    142
    143	return 0;
    144}
    145
    146static const struct devlink_param qed_devlink_params[] = {
    147	DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT,
    148			     "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL,
    149			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
    150			     qed_dl_param_get, qed_dl_param_set, NULL),
    151};
    152
    153static int qed_devlink_info_get(struct devlink *devlink,
    154				struct devlink_info_req *req,
    155				struct netlink_ext_ack *extack)
    156{
    157	struct qed_devlink *qed_dl = devlink_priv(devlink);
    158	struct qed_dev *cdev = qed_dl->cdev;
    159	struct qed_dev_info *dev_info;
    160	char buf[100];
    161	int err;
    162
    163	dev_info = &cdev->common_dev_info;
    164
    165	err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
    166	if (err)
    167		return err;
    168
    169	memcpy(buf, cdev->hwfns[0].hw_info.part_num, sizeof(cdev->hwfns[0].hw_info.part_num));
    170	buf[sizeof(cdev->hwfns[0].hw_info.part_num)] = 0;
    171
    172	if (buf[0]) {
    173		err = devlink_info_board_serial_number_put(req, buf);
    174		if (err)
    175			return err;
    176	}
    177
    178	snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
    179		 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_3),
    180		 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_2),
    181		 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_1),
    182		 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_0));
    183
    184	err = devlink_info_version_stored_put(req,
    185					      DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, buf);
    186	if (err)
    187		return err;
    188
    189	snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
    190		 dev_info->fw_major,
    191		 dev_info->fw_minor,
    192		 dev_info->fw_rev,
    193		 dev_info->fw_eng);
    194
    195	return devlink_info_version_running_put(req,
    196						DEVLINK_INFO_VERSION_GENERIC_FW_APP, buf);
    197}
    198
    199static const struct devlink_ops qed_dl_ops = {
    200	.info_get = qed_devlink_info_get,
    201};
    202
    203struct devlink *qed_devlink_register(struct qed_dev *cdev)
    204{
    205	union devlink_param_value value;
    206	struct qed_devlink *qdevlink;
    207	struct devlink *dl;
    208	int rc;
    209
    210	dl = devlink_alloc(&qed_dl_ops, sizeof(struct qed_devlink),
    211			   &cdev->pdev->dev);
    212	if (!dl)
    213		return ERR_PTR(-ENOMEM);
    214
    215	qdevlink = devlink_priv(dl);
    216	qdevlink->cdev = cdev;
    217
    218	rc = devlink_params_register(dl, qed_devlink_params,
    219				     ARRAY_SIZE(qed_devlink_params));
    220	if (rc)
    221		goto err_unregister;
    222
    223	value.vbool = false;
    224	devlink_param_driverinit_value_set(dl,
    225					   QED_DEVLINK_PARAM_ID_IWARP_CMT,
    226					   value);
    227
    228	cdev->iwarp_cmt = false;
    229
    230	qed_fw_reporters_create(dl);
    231	devlink_register(dl);
    232	return dl;
    233
    234err_unregister:
    235	devlink_free(dl);
    236
    237	return ERR_PTR(rc);
    238}
    239
    240void qed_devlink_unregister(struct devlink *devlink)
    241{
    242	if (!devlink)
    243		return;
    244
    245	devlink_unregister(devlink);
    246	qed_fw_reporters_destroy(devlink);
    247
    248	devlink_params_unregister(devlink, qed_devlink_params,
    249				  ARRAY_SIZE(qed_devlink_params));
    250
    251	devlink_free(devlink);
    252}