brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · fa62671 Raw
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