Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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		       struct netlink_ext_ack *extack)
 42{
 43	struct pdsc *pdsc = devlink_priv(dl);
 44	struct pdsc_viftype *vt_entry;
 45	int err = 0;
 46	int vf_id;
 47
 48	vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id);
 49	if (!vt_entry || !vt_entry->supported)
 50		return -EOPNOTSUPP;
 51
 52	if (vt_entry->enabled == ctx->val.vbool)
 53		return 0;
 54
 55	vt_entry->enabled = ctx->val.vbool;
 56	for (vf_id = 0; vf_id < pdsc->num_vfs; vf_id++) {
 57		struct pdsc *vf = pdsc->vfs[vf_id].vf;
 58
 59		err = ctx->val.vbool ? pdsc_auxbus_dev_add(vf, pdsc) :
 60				       pdsc_auxbus_dev_del(vf, pdsc);
 61	}
 62
 63	return err;
 64}
 65
 66int pdsc_dl_enable_validate(struct devlink *dl, u32 id,
 67			    union devlink_param_value val,
 68			    struct netlink_ext_ack *extack)
 69{
 70	struct pdsc *pdsc = devlink_priv(dl);
 71	struct pdsc_viftype *vt_entry;
 72
 73	vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id);
 74	if (!vt_entry || !vt_entry->supported)
 75		return -EOPNOTSUPP;
 76
 77	if (!pdsc->viftype_status[vt_entry->vif_id].supported)
 78		return -ENODEV;
 79
 80	return 0;
 81}
 82
 83int pdsc_dl_flash_update(struct devlink *dl,
 84			 struct devlink_flash_update_params *params,
 85			 struct netlink_ext_ack *extack)
 86{
 87	struct pdsc *pdsc = devlink_priv(dl);
 88
 89	return pdsc_firmware_update(pdsc, params->fw, extack);
 90}
 91
 92static char *fw_slotnames[] = {
 93	"fw.goldfw",
 94	"fw.mainfwa",
 95	"fw.mainfwb",
 96};
 97
 98int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
 99		     struct netlink_ext_ack *extack)
100{
101	union pds_core_dev_cmd cmd = {
102		.fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,
103		.fw_control.oper = PDS_CORE_FW_GET_LIST,
104	};
105	struct pds_core_fw_list_info fw_list;
106	struct pdsc *pdsc = devlink_priv(dl);
107	union pds_core_dev_comp comp;
108	char buf[32];
109	int listlen;
110	int err;
111	int i;
112
113	mutex_lock(&pdsc->devcmd_lock);
114	err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2);
115	if (!err)
116		memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
117	mutex_unlock(&pdsc->devcmd_lock);
118	if (err && err != -EIO)
119		return err;
120
121	listlen = min(fw_list.num_fw_slots, ARRAY_SIZE(fw_list.fw_names));
122	for (i = 0; i < listlen; i++) {
123		if (i < ARRAY_SIZE(fw_slotnames))
124			strscpy(buf, fw_slotnames[i], sizeof(buf));
125		else
126			snprintf(buf, sizeof(buf), "fw.slot_%d", i);
127		err = devlink_info_version_stored_put(req, buf,
128						      fw_list.fw_names[i].fw_version);
129		if (err)
130			return err;
131	}
132
133	err = devlink_info_version_running_put(req,
134					       DEVLINK_INFO_VERSION_GENERIC_FW,
135					       pdsc->dev_info.fw_version);
136	if (err)
137		return err;
138
139	snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_type);
140	err = devlink_info_version_fixed_put(req,
141					     DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
142					     buf);
143	if (err)
144		return err;
145
146	snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_rev);
147	err = devlink_info_version_fixed_put(req,
148					     DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
149					     buf);
150	if (err)
151		return err;
152
153	return devlink_info_serial_number_put(req, pdsc->dev_info.serial_num);
154}
155
156int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
157			      struct devlink_fmsg *fmsg,
158			      struct netlink_ext_ack *extack)
159{
160	struct pdsc *pdsc = devlink_health_reporter_priv(reporter);
161
162	mutex_lock(&pdsc->config_lock);
163	if (test_bit(PDSC_S_FW_DEAD, &pdsc->state))
164		devlink_fmsg_string_pair_put(fmsg, "Status", "dead");
165	else if (!pdsc_is_fw_good(pdsc))
166		devlink_fmsg_string_pair_put(fmsg, "Status", "unhealthy");
167	else
168		devlink_fmsg_string_pair_put(fmsg, "Status", "healthy");
169	mutex_unlock(&pdsc->config_lock);
170
171	devlink_fmsg_u32_pair_put(fmsg, "State",
172				  pdsc->fw_status & ~PDS_CORE_FW_STS_F_GENERATION);
173	devlink_fmsg_u32_pair_put(fmsg, "Generation", pdsc->fw_generation >> 4);
174	devlink_fmsg_u32_pair_put(fmsg, "Recoveries", pdsc->fw_recoveries);
175
176	return 0;
177}