static int hl_fw_static_init_cpu()

in habanalabs/common/firmware_if.c [2473:2664]


static int hl_fw_static_init_cpu(struct hl_device *hdev,
					struct fw_load_mgr *fw_loader)
{
	u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status;
	u32 cpu_boot_dev_status0_reg, cpu_boot_dev_status1_reg;
	struct static_fw_load_mgr *static_loader;
	u32 cpu_boot_status_reg;
	int rc;

	if (!(hdev->fw_components & FW_TYPE_BOOT_CPU))
		return 0;

	/* init common loader parameters */
	cpu_timeout = fw_loader->cpu_timeout;

	/* init static loader parameters */
	static_loader = &fw_loader->static_loader;
	cpu_msg_status_reg = static_loader->cpu_cmd_status_to_host_reg;
	msg_to_cpu_reg = static_loader->kmd_msg_to_cpu_reg;
	cpu_boot_dev_status0_reg = static_loader->cpu_boot_dev_status0_reg;
	cpu_boot_dev_status1_reg = static_loader->cpu_boot_dev_status1_reg;
	cpu_boot_status_reg = static_loader->cpu_boot_status_reg;

	dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n",
		cpu_timeout / USEC_PER_SEC);

	/* Wait for boot FIT request */
	rc = hl_poll_timeout(
		hdev,
		cpu_boot_status_reg,
		status,
		status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT,
		hdev->fw_poll_interval_usec,
		fw_loader->boot_fit_timeout);

	if (rc) {
		dev_dbg(hdev->dev,
			"No boot fit request received, resuming boot\n");
	} else {
		rc = hdev->asic_funcs->load_boot_fit_to_device(hdev);
		if (rc)
			goto out;

		/* Clear device CPU message status */
		WREG32(cpu_msg_status_reg, CPU_MSG_CLR);

		/* Signal device CPU that boot loader is ready */
		WREG32(msg_to_cpu_reg, KMD_MSG_FIT_RDY);

		/* Poll for CPU device ack */
		rc = hl_poll_timeout(
			hdev,
			cpu_msg_status_reg,
			status,
			status == CPU_MSG_OK,
			hdev->fw_poll_interval_usec,
			fw_loader->boot_fit_timeout);

		if (rc) {
			dev_err(hdev->dev,
				"Timeout waiting for boot fit load ack\n");
			goto out;
		}

		/* Clear message */
		WREG32(msg_to_cpu_reg, KMD_MSG_NA);
	}

	/*
	 * Make sure CPU boot-loader is running
	 * Note that the CPU_BOOT_STATUS_SRAM_AVAIL is generally set by Linux
	 * yet there is a debug scenario in which we loading uboot (without Linux)
	 * which at later stage is relocated to DRAM. In this case we expect
	 * uboot to set the CPU_BOOT_STATUS_SRAM_AVAIL and so we add it to the
	 * poll flags
	 */
	rc = hl_poll_timeout(
		hdev,
		cpu_boot_status_reg,
		status,
		(status == CPU_BOOT_STATUS_DRAM_RDY) ||
		(status == CPU_BOOT_STATUS_NIC_FW_RDY) ||
		(status == CPU_BOOT_STATUS_READY_TO_BOOT) ||
		(status == CPU_BOOT_STATUS_SRAM_AVAIL),
		hdev->fw_poll_interval_usec,
		cpu_timeout);

	dev_dbg(hdev->dev, "uboot status = %d\n", status);

	/* Read U-Boot version now in case we will later fail */
	hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT);

	/* update state according to boot stage */
	hl_fw_boot_fit_update_state(hdev, cpu_boot_dev_status0_reg,
						cpu_boot_dev_status1_reg);

	if (rc) {
		detect_cpu_boot_status(hdev, status);
		rc = -EIO;
		goto out;
	}

	/* Enable DRAM scrambling before Linux boot and after successful
	 *  UBoot
	 */
	hdev->asic_funcs->init_cpu_scrambler_dram(hdev);

	if (!(hdev->fw_components & FW_TYPE_LINUX)) {
		dev_info(hdev->dev, "Skip loading Linux F/W\n");
		rc = 0;
		goto out;
	}

	if (status == CPU_BOOT_STATUS_SRAM_AVAIL) {
		rc = 0;
		goto out;
	}

	dev_info(hdev->dev,
		"Loading firmware to device, may take some time...\n");

	rc = hdev->asic_funcs->load_firmware_to_device(hdev);
	if (rc)
		goto out;

	if (fw_loader->skip_bmc) {
		WREG32(msg_to_cpu_reg, KMD_MSG_SKIP_BMC);

		rc = hl_poll_timeout(
			hdev,
			cpu_boot_status_reg,
			status,
			(status == CPU_BOOT_STATUS_BMC_WAITING_SKIPPED),
			hdev->fw_poll_interval_usec,
			cpu_timeout);

		if (rc) {
			dev_err(hdev->dev,
				"Failed to get ACK on skipping BMC, %d\n",
				status);
			WREG32(msg_to_cpu_reg, KMD_MSG_NA);
			rc = -EIO;
			goto out;
		}
	}

	WREG32(msg_to_cpu_reg, KMD_MSG_FIT_RDY);

	rc = hl_poll_timeout(
		hdev,
		cpu_boot_status_reg,
		status,
		(status == CPU_BOOT_STATUS_SRAM_AVAIL),
		hdev->fw_poll_interval_usec,
		cpu_timeout);

	/* Clear message */
	WREG32(msg_to_cpu_reg, KMD_MSG_NA);

	if (rc) {
		if (status == CPU_BOOT_STATUS_FIT_CORRUPTED)
			dev_err(hdev->dev,
				"Device reports FIT image is corrupted\n");
		else
			dev_err(hdev->dev,
				"Failed to load firmware to device, %d\n",
				status);

		rc = -EIO;
		goto out;
	}

	rc = fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,
					fw_loader->static_loader.boot_err1_reg,
					cpu_boot_dev_status0_reg,
					cpu_boot_dev_status1_reg);
	if (rc)
		return rc;

	hl_fw_linux_update_state(hdev, cpu_boot_dev_status0_reg,
						cpu_boot_dev_status1_reg);

	return 0;

out:
	fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,
					fw_loader->static_loader.boot_err1_reg,
					cpu_boot_dev_status0_reg,
					cpu_boot_dev_status1_reg);

	return rc;
}