Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 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_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
 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 = slot
 54	};
 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 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
 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	else
194		devlink_flash_update_status_notify(dl, "Flash done",
195						   NULL, 0, 0);
196	return err;
197}