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
pdsc_dl_find_viftype_by_id(struct pdsc * pdsc,enum devlink_param_type dl_id)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 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
pdsc_dl_enable_get(struct devlink * dl,u32 id,struct devlink_param_gset_ctx * ctx)24 int 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
pdsc_dl_enable_set(struct devlink * dl,u32 id,struct devlink_param_gset_ctx * ctx)39 int 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 if (ctx->val.vbool)
59 err = pdsc_auxbus_dev_add(vf, pdsc, vt_entry->vif_id,
60 &pdsc->vfs[vf_id].padev);
61 else
62 pdsc_auxbus_dev_del(vf, pdsc, &pdsc->vfs[vf_id].padev);
63 }
64
65 return err;
66 }
67
pdsc_dl_enable_validate(struct devlink * dl,u32 id,union devlink_param_value val,struct netlink_ext_ack * extack)68 int pdsc_dl_enable_validate(struct devlink *dl, u32 id,
69 union devlink_param_value val,
70 struct netlink_ext_ack *extack)
71 {
72 struct pdsc *pdsc = devlink_priv(dl);
73 struct pdsc_viftype *vt_entry;
74
75 vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id);
76 if (!vt_entry || !vt_entry->supported)
77 return -EOPNOTSUPP;
78
79 if (!pdsc->viftype_status[vt_entry->vif_id].supported)
80 return -ENODEV;
81
82 return 0;
83 }
84
pdsc_dl_flash_update(struct devlink * dl,struct devlink_flash_update_params * params,struct netlink_ext_ack * extack)85 int pdsc_dl_flash_update(struct devlink *dl,
86 struct devlink_flash_update_params *params,
87 struct netlink_ext_ack *extack)
88 {
89 struct pdsc *pdsc = devlink_priv(dl);
90
91 return pdsc_firmware_update(pdsc, params->fw, extack);
92 }
93
94 static char *fw_slotnames[] = {
95 "fw.goldfw",
96 "fw.mainfwa",
97 "fw.mainfwb",
98 };
99
pdsc_dl_info_get(struct devlink * dl,struct devlink_info_req * req,struct netlink_ext_ack * extack)100 int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
101 struct netlink_ext_ack *extack)
102 {
103 union pds_core_dev_cmd cmd = {
104 .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,
105 .fw_control.oper = PDS_CORE_FW_GET_LIST,
106 };
107 struct pds_core_fw_list_info fw_list = {};
108 struct pdsc *pdsc = devlink_priv(dl);
109 union pds_core_dev_comp comp;
110 char buf[32];
111 int listlen;
112 int err;
113 int i;
114
115 mutex_lock(&pdsc->devcmd_lock);
116 err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2);
117 if (!err)
118 memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
119 mutex_unlock(&pdsc->devcmd_lock);
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 }
130
131 err = devlink_info_version_running_put(req,
132 DEVLINK_INFO_VERSION_GENERIC_FW,
133 pdsc->dev_info.fw_version);
134 if (err)
135 return err;
136
137 snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_type);
138 err = devlink_info_version_fixed_put(req,
139 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
140 buf);
141 if (err)
142 return err;
143
144 snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_rev);
145 err = devlink_info_version_fixed_put(req,
146 DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
147 buf);
148 if (err)
149 return err;
150
151 return devlink_info_serial_number_put(req, pdsc->dev_info.serial_num);
152 }
153
pdsc_fw_reporter_diagnose(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,struct netlink_ext_ack * extack)154 int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
155 struct devlink_fmsg *fmsg,
156 struct netlink_ext_ack *extack)
157 {
158 struct pdsc *pdsc = devlink_health_reporter_priv(reporter);
159 int err;
160
161 mutex_lock(&pdsc->config_lock);
162
163 if (test_bit(PDSC_S_FW_DEAD, &pdsc->state))
164 err = devlink_fmsg_string_pair_put(fmsg, "Status", "dead");
165 else if (!pdsc_is_fw_good(pdsc))
166 err = devlink_fmsg_string_pair_put(fmsg, "Status", "unhealthy");
167 else
168 err = devlink_fmsg_string_pair_put(fmsg, "Status", "healthy");
169
170 mutex_unlock(&pdsc->config_lock);
171
172 if (err)
173 return err;
174
175 err = devlink_fmsg_u32_pair_put(fmsg, "State",
176 pdsc->fw_status &
177 ~PDS_CORE_FW_STS_F_GENERATION);
178 if (err)
179 return err;
180
181 err = devlink_fmsg_u32_pair_put(fmsg, "Generation",
182 pdsc->fw_generation >> 4);
183 if (err)
184 return err;
185
186 return devlink_fmsg_u32_pair_put(fmsg, "Recoveries",
187 pdsc->fw_recoveries);
188 }
189