Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pds_core: add FW update feature to devlink

Add in the support for doing firmware updates. Of the two
main banks available, a and b, this updates the one not in
use and then selects it for the next boot.

Example:
devlink dev flash pci/0000:b2:00.0 \
file pensando/dsc_fw_1.63.0-22.tar

Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Shannon Nelson and committed by
David S. Miller
49ce92fb 01ba61b5

+221 -1
+10
Documentation/networking/device_drivers/ethernet/amd/pds_core.rst
··· 73 73 - fixed 74 74 - The revision of the ASIC for this device 75 75 76 + Firmware Management 77 + =================== 78 + 79 + The ``flash`` command can update a the DSC firmware. The downloaded firmware 80 + will be saved into either of firmware bank 1 or bank 2, whichever is not 81 + currently in use, and that bank will used for the next boot:: 82 + 83 + # devlink dev flash pci/0000:b5:00.0 \ 84 + file pensando/dsc_fw_1.63.0-22.tar 85 + 76 86 Health Reporters 77 87 ================ 78 88
+2 -1
drivers/net/ethernet/amd/pds_core/Makefile
··· 7 7 devlink.o \ 8 8 dev.o \ 9 9 adminq.o \ 10 - core.o 10 + core.o \ 11 + fw.o 11 12 12 13 pds_core-$(CONFIG_DEBUG_FS) += debugfs.o
+5
drivers/net/ethernet/amd/pds_core/core.h
··· 226 226 struct netlink_ext_ack *extack); 227 227 int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 228 228 struct netlink_ext_ack *extack); 229 + int pdsc_dl_flash_update(struct devlink *dl, 230 + struct devlink_flash_update_params *params, 231 + struct netlink_ext_ack *extack); 229 232 230 233 void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num); 231 234 ··· 271 268 void pdsc_work_thread(struct work_struct *work); 272 269 irqreturn_t pdsc_adminq_isr(int irq, void *data); 273 270 271 + int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw, 272 + struct netlink_ext_ack *extack); 274 273 #endif /* _PDSC_H_ */
+9
drivers/net/ethernet/amd/pds_core/devlink.c
··· 3 3 4 4 #include "core.h" 5 5 6 + int pdsc_dl_flash_update(struct devlink *dl, 7 + struct devlink_flash_update_params *params, 8 + struct netlink_ext_ack *extack) 9 + { 10 + struct pdsc *pdsc = devlink_priv(dl); 11 + 12 + return pdsc_firmware_update(pdsc, params->fw, extack); 13 + } 14 + 6 15 static char *fw_slotnames[] = { 7 16 "fw.goldfw", 8 17 "fw.mainfwa",
+194
drivers/net/ethernet/amd/pds_core/fw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 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 when 7 + * installing a new CPLD, which is very seldom. Normal is about 30-35 8 + * seconds. Since the driver can't tell if a CPLD update will happen we 9 + * set the timeout for the ugly case. 10 + */ 11 + #define PDSC_FW_INSTALL_TIMEOUT (25 * 60) 12 + #define PDSC_FW_SELECT_TIMEOUT 30 13 + 14 + /* Number of periodic log updates during fw file download */ 15 + #define PDSC_FW_INTERVAL_FRACTION 32 16 + 17 + static 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 + 31 + static 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_ASYNC 36 + }; 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 + 47 + static 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 = slot 54 + }; 55 + union pds_core_dev_comp comp; 56 + 57 + return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 58 + } 59 + 60 + static 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 install 76 + * command. We get EAGAIN while the command is still 77 + * 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 + 98 + int 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 + dl = priv_to_devlink(pdsc); 111 + devlink_flash_update_status_notify(dl, "Preparing to flash", 112 + NULL, 0, 0); 113 + 114 + buf_sz = sizeof(pdsc->cmd_regs->data); 115 + 116 + dev_dbg(pdsc->dev, 117 + "downloading firmware - size %d part_sz %d nparts %lu\n", 118 + (int)fw->size, buf_sz, DIV_ROUND_UP(fw->size, buf_sz)); 119 + 120 + offset = 0; 121 + next_interval = 0; 122 + data_addr = offsetof(struct pds_core_dev_cmd_regs, data); 123 + while (offset < fw->size) { 124 + if (offset >= next_interval) { 125 + devlink_flash_update_status_notify(dl, "Downloading", 126 + NULL, offset, 127 + fw->size); 128 + next_interval = offset + 129 + (fw->size / PDSC_FW_INTERVAL_FRACTION); 130 + } 131 + 132 + copy_sz = min_t(unsigned int, buf_sz, fw->size - offset); 133 + mutex_lock(&pdsc->devcmd_lock); 134 + memcpy_toio(&pdsc->cmd_regs->data, fw->data + offset, copy_sz); 135 + err = pdsc_devcmd_fw_download_locked(pdsc, data_addr, 136 + offset, copy_sz); 137 + mutex_unlock(&pdsc->devcmd_lock); 138 + if (err) { 139 + dev_err(pdsc->dev, 140 + "download failed offset 0x%x addr 0x%llx len 0x%x: %pe\n", 141 + offset, data_addr, copy_sz, ERR_PTR(err)); 142 + NL_SET_ERR_MSG_MOD(extack, "Segment download failed"); 143 + goto err_out; 144 + } 145 + offset += copy_sz; 146 + } 147 + devlink_flash_update_status_notify(dl, "Downloading", NULL, 148 + fw->size, fw->size); 149 + 150 + devlink_flash_update_timeout_notify(dl, "Installing", NULL, 151 + PDSC_FW_INSTALL_TIMEOUT); 152 + 153 + fw_slot = pdsc_devcmd_fw_install(pdsc); 154 + if (fw_slot < 0) { 155 + err = fw_slot; 156 + dev_err(pdsc->dev, "install failed: %pe\n", ERR_PTR(err)); 157 + NL_SET_ERR_MSG_MOD(extack, "Failed to start firmware install"); 158 + goto err_out; 159 + } 160 + 161 + err = pdsc_fw_status_long_wait(pdsc, "Installing", 162 + PDSC_FW_INSTALL_TIMEOUT, 163 + PDS_CORE_FW_INSTALL_STATUS, 164 + extack); 165 + if (err) 166 + goto err_out; 167 + 168 + devlink_flash_update_timeout_notify(dl, "Selecting", NULL, 169 + PDSC_FW_SELECT_TIMEOUT); 170 + 171 + err = pdsc_devcmd_fw_activate(pdsc, fw_slot); 172 + if (err) { 173 + NL_SET_ERR_MSG_MOD(extack, "Failed to start firmware select"); 174 + goto err_out; 175 + } 176 + 177 + err = pdsc_fw_status_long_wait(pdsc, "Selecting", 178 + PDSC_FW_SELECT_TIMEOUT, 179 + PDS_CORE_FW_ACTIVATE_STATUS, 180 + extack); 181 + if (err) 182 + goto err_out; 183 + 184 + dev_info(pdsc->dev, "Firmware update completed, slot %d\n", fw_slot); 185 + 186 + err_out: 187 + if (err) 188 + devlink_flash_update_status_notify(dl, "Flash failed", 189 + NULL, 0, 0); 190 + else 191 + devlink_flash_update_status_notify(dl, "Flash done", 192 + NULL, 0, 0); 193 + return err; 194 + }
+1
drivers/net/ethernet/amd/pds_core/main.c
··· 228 228 229 229 static const struct devlink_ops pdsc_dl_ops = { 230 230 .info_get = pdsc_dl_info_get, 231 + .flash_update = pdsc_dl_flash_update, 231 232 }; 232 233 233 234 static const struct devlink_ops pdsc_dl_vf_ops = {