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