Loading...
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}
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}