Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / ethernet / amd / pds_core / fw.c
blobfa626719e68d1b206fc9bbe1d038daf51984f19b
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2023 Advanced Micro Devices, Inc */
4 #include "core.h"
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.
11 #define PDSC_FW_INSTALL_TIMEOUT (25 * 60)
12 #define PDSC_FW_SELECT_TIMEOUT 30
14 /* Number of periodic log updates during fw file download */
15 #define PDSC_FW_INTERVAL_FRACTION 32
17 static int pdsc_devcmd_fw_download_locked(struct pdsc *pdsc, u64 addr,
18 u32 offset, u32 length)
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),
26 union pds_core_dev_comp comp;
28 return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
31 static int pdsc_devcmd_fw_install(struct pdsc *pdsc)
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
37 union pds_core_dev_comp comp;
38 int err;
40 err = pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
41 if (err < 0)
42 return err;
44 return comp.fw_control.slot;
47 static int pdsc_devcmd_fw_activate(struct pdsc *pdsc,
48 enum pds_core_fw_slot slot)
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
55 union pds_core_dev_comp comp;
57 return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
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)
66 union pds_core_dev_cmd cmd = {
67 .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,
68 .fw_control.oper = fw_cmd,
70 union pds_core_dev_comp comp;
71 unsigned long start_time;
72 unsigned long end_time;
73 int err;
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.
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));
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");
95 return err;
98 int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,
99 struct netlink_ext_ack *extack)
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;
108 dev_info(pdsc->dev, "Installing firmware\n");
110 if (!pdsc->cmd_regs)
111 return -ENXIO;
113 dl = priv_to_devlink(pdsc);
114 devlink_flash_update_status_notify(dl, "Preparing to flash",
115 NULL, 0, 0);
117 buf_sz = sizeof(pdsc->cmd_regs->data);
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));
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);
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;
148 offset += copy_sz;
150 devlink_flash_update_status_notify(dl, "Downloading", NULL,
151 fw->size, fw->size);
153 devlink_flash_update_timeout_notify(dl, "Installing", NULL,
154 PDSC_FW_INSTALL_TIMEOUT);
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;
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;
171 devlink_flash_update_timeout_notify(dl, "Selecting", NULL,
172 PDSC_FW_SELECT_TIMEOUT);
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;
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;
187 dev_info(pdsc->dev, "Firmware update completed, slot %d\n", fw_slot);
189 err_out:
190 if (err)
191 devlink_flash_update_status_notify(dl, "Flash failed",
192 NULL, 0, 0);
193 else
194 devlink_flash_update_status_notify(dl, "Flash done",
195 NULL, 0, 0);
196 return err;