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