Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright(c) 2023 Advanced Micro Devices, Inc */
  3
  4#include "core.h"
  5#include <linux/pds/pds_auxbus.h>
  6
  7static struct
  8pdsc_viftype *pdsc_dl_find_viftype_by_id(struct pdsc *pdsc,
  9					 enum devlink_param_type dl_id)
 10{
 11	int vt;
 12
 13	if (!pdsc->viftype_status)
 14		return NULL;
 15
 16	for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) {
 17		if (pdsc->viftype_status[vt].dl_id == dl_id)
 18			return &pdsc->viftype_status[vt];
 19	}
 20
 21	return NULL;
 22}
 23
 24int pdsc_dl_enable_get(struct devlink *dl, u32 id,
 25		       struct devlink_param_gset_ctx *ctx)
 26{
 27	struct pdsc *pdsc = devlink_priv(dl);
 28	struct pdsc_viftype *vt_entry;
 29
 30	vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id);
 31	if (!vt_entry)
 32		return -ENOENT;
 33
 34	ctx->val.vbool = vt_entry->enabled;
 35
 36	return 0;
 37}
 38
 39int pdsc_dl_enable_set(struct devlink *dl, u32 id,
 40		       struct devlink_param_gset_ctx *ctx)
 41{
 42	struct pdsc *pdsc = devlink_priv(dl);
 43	struct pdsc_viftype *vt_entry;
 44	int err = 0;
 45	int vf_id;
 46
 47	vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id);
 48	if (!vt_entry || !vt_entry->supported)
 49		return -EOPNOTSUPP;
 50
 51	if (vt_entry->enabled == ctx->val.vbool)
 52		return 0;
 53
 54	vt_entry->enabled = ctx->val.vbool;
 55	for (vf_id = 0; vf_id < pdsc->num_vfs; vf_id++) {
 56		struct pdsc *vf = pdsc->vfs[vf_id].vf;
 57
 58		err = ctx->val.vbool ? pdsc_auxbus_dev_add(vf, pdsc) :
 59				       pdsc_auxbus_dev_del(vf, pdsc);
 60	}
 61
 62	return err;
 63}
 64
 65int pdsc_dl_enable_validate(struct devlink *dl, u32 id,
 66			    union devlink_param_value val,
 67			    struct netlink_ext_ack *extack)
 68{
 69	struct pdsc *pdsc = devlink_priv(dl);
 70	struct pdsc_viftype *vt_entry;
 71
 72	vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id);
 73	if (!vt_entry || !vt_entry->supported)
 74		return -EOPNOTSUPP;
 75
 76	if (!pdsc->viftype_status[vt_entry->vif_id].supported)
 77		return -ENODEV;
 78
 79	return 0;
 80}
 81
 82int pdsc_dl_flash_update(struct devlink *dl,
 83			 struct devlink_flash_update_params *params,
 84			 struct netlink_ext_ack *extack)
 85{
 86	struct pdsc *pdsc = devlink_priv(dl);
 87
 88	return pdsc_firmware_update(pdsc, params->fw, extack);
 89}
 90
 91static char *fw_slotnames[] = {
 92	"fw.goldfw",
 93	"fw.mainfwa",
 94	"fw.mainfwb",
 95};
 96
 97int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
 98		     struct netlink_ext_ack *extack)
 99{
100	union pds_core_dev_cmd cmd = {
101		.fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,
102		.fw_control.oper = PDS_CORE_FW_GET_LIST,
103	};
104	struct pds_core_fw_list_info fw_list;
105	struct pdsc *pdsc = devlink_priv(dl);
106	union pds_core_dev_comp comp;
107	char buf[32];
108	int listlen;
109	int err;
110	int i;
111
112	mutex_lock(&pdsc->devcmd_lock);
113	err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2);
114	if (!err)
115		memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
116	mutex_unlock(&pdsc->devcmd_lock);
117	if (err && err != -EIO)
118		return err;
119
120	listlen = fw_list.num_fw_slots;
121	for (i = 0; i < listlen; i++) {
122		if (i < ARRAY_SIZE(fw_slotnames))
123			strscpy(buf, fw_slotnames[i], sizeof(buf));
124		else
125			snprintf(buf, sizeof(buf), "fw.slot_%d", i);
126		err = devlink_info_version_stored_put(req, buf,
127						      fw_list.fw_names[i].fw_version);
128		if (err)
129			return err;
130	}
131
132	err = devlink_info_version_running_put(req,
133					       DEVLINK_INFO_VERSION_GENERIC_FW,
134					       pdsc->dev_info.fw_version);
135	if (err)
136		return err;
137
138	snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_type);
139	err = devlink_info_version_fixed_put(req,
140					     DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
141					     buf);
142	if (err)
143		return err;
144
145	snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_rev);
146	err = devlink_info_version_fixed_put(req,
147					     DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
148					     buf);
149	if (err)
150		return err;
151
152	return devlink_info_serial_number_put(req, pdsc->dev_info.serial_num);
153}
154
155int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
156			      struct devlink_fmsg *fmsg,
157			      struct netlink_ext_ack *extack)
158{
159	struct pdsc *pdsc = devlink_health_reporter_priv(reporter);
160
161	mutex_lock(&pdsc->config_lock);
162	if (test_bit(PDSC_S_FW_DEAD, &pdsc->state))
163		devlink_fmsg_string_pair_put(fmsg, "Status", "dead");
164	else if (!pdsc_is_fw_good(pdsc))
165		devlink_fmsg_string_pair_put(fmsg, "Status", "unhealthy");
166	else
167		devlink_fmsg_string_pair_put(fmsg, "Status", "healthy");
168	mutex_unlock(&pdsc->config_lock);
169
170	devlink_fmsg_u32_pair_put(fmsg, "State",
171				  pdsc->fw_status & ~PDS_CORE_FW_STS_F_GENERATION);
172	devlink_fmsg_u32_pair_put(fmsg, "Generation", pdsc->fw_generation >> 4);
173	devlink_fmsg_u32_pair_put(fmsg, "Recoveries", pdsc->fw_recoveries);
174
175	return 0;
176}