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