• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
pdsc_devcmd_fw_download_locked(struct pdsc * pdsc,u64 addr,u32 offset,u32 length)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 
pdsc_devcmd_fw_install(struct pdsc * pdsc)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 
pdsc_devcmd_fw_activate(struct pdsc * pdsc,enum pds_core_fw_slot slot)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 
pdsc_fw_status_long_wait(struct pdsc * pdsc,const char * label,unsigned long timeout,u8 fw_cmd,struct netlink_ext_ack * extack)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 
pdsc_firmware_update(struct pdsc * pdsc,const struct firmware * fw,struct netlink_ext_ack * extack)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 	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 
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;
197 }
198