198 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2023 Advanced Micro Devices, Inc */3 4#include "core.h"5 6/* The worst case wait for the install activity is about 25 minutes when7 * installing a new CPLD, which is very seldom. Normal is about 30-358 * seconds. Since the driver can't tell if a CPLD update will happen we9 * set the timeout for the ugly case.10 */11#define PDSC_FW_INSTALL_TIMEOUT (25 * 60)12#define PDSC_FW_SELECT_TIMEOUT 3013 14/* Number of periodic log updates during fw file download */15#define PDSC_FW_INTERVAL_FRACTION 3216 17static int pdsc_devcmd_fw_download_locked(struct pdsc *pdsc, u64 addr,18 u32 offset, u32 length)19{20 union pds_core_dev_cmd cmd = {21 .fw_download.opcode = PDS_CORE_CMD_FW_DOWNLOAD,22 .fw_download.offset = cpu_to_le32(offset),23 .fw_download.addr = cpu_to_le64(addr),24 .fw_download.length = cpu_to_le32(length),25 };26 union pds_core_dev_comp comp;27 28 return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout);29}30 31static int pdsc_devcmd_fw_install(struct pdsc *pdsc)32{33 union pds_core_dev_cmd cmd = {34 .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,35 .fw_control.oper = PDS_CORE_FW_INSTALL_ASYNC36 };37 union pds_core_dev_comp comp;38 int err;39 40 err = pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);41 if (err < 0)42 return err;43 44 return comp.fw_control.slot;45}46 47static int pdsc_devcmd_fw_activate(struct pdsc *pdsc,48 enum pds_core_fw_slot slot)49{50 union pds_core_dev_cmd cmd = {51 .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,52 .fw_control.oper = PDS_CORE_FW_ACTIVATE_ASYNC,53 .fw_control.slot = slot54 };55 union pds_core_dev_comp comp;56 57 return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);58}59 60static int pdsc_fw_status_long_wait(struct pdsc *pdsc,61 const char *label,62 unsigned long timeout,63 u8 fw_cmd,64 struct netlink_ext_ack *extack)65{66 union pds_core_dev_cmd cmd = {67 .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,68 .fw_control.oper = fw_cmd,69 };70 union pds_core_dev_comp comp;71 unsigned long start_time;72 unsigned long end_time;73 int err;74 75 /* Ping on the status of the long running async install76 * command. We get EAGAIN while the command is still77 * running, else we get the final command status.78 */79 start_time = jiffies;80 end_time = start_time + (timeout * HZ);81 do {82 err = pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);83 msleep(20);84 } while (time_before(jiffies, end_time) &&85 (err == -EAGAIN || err == -ETIMEDOUT));86 87 if (err == -EAGAIN || err == -ETIMEDOUT) {88 NL_SET_ERR_MSG_MOD(extack, "Firmware wait timed out");89 dev_err(pdsc->dev, "DEV_CMD firmware wait %s timed out\n",90 label);91 } else if (err) {92 NL_SET_ERR_MSG_MOD(extack, "Firmware wait failed");93 }94 95 return err;96}97 98int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,99 struct netlink_ext_ack *extack)100{101 u32 buf_sz, copy_sz, offset;102 struct devlink *dl;103 int next_interval;104 u64 data_addr;105 int err = 0;106 int fw_slot;107 108 dev_info(pdsc->dev, "Installing firmware\n");109 110 if (!pdsc->cmd_regs)111 return -ENXIO;112 113 dl = priv_to_devlink(pdsc);114 devlink_flash_update_status_notify(dl, "Preparing to flash",115 NULL, 0, 0);116 117 buf_sz = sizeof(pdsc->cmd_regs->data);118 119 dev_dbg(pdsc->dev,120 "downloading firmware - size %d part_sz %d nparts %lu\n",121 (int)fw->size, buf_sz, DIV_ROUND_UP(fw->size, buf_sz));122 123 offset = 0;124 next_interval = 0;125 data_addr = offsetof(struct pds_core_dev_cmd_regs, data);126 while (offset < fw->size) {127 if (offset >= next_interval) {128 devlink_flash_update_status_notify(dl, "Downloading",129 NULL, offset,130 fw->size);131 next_interval = offset +132 (fw->size / PDSC_FW_INTERVAL_FRACTION);133 }134 135 copy_sz = min_t(unsigned int, buf_sz, fw->size - offset);136 mutex_lock(&pdsc->devcmd_lock);137 memcpy_toio(&pdsc->cmd_regs->data, fw->data + offset, copy_sz);138 err = pdsc_devcmd_fw_download_locked(pdsc, data_addr,139 offset, copy_sz);140 mutex_unlock(&pdsc->devcmd_lock);141 if (err) {142 dev_err(pdsc->dev,143 "download failed offset 0x%x addr 0x%llx len 0x%x: %pe\n",144 offset, data_addr, copy_sz, ERR_PTR(err));145 NL_SET_ERR_MSG_MOD(extack, "Segment download failed");146 goto err_out;147 }148 offset += copy_sz;149 }150 devlink_flash_update_status_notify(dl, "Downloading", NULL,151 fw->size, fw->size);152 153 devlink_flash_update_timeout_notify(dl, "Installing", NULL,154 PDSC_FW_INSTALL_TIMEOUT);155 156 fw_slot = pdsc_devcmd_fw_install(pdsc);157 if (fw_slot < 0) {158 err = fw_slot;159 dev_err(pdsc->dev, "install failed: %pe\n", ERR_PTR(err));160 NL_SET_ERR_MSG_MOD(extack, "Failed to start firmware install");161 goto err_out;162 }163 164 err = pdsc_fw_status_long_wait(pdsc, "Installing",165 PDSC_FW_INSTALL_TIMEOUT,166 PDS_CORE_FW_INSTALL_STATUS,167 extack);168 if (err)169 goto err_out;170 171 devlink_flash_update_timeout_notify(dl, "Selecting", NULL,172 PDSC_FW_SELECT_TIMEOUT);173 174 err = pdsc_devcmd_fw_activate(pdsc, fw_slot);175 if (err) {176 NL_SET_ERR_MSG_MOD(extack, "Failed to start firmware select");177 goto err_out;178 }179 180 err = pdsc_fw_status_long_wait(pdsc, "Selecting",181 PDSC_FW_SELECT_TIMEOUT,182 PDS_CORE_FW_ACTIVATE_STATUS,183 extack);184 if (err)185 goto err_out;186 187 dev_info(pdsc->dev, "Firmware update completed, slot %d\n", fw_slot);188 189err_out:190 if (err)191 devlink_flash_update_status_notify(dl, "Flash failed",192 NULL, 0, 0);193 else194 devlink_flash_update_status_notify(dl, "Flash done",195 NULL, 0, 0);196 return err;197}198