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