Path: blob/master/drivers/accel/habanalabs/common/firmware_if.c
26436 views
// SPDX-License-Identifier: GPL-2.012/*3* Copyright 2016-2022 HabanaLabs, Ltd.4* All Rights Reserved.5*/67#include "habanalabs.h"8#include <linux/habanalabs/hl_boot_if.h>910#include <linux/pci.h>11#include <linux/firmware.h>12#include <linux/crc32.h>13#include <linux/slab.h>14#include <linux/ctype.h>15#include <linux/vmalloc.h>1617#include <trace/events/habanalabs.h>1819#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */2021static char *comms_cmd_str_arr[COMMS_INVLD_LAST] = {22[COMMS_NOOP] = __stringify(COMMS_NOOP),23[COMMS_CLR_STS] = __stringify(COMMS_CLR_STS),24[COMMS_RST_STATE] = __stringify(COMMS_RST_STATE),25[COMMS_PREP_DESC] = __stringify(COMMS_PREP_DESC),26[COMMS_DATA_RDY] = __stringify(COMMS_DATA_RDY),27[COMMS_EXEC] = __stringify(COMMS_EXEC),28[COMMS_RST_DEV] = __stringify(COMMS_RST_DEV),29[COMMS_GOTO_WFE] = __stringify(COMMS_GOTO_WFE),30[COMMS_SKIP_BMC] = __stringify(COMMS_SKIP_BMC),31[COMMS_PREP_DESC_ELBI] = __stringify(COMMS_PREP_DESC_ELBI),32};3334static char *comms_sts_str_arr[COMMS_STS_INVLD_LAST] = {35[COMMS_STS_NOOP] = __stringify(COMMS_STS_NOOP),36[COMMS_STS_ACK] = __stringify(COMMS_STS_ACK),37[COMMS_STS_OK] = __stringify(COMMS_STS_OK),38[COMMS_STS_ERR] = __stringify(COMMS_STS_ERR),39[COMMS_STS_VALID_ERR] = __stringify(COMMS_STS_VALID_ERR),40[COMMS_STS_TIMEOUT_ERR] = __stringify(COMMS_STS_TIMEOUT_ERR),41};4243/**44* hl_fw_version_cmp() - compares the FW version to a specific version45*46* @hdev: pointer to hl_device structure47* @major: major number of a reference version48* @minor: minor number of a reference version49* @subminor: sub-minor number of a reference version50*51* Return 1 if FW version greater than the reference version, -1 if it's52* smaller and 0 if versions are identical.53*/54int hl_fw_version_cmp(struct hl_device *hdev, u32 major, u32 minor, u32 subminor)55{56if (hdev->fw_sw_major_ver != major)57return (hdev->fw_sw_major_ver > major) ? 1 : -1;5859if (hdev->fw_sw_minor_ver != minor)60return (hdev->fw_sw_minor_ver > minor) ? 1 : -1;6162if (hdev->fw_sw_sub_minor_ver != subminor)63return (hdev->fw_sw_sub_minor_ver > subminor) ? 1 : -1;6465return 0;66}6768static char *extract_fw_ver_from_str(const char *fw_str)69{70char *str, *fw_ver, *whitespace;71u32 ver_offset;7273fw_ver = kmalloc(VERSION_MAX_LEN, GFP_KERNEL);74if (!fw_ver)75return NULL;7677str = strnstr(fw_str, "fw-", VERSION_MAX_LEN);78if (!str)79goto free_fw_ver;8081/* Skip the fw- part */82str += 3;83ver_offset = str - fw_str;8485/* Copy until the next whitespace */86whitespace = strnstr(str, " ", VERSION_MAX_LEN - ver_offset);87if (!whitespace)88goto free_fw_ver;8990strscpy(fw_ver, str, whitespace - str + 1);9192return fw_ver;9394free_fw_ver:95kfree(fw_ver);96return NULL;97}9899/**100* extract_u32_until_given_char() - given a string of the format "<u32><char>*", extract the u32.101* @str: the given string102* @ver_num: the pointer to the extracted u32 to be returned to the caller.103* @given_char: the given char at the end of the u32 in the string104*105* Return: Upon success, return a pointer to the given_char in the string. Upon failure, return NULL106*/107static char *extract_u32_until_given_char(char *str, u32 *ver_num, char given_char)108{109char num_str[8] = {}, *ch;110111ch = strchrnul(str, given_char);112if (*ch == '\0' || ch == str || ch - str >= sizeof(num_str))113return NULL;114115memcpy(num_str, str, ch - str);116if (kstrtou32(num_str, 10, ver_num))117return NULL;118return ch;119}120121/**122* hl_get_sw_major_minor_subminor() - extract the FW's SW version major, minor, sub-minor123* from the version string124* @hdev: pointer to the hl_device125* @fw_str: the FW's version string126*127* The extracted version is set in the hdev fields: fw_sw_{major/minor/sub_minor}_ver.128*129* fw_str is expected to have one of two possible formats, examples:130* 1) 'Preboot version hl-gaudi2-1.9.0-fw-42.0.1-sec-3'131* 2) 'Preboot version hl-gaudi2-1.9.0-rc-fw-42.0.1-sec-3'132* In those examples, the SW major,minor,subminor are correspondingly: 1,9,0.133*134* Return: 0 for success or a negative error code for failure.135*/136static int hl_get_sw_major_minor_subminor(struct hl_device *hdev, const char *fw_str)137{138char *end, *start;139140end = strnstr(fw_str, "-rc-", VERSION_MAX_LEN);141if (end == fw_str)142return -EINVAL;143144if (!end)145end = strnstr(fw_str, "-fw-", VERSION_MAX_LEN);146147if (end == fw_str)148return -EINVAL;149150if (!end)151return -EINVAL;152153for (start = end - 1; start != fw_str; start--) {154if (*start == '-')155break;156}157158if (start == fw_str)159return -EINVAL;160161/* start/end point each to the starting and ending hyphen of the sw version e.g. -1.9.0- */162start++;163start = extract_u32_until_given_char(start, &hdev->fw_sw_major_ver, '.');164if (!start)165goto err_zero_ver;166167start++;168start = extract_u32_until_given_char(start, &hdev->fw_sw_minor_ver, '.');169if (!start)170goto err_zero_ver;171172start++;173start = extract_u32_until_given_char(start, &hdev->fw_sw_sub_minor_ver, '-');174if (!start)175goto err_zero_ver;176177return 0;178179err_zero_ver:180hdev->fw_sw_major_ver = 0;181hdev->fw_sw_minor_ver = 0;182hdev->fw_sw_sub_minor_ver = 0;183return -EINVAL;184}185186/**187* hl_get_preboot_major_minor() - extract the FW's version major, minor from the version string.188* @hdev: pointer to the hl_device189* @preboot_ver: the FW's version string190*191* preboot_ver is expected to be the format of <major>.<minor>.<sub minor>*, e.g: 42.0.1-sec-3192* The extracted version is set in the hdev fields: fw_inner_{major/minor}_ver.193*194* Return: 0 on success, negative error code for failure.195*/196static int hl_get_preboot_major_minor(struct hl_device *hdev, char *preboot_ver)197{198preboot_ver = extract_u32_until_given_char(preboot_ver, &hdev->fw_inner_major_ver, '.');199if (!preboot_ver) {200dev_err(hdev->dev, "Error parsing preboot major version\n");201goto err_zero_ver;202}203204preboot_ver++;205206preboot_ver = extract_u32_until_given_char(preboot_ver, &hdev->fw_inner_minor_ver, '.');207if (!preboot_ver) {208dev_err(hdev->dev, "Error parsing preboot minor version\n");209goto err_zero_ver;210}211return 0;212213err_zero_ver:214hdev->fw_inner_major_ver = 0;215hdev->fw_inner_minor_ver = 0;216return -EINVAL;217}218219static int hl_request_fw(struct hl_device *hdev,220const struct firmware **firmware_p,221const char *fw_name)222{223size_t fw_size;224int rc;225226rc = request_firmware(firmware_p, fw_name, hdev->dev);227if (rc) {228dev_err(hdev->dev, "Firmware file %s is not found! (error %d)\n",229fw_name, rc);230goto out;231}232233fw_size = (*firmware_p)->size;234if ((fw_size % 4) != 0) {235dev_err(hdev->dev, "Illegal %s firmware size %zu\n",236fw_name, fw_size);237rc = -EINVAL;238goto release_fw;239}240241dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);242243if (fw_size > FW_FILE_MAX_SIZE) {244dev_err(hdev->dev,245"FW file size %zu exceeds maximum of %u bytes\n",246fw_size, FW_FILE_MAX_SIZE);247rc = -EINVAL;248goto release_fw;249}250251return 0;252253release_fw:254release_firmware(*firmware_p);255out:256return rc;257}258259/**260* hl_release_firmware() - release FW261*262* @fw: fw descriptor263*264* note: this inline function added to serve as a comprehensive mirror for the265* hl_request_fw function.266*/267static inline void hl_release_firmware(const struct firmware *fw)268{269release_firmware(fw);270}271272/**273* hl_fw_copy_fw_to_device() - copy FW to device274*275* @hdev: pointer to hl_device structure.276* @fw: fw descriptor277* @dst: IO memory mapped address space to copy firmware to278* @src_offset: offset in src FW to copy from279* @size: amount of bytes to copy (0 to copy the whole binary)280*281* actual copy of FW binary data to device, shared by static and dynamic loaders282*/283static int hl_fw_copy_fw_to_device(struct hl_device *hdev,284const struct firmware *fw, void __iomem *dst,285u32 src_offset, u32 size)286{287const void *fw_data;288289/* size 0 indicates to copy the whole file */290if (!size)291size = fw->size;292293if (src_offset + size > fw->size) {294dev_err(hdev->dev,295"size to copy(%u) and offset(%u) are invalid\n",296size, src_offset);297return -EINVAL;298}299300fw_data = (const void *) fw->data;301302memcpy_toio(dst, fw_data + src_offset, size);303return 0;304}305306/**307* hl_fw_copy_msg_to_device() - copy message to device308*309* @hdev: pointer to hl_device structure.310* @msg: message311* @dst: IO memory mapped address space to copy firmware to312* @src_offset: offset in src message to copy from313* @size: amount of bytes to copy (0 to copy the whole binary)314*315* actual copy of message data to device.316*/317static int hl_fw_copy_msg_to_device(struct hl_device *hdev,318struct lkd_msg_comms *msg, void __iomem *dst,319u32 src_offset, u32 size)320{321void *msg_data;322323/* size 0 indicates to copy the whole file */324if (!size)325size = sizeof(struct lkd_msg_comms);326327if (src_offset + size > sizeof(struct lkd_msg_comms)) {328dev_err(hdev->dev,329"size to copy(%u) and offset(%u) are invalid\n",330size, src_offset);331return -EINVAL;332}333334msg_data = (void *) msg;335336memcpy_toio(dst, msg_data + src_offset, size);337338return 0;339}340341/**342* hl_fw_load_fw_to_device() - Load F/W code to device's memory.343*344* @hdev: pointer to hl_device structure.345* @fw_name: the firmware image name346* @dst: IO memory mapped address space to copy firmware to347* @src_offset: offset in src FW to copy from348* @size: amount of bytes to copy (0 to copy the whole binary)349*350* Copy fw code from firmware file to device memory.351*352* Return: 0 on success, non-zero for failure.353*/354int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,355void __iomem *dst, u32 src_offset, u32 size)356{357const struct firmware *fw;358int rc;359360rc = hl_request_fw(hdev, &fw, fw_name);361if (rc)362return rc;363364rc = hl_fw_copy_fw_to_device(hdev, fw, dst, src_offset, size);365366hl_release_firmware(fw);367return rc;368}369370int hl_fw_send_pci_access_msg(struct hl_device *hdev, u32 opcode, u64 value)371{372struct cpucp_packet pkt = {};373int rc;374375pkt.ctl = cpu_to_le32(opcode << CPUCP_PKT_CTL_OPCODE_SHIFT);376pkt.value = cpu_to_le64(value);377378rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);379if (rc)380dev_err(hdev->dev, "Failed to disable FW's PCI access\n");381382return rc;383}384385/**386* hl_fw_send_cpu_message() - send CPU message to the device.387*388* @hdev: pointer to hl_device structure.389* @hw_queue_id: HW queue ID390* @msg: raw data of the message/packet391* @size: size of @msg in bytes392* @timeout_us: timeout in usec to wait for CPU reply on the message393* @result: return code reported by FW394*395* send message to the device CPU.396*397* Return: 0 on success, non-zero for failure.398* -ENOMEM: memory allocation failure399* -EAGAIN: CPU is disabled (try again when enabled)400* -ETIMEDOUT: timeout waiting for FW response401* -EIO: protocol error402*/403int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,404u16 size, u32 timeout_us, u64 *result)405{406struct hl_hw_queue *queue = &hdev->kernel_queues[hw_queue_id];407struct asic_fixed_properties *prop = &hdev->asic_prop;408u32 tmp, expected_ack_val, pi, opcode;409struct cpucp_packet *pkt;410dma_addr_t pkt_dma_addr;411struct hl_bd *sent_bd;412int rc = 0, fw_rc;413414pkt = hl_cpu_accessible_dma_pool_alloc(hdev, size, &pkt_dma_addr);415if (!pkt) {416dev_err(hdev->dev, "Failed to allocate DMA memory for packet to CPU\n");417return -ENOMEM;418}419420memcpy(pkt, msg, size);421422mutex_lock(&hdev->send_cpu_message_lock);423424/* CPU-CP messages can be sent during soft-reset */425if (hdev->disabled && !hdev->reset_info.in_compute_reset)426goto out;427428if (hdev->device_cpu_disabled) {429rc = -EAGAIN;430goto out;431}432433/* set fence to a non valid value */434pkt->fence = cpu_to_le32(UINT_MAX);435pi = queue->pi;436437/*438* The CPU queue is a synchronous queue with an effective depth of439* a single entry (although it is allocated with room for multiple440* entries). We lock on it using 'send_cpu_message_lock' which441* serializes accesses to the CPU queue.442* Which means that we don't need to lock the access to the entire H/W443* queues module when submitting a JOB to the CPU queue.444*/445hl_hw_queue_submit_bd(hdev, queue, hl_queue_inc_ptr(queue->pi), size, pkt_dma_addr);446447if (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN)448expected_ack_val = queue->pi;449else450expected_ack_val = CPUCP_PACKET_FENCE_VAL;451452rc = hl_poll_timeout_memory(hdev, &pkt->fence, tmp,453(tmp == expected_ack_val), 1000,454timeout_us, true);455456hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);457458if (rc == -ETIMEDOUT) {459/* If FW performed reset just before sending it a packet, we will get a timeout.460* This is expected behavior, hence no need for error message.461*/462if (!hl_device_operational(hdev, NULL) && !hdev->reset_info.in_compute_reset) {463dev_dbg(hdev->dev, "Device CPU packet timeout (0x%x) due to FW reset\n",464tmp);465} else {466struct hl_bd *bd = queue->kernel_address;467468bd += hl_pi_2_offset(pi);469470dev_err(hdev->dev, "Device CPU packet timeout (status = 0x%x)\n"471"Pkt info[%u]: dma_addr: 0x%llx, kernel_addr: %p, len:0x%x, ctl: 0x%x, ptr:0x%llx, dram_bd:%u\n",472tmp, pi, pkt_dma_addr, (void *)pkt, bd->len, bd->ctl, bd->ptr,473queue->dram_bd);474}475hdev->device_cpu_disabled = true;476goto out;477}478479tmp = le32_to_cpu(pkt->ctl);480481fw_rc = (tmp & CPUCP_PKT_CTL_RC_MASK) >> CPUCP_PKT_CTL_RC_SHIFT;482if (fw_rc) {483opcode = (tmp & CPUCP_PKT_CTL_OPCODE_MASK) >> CPUCP_PKT_CTL_OPCODE_SHIFT;484485if (!prop->supports_advanced_cpucp_rc) {486dev_dbg(hdev->dev, "F/W ERROR %d for CPU packet %d\n", rc, opcode);487rc = -EIO;488goto scrub_descriptor;489}490491switch (fw_rc) {492case cpucp_packet_invalid:493dev_err(hdev->dev,494"CPU packet %d is not supported by F/W\n", opcode);495break;496case cpucp_packet_fault:497dev_err(hdev->dev,498"F/W failed processing CPU packet %d\n", opcode);499break;500case cpucp_packet_invalid_pkt:501dev_dbg(hdev->dev,502"CPU packet %d is not supported by F/W\n", opcode);503break;504case cpucp_packet_invalid_params:505dev_err(hdev->dev,506"F/W reports invalid parameters for CPU packet %d\n", opcode);507break;508509default:510dev_err(hdev->dev,511"Unknown F/W ERROR %d for CPU packet %d\n", rc, opcode);512}513514/* propagate the return code from the f/w to the callers who want to check it */515if (result)516*result = fw_rc;517518rc = -EIO;519520} else if (result) {521*result = le64_to_cpu(pkt->result);522}523524scrub_descriptor:525/* Scrub previous buffer descriptor 'ctl' field which contains the526* previous PI value written during packet submission.527* We must do this or else F/W can read an old value upon queue wraparound.528*/529sent_bd = queue->kernel_address;530sent_bd += hl_pi_2_offset(pi);531sent_bd->ctl = cpu_to_le32(UINT_MAX);532533out:534mutex_unlock(&hdev->send_cpu_message_lock);535536hl_cpu_accessible_dma_pool_free(hdev, size, pkt);537538return rc;539}540541int hl_fw_unmask_irq(struct hl_device *hdev, u16 event_type)542{543struct cpucp_packet pkt;544u64 result;545int rc;546547memset(&pkt, 0, sizeof(pkt));548549pkt.ctl = cpu_to_le32(CPUCP_PACKET_UNMASK_RAZWI_IRQ <<550CPUCP_PKT_CTL_OPCODE_SHIFT);551pkt.value = cpu_to_le64(event_type);552553rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),5540, &result);555556if (rc)557dev_err(hdev->dev, "failed to unmask event %d", event_type);558559return rc;560}561562int hl_fw_unmask_irq_arr(struct hl_device *hdev, const u32 *irq_arr,563size_t irq_arr_size)564{565struct cpucp_unmask_irq_arr_packet *pkt;566size_t total_pkt_size;567u64 result;568int rc;569570total_pkt_size = sizeof(struct cpucp_unmask_irq_arr_packet) +571irq_arr_size;572573/* data should be aligned to 8 bytes in order to CPU-CP to copy it */574total_pkt_size = (total_pkt_size + 0x7) & ~0x7;575576/* total_pkt_size is casted to u16 later on */577if (total_pkt_size > USHRT_MAX) {578dev_err(hdev->dev, "too many elements in IRQ array\n");579return -EINVAL;580}581582pkt = kzalloc(total_pkt_size, GFP_KERNEL);583if (!pkt)584return -ENOMEM;585586pkt->length = cpu_to_le32(irq_arr_size / sizeof(irq_arr[0]));587memcpy(&pkt->irqs, irq_arr, irq_arr_size);588589pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_UNMASK_RAZWI_IRQ_ARRAY <<590CPUCP_PKT_CTL_OPCODE_SHIFT);591592rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) pkt,593total_pkt_size, 0, &result);594595if (rc)596dev_err(hdev->dev, "failed to unmask event array\n");597598kfree(pkt);599600return rc;601}602603int hl_fw_test_cpu_queue(struct hl_device *hdev)604{605struct cpucp_packet test_pkt = {};606u64 result = 0;607int rc;608609test_pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEST <<610CPUCP_PKT_CTL_OPCODE_SHIFT);611test_pkt.value = cpu_to_le64(CPUCP_PACKET_FENCE_VAL);612613rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &test_pkt,614sizeof(test_pkt), 0, &result);615616if (!rc) {617if (result != CPUCP_PACKET_FENCE_VAL)618dev_err(hdev->dev,619"CPU queue test failed (%#08llx)\n", result);620} else {621dev_err(hdev->dev, "CPU queue test failed, error %d\n", rc);622}623624return rc;625}626627void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,628dma_addr_t *dma_handle)629{630u64 kernel_addr;631632kernel_addr = gen_pool_alloc(hdev->cpu_accessible_dma_pool, size);633634*dma_handle = hdev->cpu_accessible_dma_address +635(kernel_addr - (u64) (uintptr_t) hdev->cpu_accessible_dma_mem);636637return (void *) (uintptr_t) kernel_addr;638}639640void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,641void *vaddr)642{643gen_pool_free(hdev->cpu_accessible_dma_pool, (u64) (uintptr_t) vaddr,644size);645}646647int hl_fw_send_soft_reset(struct hl_device *hdev)648{649struct cpucp_packet pkt;650int rc;651652memset(&pkt, 0, sizeof(pkt));653pkt.ctl = cpu_to_le32(CPUCP_PACKET_SOFT_RESET << CPUCP_PKT_CTL_OPCODE_SHIFT);654rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);655if (rc)656dev_err(hdev->dev, "failed to send soft-reset msg (err = %d)\n", rc);657658return rc;659}660661int hl_fw_send_device_activity(struct hl_device *hdev, bool open)662{663struct cpucp_packet pkt;664int rc;665666memset(&pkt, 0, sizeof(pkt));667pkt.ctl = cpu_to_le32(CPUCP_PACKET_ACTIVE_STATUS_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);668pkt.value = cpu_to_le64(open);669rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);670if (rc)671dev_err(hdev->dev, "failed to send device activity msg(%u)\n", open);672673return rc;674}675676int hl_fw_send_heartbeat(struct hl_device *hdev)677{678struct cpucp_packet hb_pkt;679u64 result = 0;680int rc;681682memset(&hb_pkt, 0, sizeof(hb_pkt));683hb_pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEST << CPUCP_PKT_CTL_OPCODE_SHIFT);684hb_pkt.value = cpu_to_le64(CPUCP_PACKET_FENCE_VAL);685686rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &hb_pkt, sizeof(hb_pkt), 0, &result);687688if ((rc) || (result != CPUCP_PACKET_FENCE_VAL))689return -EIO;690691if (le32_to_cpu(hb_pkt.status_mask) &692CPUCP_PKT_HB_STATUS_EQ_FAULT_MASK) {693dev_warn(hdev->dev, "FW reported EQ fault during heartbeat\n");694rc = -EIO;695}696697hdev->heartbeat_debug_info.last_pq_heartbeat_ts = ktime_get_real_seconds();698699return rc;700}701702static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, u32 sts_val)703{704bool err_exists = false;705706if (!(err_val & CPU_BOOT_ERR0_ENABLED))707return false;708709if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL)710dev_err(hdev->dev, "Device boot error - DRAM initialization failed\n");711712if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED)713dev_err(hdev->dev, "Device boot error - FIT image corrupted\n");714715if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL)716dev_err(hdev->dev, "Device boot error - Thermal Sensor initialization failed\n");717718if (err_val & CPU_BOOT_ERR0_BMC_WAIT_SKIPPED) {719if (hdev->bmc_enable) {720dev_err(hdev->dev, "Device boot error - Skipped waiting for BMC\n");721} else {722dev_info(hdev->dev, "Device boot message - Skipped waiting for BMC\n");723/* This is an info so we don't want it to disable the724* device725*/726err_val &= ~CPU_BOOT_ERR0_BMC_WAIT_SKIPPED;727}728}729730if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY)731dev_err(hdev->dev, "Device boot error - Serdes data from BMC not available\n");732733if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL)734dev_err(hdev->dev, "Device boot error - NIC F/W initialization failed\n");735736if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY)737dev_err(hdev->dev, "Device boot warning - security not ready\n");738739if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL)740dev_err(hdev->dev, "Device boot error - security failure\n");741742if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL)743dev_err(hdev->dev, "Device boot error - eFuse failure\n");744745if (err_val & CPU_BOOT_ERR0_SEC_IMG_VER_FAIL)746dev_err(hdev->dev, "Device boot error - Failed to load preboot secondary image\n");747748if (err_val & CPU_BOOT_ERR0_PLL_FAIL)749dev_err(hdev->dev, "Device boot error - PLL failure\n");750751if (err_val & CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL)752dev_err(hdev->dev, "Device boot error - Failed to set threshold for temperature sensor\n");753754if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) {755/* Ignore this bit, don't prevent driver loading */756dev_dbg(hdev->dev, "device unusable status is set\n");757err_val &= ~CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL;758}759760if (err_val & CPU_BOOT_ERR0_BINNING_FAIL)761dev_err(hdev->dev, "Device boot error - binning failure\n");762763if (sts_val & CPU_BOOT_DEV_STS0_ENABLED)764dev_dbg(hdev->dev, "Device status0 %#x\n", sts_val);765766if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED)767dev_err(hdev->dev, "Device boot warning - Skipped DRAM initialization\n");768769if (err_val & CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL)770dev_err(hdev->dev, "Device boot error - ARC memory scrub failed\n");771772/* All warnings should go here in order not to reach the unknown error validation */773if (err_val & CPU_BOOT_ERR0_EEPROM_FAIL) {774dev_err(hdev->dev, "Device boot error - EEPROM failure detected\n");775err_exists = true;776}777778if (err_val & CPU_BOOT_ERR0_PRI_IMG_VER_FAIL)779dev_warn(hdev->dev, "Device boot warning - Failed to load preboot primary image\n");780781if (err_val & CPU_BOOT_ERR0_TPM_FAIL)782dev_warn(hdev->dev, "Device boot warning - TPM failure\n");783784if (err_val & CPU_BOOT_ERR_FATAL_MASK)785err_exists = true;786787/* return error only if it's in the predefined mask */788if (err_exists && ((err_val & ~CPU_BOOT_ERR0_ENABLED) &789lower_32_bits(hdev->boot_error_status_mask)))790return true;791792return false;793}794795/* placeholder for ERR1 as no errors defined there yet */796static bool fw_report_boot_dev1(struct hl_device *hdev, u32 err_val,797u32 sts_val)798{799/*800* keep this variable to preserve the logic of the function.801* this way it would require less modifications when error will be802* added to DEV_ERR1803*/804bool err_exists = false;805806if (!(err_val & CPU_BOOT_ERR1_ENABLED))807return false;808809if (sts_val & CPU_BOOT_DEV_STS1_ENABLED)810dev_dbg(hdev->dev, "Device status1 %#x\n", sts_val);811812if (!err_exists && (err_val & ~CPU_BOOT_ERR1_ENABLED)) {813dev_err(hdev->dev,814"Device boot error - unknown ERR1 error 0x%08x\n",815err_val);816err_exists = true;817}818819/* return error only if it's in the predefined mask */820if (err_exists && ((err_val & ~CPU_BOOT_ERR1_ENABLED) &821upper_32_bits(hdev->boot_error_status_mask)))822return true;823824return false;825}826827static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg,828u32 boot_err1_reg, u32 cpu_boot_dev_status0_reg,829u32 cpu_boot_dev_status1_reg)830{831u32 err_val, status_val;832bool err_exists = false;833834/* Some of the firmware status codes are deprecated in newer f/w835* versions. In those versions, the errors are reported836* in different registers. Therefore, we need to check those837* registers and print the exact errors. Moreover, there838* may be multiple errors, so we need to report on each error839* separately. Some of the error codes might indicate a state840* that is not an error per-se, but it is an error in production841* environment842*/843err_val = RREG32(boot_err0_reg);844status_val = RREG32(cpu_boot_dev_status0_reg);845err_exists = fw_report_boot_dev0(hdev, err_val, status_val);846847err_val = RREG32(boot_err1_reg);848status_val = RREG32(cpu_boot_dev_status1_reg);849err_exists |= fw_report_boot_dev1(hdev, err_val, status_val);850851if (err_exists)852return -EIO;853854return 0;855}856857int hl_fw_cpucp_info_get(struct hl_device *hdev,858u32 sts_boot_dev_sts0_reg,859u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,860u32 boot_err1_reg)861{862struct asic_fixed_properties *prop = &hdev->asic_prop;863struct cpucp_packet pkt = {};864dma_addr_t cpucp_info_dma_addr;865void *cpucp_info_cpu_addr;866char *kernel_ver;867u64 result;868int rc;869870cpucp_info_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, sizeof(struct cpucp_info),871&cpucp_info_dma_addr);872if (!cpucp_info_cpu_addr) {873dev_err(hdev->dev,874"Failed to allocate DMA memory for CPU-CP info packet\n");875return -ENOMEM;876}877878memset(cpucp_info_cpu_addr, 0, sizeof(struct cpucp_info));879880pkt.ctl = cpu_to_le32(CPUCP_PACKET_INFO_GET <<881CPUCP_PKT_CTL_OPCODE_SHIFT);882pkt.addr = cpu_to_le64(cpucp_info_dma_addr);883pkt.data_max_size = cpu_to_le32(sizeof(struct cpucp_info));884885rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),886HL_CPUCP_INFO_TIMEOUT_USEC, &result);887if (rc) {888dev_err(hdev->dev,889"Failed to handle CPU-CP info pkt, error %d\n", rc);890goto out;891}892893rc = fw_read_errors(hdev, boot_err0_reg, boot_err1_reg,894sts_boot_dev_sts0_reg, sts_boot_dev_sts1_reg);895if (rc) {896dev_err(hdev->dev, "Errors in device boot\n");897goto out;898}899900memcpy(&prop->cpucp_info, cpucp_info_cpu_addr,901sizeof(prop->cpucp_info));902903rc = hl_build_hwmon_channel_info(hdev, prop->cpucp_info.sensors);904if (rc) {905dev_err(hdev->dev,906"Failed to build hwmon channel info, error %d\n", rc);907rc = -EFAULT;908goto out;909}910911kernel_ver = extract_fw_ver_from_str(prop->cpucp_info.kernel_version);912if (kernel_ver) {913dev_info(hdev->dev, "Linux version %s", kernel_ver);914kfree(kernel_ver);915}916917/* assume EQ code doesn't need to check eqe index */918hdev->event_queue.check_eqe_index = false;919920/* Read FW application security bits again */921if (prop->fw_cpu_boot_dev_sts0_valid) {922prop->fw_app_cpu_boot_dev_sts0 = RREG32(sts_boot_dev_sts0_reg);923if (prop->fw_app_cpu_boot_dev_sts0 &924CPU_BOOT_DEV_STS0_EQ_INDEX_EN)925hdev->event_queue.check_eqe_index = true;926}927928if (prop->fw_cpu_boot_dev_sts1_valid)929prop->fw_app_cpu_boot_dev_sts1 = RREG32(sts_boot_dev_sts1_reg);930931out:932hl_cpu_accessible_dma_pool_free(hdev, sizeof(struct cpucp_info), cpucp_info_cpu_addr);933934return rc;935}936937static int hl_fw_send_msi_info_msg(struct hl_device *hdev)938{939struct cpucp_array_data_packet *pkt;940size_t total_pkt_size, data_size;941u64 result = 0;942int rc;943944/* skip sending this info for unsupported ASICs */945if (!hdev->asic_funcs->get_msi_info)946return 0;947948data_size = CPUCP_NUM_OF_MSI_TYPES * sizeof(u32);949total_pkt_size = sizeof(struct cpucp_array_data_packet) + data_size;950951/* data should be aligned to 8 bytes in order to CPU-CP to copy it */952total_pkt_size = (total_pkt_size + 0x7) & ~0x7;953954/* total_pkt_size is casted to u16 later on */955if (total_pkt_size > USHRT_MAX) {956dev_err(hdev->dev, "CPUCP array data is too big\n");957return -EINVAL;958}959960pkt = kzalloc(total_pkt_size, GFP_KERNEL);961if (!pkt)962return -ENOMEM;963964pkt->length = cpu_to_le32(CPUCP_NUM_OF_MSI_TYPES);965966memset((void *) &pkt->data, 0xFF, data_size);967hdev->asic_funcs->get_msi_info(pkt->data);968969pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_MSI_INFO_SET <<970CPUCP_PKT_CTL_OPCODE_SHIFT);971972rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)pkt,973total_pkt_size, 0, &result);974975/*976* in case packet result is invalid it means that FW does not support977* this feature and will use default/hard coded MSI values. no reason978* to stop the boot979*/980if (rc && result == cpucp_packet_invalid)981rc = 0;982983if (rc)984dev_err(hdev->dev, "failed to send CPUCP array data\n");985986kfree(pkt);987988return rc;989}990991int hl_fw_cpucp_handshake(struct hl_device *hdev,992u32 sts_boot_dev_sts0_reg,993u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,994u32 boot_err1_reg)995{996int rc;997998rc = hl_fw_cpucp_info_get(hdev, sts_boot_dev_sts0_reg,999sts_boot_dev_sts1_reg, boot_err0_reg,1000boot_err1_reg);1001if (rc)1002return rc;10031004return hl_fw_send_msi_info_msg(hdev);1005}10061007int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)1008{1009struct cpucp_packet pkt = {};1010void *eeprom_info_cpu_addr;1011dma_addr_t eeprom_info_dma_addr;1012u64 result;1013int rc;10141015eeprom_info_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, max_size,1016&eeprom_info_dma_addr);1017if (!eeprom_info_cpu_addr) {1018dev_err(hdev->dev,1019"Failed to allocate DMA memory for CPU-CP EEPROM packet\n");1020return -ENOMEM;1021}10221023memset(eeprom_info_cpu_addr, 0, max_size);10241025pkt.ctl = cpu_to_le32(CPUCP_PACKET_EEPROM_DATA_GET <<1026CPUCP_PKT_CTL_OPCODE_SHIFT);1027pkt.addr = cpu_to_le64(eeprom_info_dma_addr);1028pkt.data_max_size = cpu_to_le32(max_size);10291030rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1031HL_CPUCP_EEPROM_TIMEOUT_USEC, &result);1032if (rc) {1033if (rc != -EAGAIN)1034dev_err(hdev->dev,1035"Failed to handle CPU-CP EEPROM packet, error %d\n", rc);1036goto out;1037}10381039/* result contains the actual size */1040memcpy(data, eeprom_info_cpu_addr, min((size_t)result, max_size));10411042out:1043hl_cpu_accessible_dma_pool_free(hdev, max_size, eeprom_info_cpu_addr);10441045return rc;1046}10471048int hl_fw_get_monitor_dump(struct hl_device *hdev, void *data)1049{1050struct cpucp_monitor_dump *mon_dump_cpu_addr;1051dma_addr_t mon_dump_dma_addr;1052struct cpucp_packet pkt = {};1053size_t data_size;1054__le32 *src_ptr;1055u32 *dst_ptr;1056u64 result;1057int i, rc;10581059data_size = sizeof(struct cpucp_monitor_dump);1060mon_dump_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, data_size, &mon_dump_dma_addr);1061if (!mon_dump_cpu_addr) {1062dev_err(hdev->dev,1063"Failed to allocate DMA memory for CPU-CP monitor-dump packet\n");1064return -ENOMEM;1065}10661067memset(mon_dump_cpu_addr, 0, data_size);10681069pkt.ctl = cpu_to_le32(CPUCP_PACKET_MONITOR_DUMP_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);1070pkt.addr = cpu_to_le64(mon_dump_dma_addr);1071pkt.data_max_size = cpu_to_le32(data_size);10721073rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1074HL_CPUCP_MON_DUMP_TIMEOUT_USEC, &result);1075if (rc) {1076if (rc != -EAGAIN)1077dev_err(hdev->dev,1078"Failed to handle CPU-CP monitor-dump packet, error %d\n", rc);1079goto out;1080}10811082/* result contains the actual size */1083src_ptr = (__le32 *) mon_dump_cpu_addr;1084dst_ptr = data;1085for (i = 0; i < (data_size / sizeof(u32)); i++) {1086*dst_ptr = le32_to_cpu(*src_ptr);1087src_ptr++;1088dst_ptr++;1089}10901091out:1092hl_cpu_accessible_dma_pool_free(hdev, data_size, mon_dump_cpu_addr);10931094return rc;1095}10961097int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev,1098struct hl_info_pci_counters *counters)1099{1100struct cpucp_packet pkt = {};1101u64 result;1102int rc;11031104pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_THROUGHPUT_GET <<1105CPUCP_PKT_CTL_OPCODE_SHIFT);11061107/* Fetch PCI rx counter */1108pkt.index = cpu_to_le32(cpucp_pcie_throughput_rx);1109rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1110HL_CPUCP_INFO_TIMEOUT_USEC, &result);1111if (rc) {1112if (rc != -EAGAIN)1113dev_err(hdev->dev,1114"Failed to handle CPU-CP PCI info pkt, error %d\n", rc);1115return rc;1116}1117counters->rx_throughput = result;11181119memset(&pkt, 0, sizeof(pkt));1120pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_THROUGHPUT_GET <<1121CPUCP_PKT_CTL_OPCODE_SHIFT);11221123/* Fetch PCI tx counter */1124pkt.index = cpu_to_le32(cpucp_pcie_throughput_tx);1125rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1126HL_CPUCP_INFO_TIMEOUT_USEC, &result);1127if (rc) {1128if (rc != -EAGAIN)1129dev_err(hdev->dev,1130"Failed to handle CPU-CP PCI info pkt, error %d\n", rc);1131return rc;1132}1133counters->tx_throughput = result;11341135/* Fetch PCI replay counter */1136memset(&pkt, 0, sizeof(pkt));1137pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_REPLAY_CNT_GET <<1138CPUCP_PKT_CTL_OPCODE_SHIFT);11391140rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1141HL_CPUCP_INFO_TIMEOUT_USEC, &result);1142if (rc) {1143if (rc != -EAGAIN)1144dev_err(hdev->dev,1145"Failed to handle CPU-CP PCI info pkt, error %d\n", rc);1146return rc;1147}1148counters->replay_cnt = (u32) result;11491150return rc;1151}11521153int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy)1154{1155struct cpucp_packet pkt = {};1156u64 result;1157int rc;11581159pkt.ctl = cpu_to_le32(CPUCP_PACKET_TOTAL_ENERGY_GET <<1160CPUCP_PKT_CTL_OPCODE_SHIFT);11611162rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1163HL_CPUCP_INFO_TIMEOUT_USEC, &result);1164if (rc) {1165if (rc != -EAGAIN)1166dev_err(hdev->dev,1167"Failed to handle CpuCP total energy pkt, error %d\n", rc);1168return rc;1169}11701171*total_energy = result;11721173return rc;1174}11751176int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index,1177enum pll_index *pll_index)1178{1179struct asic_fixed_properties *prop = &hdev->asic_prop;1180u8 pll_byte, pll_bit_off;1181bool dynamic_pll;1182int fw_pll_idx;11831184dynamic_pll = !!(prop->fw_app_cpu_boot_dev_sts0 &1185CPU_BOOT_DEV_STS0_DYN_PLL_EN);11861187if (!dynamic_pll) {1188/*1189* in case we are working with legacy FW (each asic has unique1190* PLL numbering) use the driver based index as they are1191* aligned with fw legacy numbering1192*/1193*pll_index = input_pll_index;1194return 0;1195}11961197/* retrieve a FW compatible PLL index based on1198* ASIC specific user request1199*/1200fw_pll_idx = hdev->asic_funcs->map_pll_idx_to_fw_idx(input_pll_index);1201if (fw_pll_idx < 0) {1202dev_err(hdev->dev, "Invalid PLL index (%u) error %d\n",1203input_pll_index, fw_pll_idx);1204return -EINVAL;1205}12061207/* PLL map is a u8 array */1208pll_byte = prop->cpucp_info.pll_map[fw_pll_idx >> 3];1209pll_bit_off = fw_pll_idx & 0x7;12101211if (!(pll_byte & BIT(pll_bit_off))) {1212dev_err(hdev->dev, "PLL index %d is not supported\n",1213fw_pll_idx);1214return -EINVAL;1215}12161217*pll_index = fw_pll_idx;12181219return 0;1220}12211222int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index,1223u16 *pll_freq_arr)1224{1225struct cpucp_packet pkt;1226enum pll_index used_pll_idx;1227u64 result;1228int rc;12291230rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);1231if (rc)1232return rc;12331234memset(&pkt, 0, sizeof(pkt));12351236pkt.ctl = cpu_to_le32(CPUCP_PACKET_PLL_INFO_GET <<1237CPUCP_PKT_CTL_OPCODE_SHIFT);1238pkt.pll_type = __cpu_to_le16((u16)used_pll_idx);12391240rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1241HL_CPUCP_INFO_TIMEOUT_USEC, &result);1242if (rc) {1243if (rc != -EAGAIN)1244dev_err(hdev->dev, "Failed to read PLL info, error %d\n", rc);1245return rc;1246}12471248pll_freq_arr[0] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT0_MASK, result);1249pll_freq_arr[1] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT1_MASK, result);1250pll_freq_arr[2] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT2_MASK, result);1251pll_freq_arr[3] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT3_MASK, result);12521253return 0;1254}12551256int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power)1257{1258struct cpucp_packet pkt;1259u64 result;1260int rc;12611262memset(&pkt, 0, sizeof(pkt));12631264pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET <<1265CPUCP_PKT_CTL_OPCODE_SHIFT);1266pkt.type = cpu_to_le16(CPUCP_POWER_INPUT);12671268rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1269HL_CPUCP_INFO_TIMEOUT_USEC, &result);1270if (rc) {1271if (rc != -EAGAIN)1272dev_err(hdev->dev, "Failed to read power, error %d\n", rc);1273return rc;1274}12751276*power = result;12771278return rc;1279}12801281int hl_fw_dram_replaced_row_get(struct hl_device *hdev,1282struct cpucp_hbm_row_info *info)1283{1284struct cpucp_hbm_row_info *cpucp_repl_rows_info_cpu_addr;1285dma_addr_t cpucp_repl_rows_info_dma_addr;1286struct cpucp_packet pkt = {};1287u64 result;1288int rc;12891290cpucp_repl_rows_info_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev,1291sizeof(struct cpucp_hbm_row_info),1292&cpucp_repl_rows_info_dma_addr);1293if (!cpucp_repl_rows_info_cpu_addr) {1294dev_err(hdev->dev,1295"Failed to allocate DMA memory for CPU-CP replaced rows info packet\n");1296return -ENOMEM;1297}12981299memset(cpucp_repl_rows_info_cpu_addr, 0, sizeof(struct cpucp_hbm_row_info));13001301pkt.ctl = cpu_to_le32(CPUCP_PACKET_HBM_REPLACED_ROWS_INFO_GET <<1302CPUCP_PKT_CTL_OPCODE_SHIFT);1303pkt.addr = cpu_to_le64(cpucp_repl_rows_info_dma_addr);1304pkt.data_max_size = cpu_to_le32(sizeof(struct cpucp_hbm_row_info));13051306rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1307HL_CPUCP_INFO_TIMEOUT_USEC, &result);1308if (rc) {1309if (rc != -EAGAIN)1310dev_err(hdev->dev,1311"Failed to handle CPU-CP replaced rows info pkt, error %d\n", rc);1312goto out;1313}13141315memcpy(info, cpucp_repl_rows_info_cpu_addr, sizeof(*info));13161317out:1318hl_cpu_accessible_dma_pool_free(hdev, sizeof(struct cpucp_hbm_row_info),1319cpucp_repl_rows_info_cpu_addr);13201321return rc;1322}13231324int hl_fw_dram_pending_row_get(struct hl_device *hdev, u32 *pend_rows_num)1325{1326struct cpucp_packet pkt;1327u64 result;1328int rc;13291330memset(&pkt, 0, sizeof(pkt));13311332pkt.ctl = cpu_to_le32(CPUCP_PACKET_HBM_PENDING_ROWS_STATUS << CPUCP_PKT_CTL_OPCODE_SHIFT);13331334rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);1335if (rc) {1336if (rc != -EAGAIN)1337dev_err(hdev->dev,1338"Failed to handle CPU-CP pending rows info pkt, error %d\n", rc);1339goto out;1340}13411342*pend_rows_num = (u32) result;1343out:1344return rc;1345}13461347int hl_fw_cpucp_engine_core_asid_set(struct hl_device *hdev, u32 asid)1348{1349struct cpucp_packet pkt;1350int rc;13511352memset(&pkt, 0, sizeof(pkt));13531354pkt.ctl = cpu_to_le32(CPUCP_PACKET_ENGINE_CORE_ASID_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);1355pkt.value = cpu_to_le64(asid);13561357rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1358HL_CPUCP_INFO_TIMEOUT_USEC, NULL);1359if (rc)1360dev_err(hdev->dev,1361"Failed on ASID configuration request for engine core, error %d\n",1362rc);13631364return rc;1365}13661367void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev)1368{1369struct static_fw_load_mgr *static_loader =1370&hdev->fw_loader.static_loader;1371int rc;13721373if (hdev->asic_prop.dynamic_fw_load) {1374rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader,1375COMMS_RST_DEV, 0, false,1376hdev->fw_loader.cpu_timeout);1377if (rc)1378dev_err(hdev->dev, "Failed sending COMMS_RST_DEV\n");1379} else {1380WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_RST_DEV);1381}1382}13831384void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev)1385{1386struct fw_load_mgr *fw_loader = &hdev->fw_loader;1387u32 status, cpu_boot_status_reg, cpu_timeout;1388struct static_fw_load_mgr *static_loader;1389struct pre_fw_load_props *pre_fw_load;1390int rc;13911392if (hdev->device_cpu_is_halted)1393return;13941395/* Stop device CPU to make sure nothing bad happens */1396if (hdev->asic_prop.dynamic_fw_load) {1397pre_fw_load = &fw_loader->pre_fw_load;1398cpu_timeout = fw_loader->cpu_timeout;1399cpu_boot_status_reg = pre_fw_load->cpu_boot_status_reg;14001401rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader,1402COMMS_GOTO_WFE, 0, false, cpu_timeout);1403if (rc) {1404dev_err(hdev->dev, "Failed sending COMMS_GOTO_WFE\n");1405} else {1406rc = hl_poll_timeout(1407hdev,1408cpu_boot_status_reg,1409status,1410status == CPU_BOOT_STATUS_IN_WFE,1411hdev->fw_poll_interval_usec,1412cpu_timeout);1413if (rc)1414dev_err(hdev->dev, "Current status=%u. Timed-out updating to WFE\n",1415status);1416}1417} else {1418static_loader = &hdev->fw_loader.static_loader;1419WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_GOTO_WFE);1420msleep(static_loader->cpu_reset_wait_msec);14211422/* Must clear this register in order to prevent preboot1423* from reading WFE after reboot1424*/1425WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_NA);1426}14271428hdev->device_cpu_is_halted = true;1429}14301431static void detect_cpu_boot_status(struct hl_device *hdev, u32 status)1432{1433/* Some of the status codes below are deprecated in newer f/w1434* versions but we keep them here for backward compatibility1435*/1436switch (status) {1437case CPU_BOOT_STATUS_NA:1438dev_err(hdev->dev,1439"Device boot progress - BTL/ROM did NOT run\n");1440break;1441case CPU_BOOT_STATUS_IN_WFE:1442dev_err(hdev->dev,1443"Device boot progress - Stuck inside WFE loop\n");1444break;1445case CPU_BOOT_STATUS_IN_BTL:1446dev_err(hdev->dev,1447"Device boot progress - Stuck in BTL\n");1448break;1449case CPU_BOOT_STATUS_IN_PREBOOT:1450dev_err(hdev->dev,1451"Device boot progress - Stuck in Preboot\n");1452break;1453case CPU_BOOT_STATUS_IN_SPL:1454dev_err(hdev->dev,1455"Device boot progress - Stuck in SPL\n");1456break;1457case CPU_BOOT_STATUS_IN_UBOOT:1458dev_err(hdev->dev,1459"Device boot progress - Stuck in u-boot\n");1460break;1461case CPU_BOOT_STATUS_DRAM_INIT_FAIL:1462dev_err(hdev->dev,1463"Device boot progress - DRAM initialization failed\n");1464break;1465case CPU_BOOT_STATUS_UBOOT_NOT_READY:1466dev_err(hdev->dev,1467"Device boot progress - Cannot boot\n");1468break;1469case CPU_BOOT_STATUS_TS_INIT_FAIL:1470dev_err(hdev->dev,1471"Device boot progress - Thermal Sensor initialization failed\n");1472break;1473case CPU_BOOT_STATUS_SECURITY_READY:1474dev_err(hdev->dev,1475"Device boot progress - Stuck in preboot after security initialization\n");1476break;1477case CPU_BOOT_STATUS_FW_SHUTDOWN_PREP:1478dev_err(hdev->dev,1479"Device boot progress - Stuck in preparation for shutdown\n");1480break;1481default:1482dev_err(hdev->dev,1483"Device boot progress - Invalid or unexpected status code %d\n", status);1484break;1485}1486}14871488int hl_fw_wait_preboot_ready(struct hl_device *hdev)1489{1490struct pre_fw_load_props *pre_fw_load = &hdev->fw_loader.pre_fw_load;1491u32 status = 0, timeout;1492int rc, tries = 1, fw_err = 0;1493bool preboot_still_runs;14941495/* Need to check two possible scenarios:1496*1497* CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT - for newer firmwares where1498* the preboot is waiting for the boot fit1499*1500* All other status values - for older firmwares where the uboot was1501* loaded from the FLASH1502*/1503timeout = pre_fw_load->wait_for_preboot_timeout;1504retry:1505rc = hl_poll_timeout(1506hdev,1507pre_fw_load->cpu_boot_status_reg,1508status,1509(status == CPU_BOOT_STATUS_NIC_FW_RDY) ||1510(status == CPU_BOOT_STATUS_READY_TO_BOOT) ||1511(status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT),1512hdev->fw_poll_interval_usec,1513timeout);1514/*1515* if F/W reports "security-ready" it means preboot might take longer.1516* If the field 'wait_for_preboot_extended_timeout' is non 0 we wait again1517* with that timeout1518*/1519preboot_still_runs = (status == CPU_BOOT_STATUS_SECURITY_READY ||1520status == CPU_BOOT_STATUS_IN_PREBOOT ||1521status == CPU_BOOT_STATUS_FW_SHUTDOWN_PREP ||1522status == CPU_BOOT_STATUS_DRAM_RDY);15231524if (rc && tries && preboot_still_runs) {1525tries--;1526if (pre_fw_load->wait_for_preboot_extended_timeout) {1527timeout = pre_fw_load->wait_for_preboot_extended_timeout;1528goto retry;1529}1530}15311532/* If we read all FF, then something is totally wrong, no point1533* of reading specific errors1534*/1535if (status != -1)1536fw_err = fw_read_errors(hdev, pre_fw_load->boot_err0_reg,1537pre_fw_load->boot_err1_reg,1538pre_fw_load->sts_boot_dev_sts0_reg,1539pre_fw_load->sts_boot_dev_sts1_reg);1540if (rc || fw_err) {1541detect_cpu_boot_status(hdev, status);1542dev_err(hdev->dev, "CPU boot %s (status = %d)\n",1543fw_err ? "failed due to an error" : "ready timeout", status);1544return -EIO;1545}15461547hdev->fw_loader.fw_comp_loaded |= FW_TYPE_PREBOOT_CPU;15481549return 0;1550}15511552static int hl_fw_read_preboot_caps(struct hl_device *hdev)1553{1554struct pre_fw_load_props *pre_fw_load;1555struct asic_fixed_properties *prop;1556u32 reg_val;1557int rc;15581559prop = &hdev->asic_prop;1560pre_fw_load = &hdev->fw_loader.pre_fw_load;15611562rc = hl_fw_wait_preboot_ready(hdev);1563if (rc)1564return rc;15651566/*1567* the registers DEV_STS* contain FW capabilities/features.1568* We can rely on this registers only if bit CPU_BOOT_DEV_STS*_ENABLED1569* is set.1570* In the first read of this register we store the value of this1571* register ONLY if the register is enabled (which will be propagated1572* to next stages) and also mark the register as valid.1573* In case it is not enabled the stored value will be left 0- all1574* caps/features are off1575*/1576reg_val = RREG32(pre_fw_load->sts_boot_dev_sts0_reg);1577if (reg_val & CPU_BOOT_DEV_STS0_ENABLED) {1578prop->fw_cpu_boot_dev_sts0_valid = true;1579prop->fw_preboot_cpu_boot_dev_sts0 = reg_val;1580}15811582reg_val = RREG32(pre_fw_load->sts_boot_dev_sts1_reg);1583if (reg_val & CPU_BOOT_DEV_STS1_ENABLED) {1584prop->fw_cpu_boot_dev_sts1_valid = true;1585prop->fw_preboot_cpu_boot_dev_sts1 = reg_val;1586}15871588prop->dynamic_fw_load = !!(prop->fw_preboot_cpu_boot_dev_sts0 &1589CPU_BOOT_DEV_STS0_FW_LD_COM_EN);15901591/* initialize FW loader once we know what load protocol is used */1592hdev->asic_funcs->init_firmware_loader(hdev);15931594dev_dbg(hdev->dev, "Attempting %s FW load\n",1595prop->dynamic_fw_load ? "dynamic" : "legacy");1596return 0;1597}15981599static int hl_fw_static_read_device_fw_version(struct hl_device *hdev,1600enum hl_fw_component fwc)1601{1602struct asic_fixed_properties *prop = &hdev->asic_prop;1603struct fw_load_mgr *fw_loader = &hdev->fw_loader;1604struct static_fw_load_mgr *static_loader;1605char *dest, *boot_ver, *preboot_ver;1606u32 ver_off, limit;1607const char *name;1608char btl_ver[32];16091610static_loader = &hdev->fw_loader.static_loader;16111612switch (fwc) {1613case FW_COMP_BOOT_FIT:1614ver_off = RREG32(static_loader->boot_fit_version_offset_reg);1615dest = prop->uboot_ver;1616name = "Boot-fit";1617limit = static_loader->boot_fit_version_max_off;1618break;1619case FW_COMP_PREBOOT:1620ver_off = RREG32(static_loader->preboot_version_offset_reg);1621dest = prop->preboot_ver;1622name = "Preboot";1623limit = static_loader->preboot_version_max_off;1624break;1625default:1626dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);1627return -EIO;1628}16291630ver_off &= static_loader->sram_offset_mask;16311632if (ver_off < limit) {1633memcpy_fromio(dest,1634hdev->pcie_bar[fw_loader->sram_bar_id] + ver_off,1635VERSION_MAX_LEN);1636} else {1637dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n",1638name, ver_off);1639strscpy(dest, "unavailable", VERSION_MAX_LEN);1640return -EIO;1641}16421643if (fwc == FW_COMP_BOOT_FIT) {1644boot_ver = extract_fw_ver_from_str(prop->uboot_ver);1645if (boot_ver) {1646dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);1647kfree(boot_ver);1648}1649} else if (fwc == FW_COMP_PREBOOT) {1650preboot_ver = strnstr(prop->preboot_ver, "Preboot",1651VERSION_MAX_LEN);1652if (preboot_ver && preboot_ver != prop->preboot_ver) {1653strscpy(btl_ver, prop->preboot_ver,1654min((int) (preboot_ver - prop->preboot_ver),165531));1656dev_info(hdev->dev, "%s\n", btl_ver);1657}16581659preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);1660if (preboot_ver) {1661dev_info(hdev->dev, "preboot version %s\n",1662preboot_ver);1663kfree(preboot_ver);1664}1665}16661667return 0;1668}16691670/**1671* hl_fw_preboot_update_state - update internal data structures during1672* handshake with preboot1673*1674*1675* @hdev: pointer to the habanalabs device structure1676*1677* @return 0 on success, otherwise non-zero error code1678*/1679static void hl_fw_preboot_update_state(struct hl_device *hdev)1680{1681struct asic_fixed_properties *prop = &hdev->asic_prop;1682u32 cpu_boot_dev_sts0, cpu_boot_dev_sts1;16831684cpu_boot_dev_sts0 = prop->fw_preboot_cpu_boot_dev_sts0;1685cpu_boot_dev_sts1 = prop->fw_preboot_cpu_boot_dev_sts1;16861687/* We read boot_dev_sts registers multiple times during boot:1688* 1. preboot - a. Check whether the security status bits are valid1689* b. Check whether fw security is enabled1690* c. Check whether hard reset is done by preboot1691* 2. boot cpu - a. Fetch boot cpu security status1692* b. Check whether hard reset is done by boot cpu1693* 3. FW application - a. Fetch fw application security status1694* b. Check whether hard reset is done by fw app1695*/1696prop->hard_reset_done_by_fw = !!(cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);16971698prop->fw_security_enabled = !!(cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_SECURITY_EN);16991700dev_dbg(hdev->dev, "Firmware preboot boot device status0 %#x\n",1701cpu_boot_dev_sts0);17021703dev_dbg(hdev->dev, "Firmware preboot boot device status1 %#x\n",1704cpu_boot_dev_sts1);17051706dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n",1707prop->hard_reset_done_by_fw ? "enabled" : "disabled");17081709dev_dbg(hdev->dev, "firmware-level security is %s\n",1710prop->fw_security_enabled ? "enabled" : "disabled");17111712dev_dbg(hdev->dev, "GIC controller is %s\n",1713prop->gic_interrupts_enable ? "enabled" : "disabled");1714}17151716static int hl_fw_static_read_preboot_status(struct hl_device *hdev)1717{1718int rc;17191720rc = hl_fw_static_read_device_fw_version(hdev, FW_COMP_PREBOOT);1721if (rc)1722return rc;17231724return 0;1725}17261727int hl_fw_read_preboot_status(struct hl_device *hdev)1728{1729int rc;17301731if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU))1732return 0;17331734/* get FW pre-load parameters */1735hdev->asic_funcs->init_firmware_preload_params(hdev);17361737/*1738* In order to determine boot method (static VS dynamic) we need to1739* read the boot caps register1740*/1741rc = hl_fw_read_preboot_caps(hdev);1742if (rc)1743return rc;17441745hl_fw_preboot_update_state(hdev);17461747/* no need to read preboot status in dynamic load */1748if (hdev->asic_prop.dynamic_fw_load)1749return 0;17501751return hl_fw_static_read_preboot_status(hdev);1752}17531754/* associate string with COMM status */1755static char *hl_dynamic_fw_status_str[COMMS_STS_INVLD_LAST] = {1756[COMMS_STS_NOOP] = "NOOP",1757[COMMS_STS_ACK] = "ACK",1758[COMMS_STS_OK] = "OK",1759[COMMS_STS_ERR] = "ERR",1760[COMMS_STS_VALID_ERR] = "VALID_ERR",1761[COMMS_STS_TIMEOUT_ERR] = "TIMEOUT_ERR",1762};17631764/**1765* hl_fw_dynamic_report_error_status - report error status1766*1767* @hdev: pointer to the habanalabs device structure1768* @status: value of FW status register1769* @expected_status: the expected status1770*/1771static void hl_fw_dynamic_report_error_status(struct hl_device *hdev,1772u32 status,1773enum comms_sts expected_status)1774{1775enum comms_sts comm_status =1776FIELD_GET(COMMS_STATUS_STATUS_MASK, status);17771778if (comm_status < COMMS_STS_INVLD_LAST)1779dev_err(hdev->dev, "Device status %s, expected status: %s\n",1780hl_dynamic_fw_status_str[comm_status],1781hl_dynamic_fw_status_str[expected_status]);1782else1783dev_err(hdev->dev, "Device status unknown %d, expected status: %s\n",1784comm_status,1785hl_dynamic_fw_status_str[expected_status]);1786}17871788/**1789* hl_fw_dynamic_send_cmd - send LKD to FW cmd1790*1791* @hdev: pointer to the habanalabs device structure1792* @fw_loader: managing structure for loading device's FW1793* @cmd: LKD to FW cmd code1794* @size: size of next FW component to be loaded (0 if not necessary)1795*1796* LDK to FW exact command layout is defined at struct comms_command.1797* note: the size argument is used only when the next FW component should be1798* loaded, otherwise it shall be 0. the size is used by the FW in later1799* protocol stages and when sending only indicating the amount of memory1800* to be allocated by the FW to receive the next boot component.1801*/1802static void hl_fw_dynamic_send_cmd(struct hl_device *hdev,1803struct fw_load_mgr *fw_loader,1804enum comms_cmd cmd, unsigned int size)1805{1806struct cpu_dyn_regs *dyn_regs;1807u32 val;18081809dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;18101811val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd);1812val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size);18131814trace_habanalabs_comms_send_cmd(&hdev->pdev->dev, comms_cmd_str_arr[cmd]);1815WREG32(le32_to_cpu(dyn_regs->kmd_msg_to_cpu), val);1816}18171818/**1819* hl_fw_dynamic_extract_fw_response - update the FW response1820*1821* @hdev: pointer to the habanalabs device structure1822* @fw_loader: managing structure for loading device's FW1823* @response: FW response1824* @status: the status read from CPU status register1825*1826* @return 0 on success, otherwise non-zero error code1827*/1828static int hl_fw_dynamic_extract_fw_response(struct hl_device *hdev,1829struct fw_load_mgr *fw_loader,1830struct fw_response *response,1831u32 status)1832{1833response->status = FIELD_GET(COMMS_STATUS_STATUS_MASK, status);1834response->ram_offset = FIELD_GET(COMMS_STATUS_OFFSET_MASK, status) <<1835COMMS_STATUS_OFFSET_ALIGN_SHIFT;1836response->ram_type = FIELD_GET(COMMS_STATUS_RAM_TYPE_MASK, status);18371838if ((response->ram_type != COMMS_SRAM) &&1839(response->ram_type != COMMS_DRAM)) {1840dev_err(hdev->dev, "FW status: invalid RAM type %u\n",1841response->ram_type);1842return -EIO;1843}18441845return 0;1846}18471848/**1849* hl_fw_dynamic_wait_for_status - wait for status in dynamic FW load1850*1851* @hdev: pointer to the habanalabs device structure1852* @fw_loader: managing structure for loading device's FW1853* @expected_status: expected status to wait for1854* @timeout: timeout for status wait1855*1856* @return 0 on success, otherwise non-zero error code1857*1858* waiting for status from FW include polling the FW status register until1859* expected status is received or timeout occurs (whatever occurs first).1860*/1861static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev,1862struct fw_load_mgr *fw_loader,1863enum comms_sts expected_status,1864u32 timeout)1865{1866struct cpu_dyn_regs *dyn_regs;1867u32 status;1868int rc;18691870dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;18711872trace_habanalabs_comms_wait_status(&hdev->pdev->dev, comms_sts_str_arr[expected_status]);18731874/* Wait for expected status */1875rc = hl_poll_timeout(1876hdev,1877le32_to_cpu(dyn_regs->cpu_cmd_status_to_host),1878status,1879FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status,1880hdev->fw_comms_poll_interval_usec,1881timeout);18821883if (rc) {1884hl_fw_dynamic_report_error_status(hdev, status,1885expected_status);1886return -EIO;1887}18881889trace_habanalabs_comms_wait_status_done(&hdev->pdev->dev,1890comms_sts_str_arr[expected_status]);18911892/*1893* skip storing FW response for NOOP to preserve the actual desired1894* FW status1895*/1896if (expected_status == COMMS_STS_NOOP)1897return 0;18981899rc = hl_fw_dynamic_extract_fw_response(hdev, fw_loader,1900&fw_loader->dynamic_loader.response,1901status);1902return rc;1903}19041905/**1906* hl_fw_dynamic_send_clear_cmd - send clear command to FW1907*1908* @hdev: pointer to the habanalabs device structure1909* @fw_loader: managing structure for loading device's FW1910*1911* @return 0 on success, otherwise non-zero error code1912*1913* after command cycle between LKD to FW CPU (i.e. LKD got an expected status1914* from FW) we need to clear the CPU status register in order to avoid garbage1915* between command cycles.1916* This is done by sending clear command and polling the CPU to LKD status1917* register to hold the status NOOP1918*/1919static int hl_fw_dynamic_send_clear_cmd(struct hl_device *hdev,1920struct fw_load_mgr *fw_loader)1921{1922hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_CLR_STS, 0);19231924return hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_NOOP,1925fw_loader->cpu_timeout);1926}19271928/**1929* hl_fw_dynamic_send_protocol_cmd - send LKD to FW cmd and wait for ACK1930*1931* @hdev: pointer to the habanalabs device structure1932* @fw_loader: managing structure for loading device's FW1933* @cmd: LKD to FW cmd code1934* @size: size of next FW component to be loaded (0 if not necessary)1935* @wait_ok: if true also wait for OK response from FW1936* @timeout: timeout for status wait1937*1938* @return 0 on success, otherwise non-zero error code1939*1940* brief:1941* when sending protocol command we have the following steps:1942* - send clear (clear command and verify clear status register)1943* - send the actual protocol command1944* - wait for ACK on the protocol command1945* - send clear1946* - send NOOP1947* if, in addition, the specific protocol command should wait for OK then:1948* - wait for OK1949* - send clear1950* - send NOOP1951*1952* NOTES:1953* send clear: this is necessary in order to clear the status register to avoid1954* leftovers between command1955* NOOP command: necessary to avoid loop on the clear command by the FW1956*/1957int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,1958struct fw_load_mgr *fw_loader,1959enum comms_cmd cmd, unsigned int size,1960bool wait_ok, u32 timeout)1961{1962int rc;19631964trace_habanalabs_comms_protocol_cmd(&hdev->pdev->dev, comms_cmd_str_arr[cmd]);19651966/* first send clear command to clean former commands */1967rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);1968if (rc)1969return rc;19701971/* send the actual command */1972hl_fw_dynamic_send_cmd(hdev, fw_loader, cmd, size);19731974/* wait for ACK for the command */1975rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_ACK,1976timeout);1977if (rc)1978return rc;19791980/* clear command to prepare for NOOP command */1981rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);1982if (rc)1983return rc;19841985/* send the actual NOOP command */1986hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0);19871988if (!wait_ok)1989return 0;19901991rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_OK,1992timeout);1993if (rc)1994return rc;19951996/* clear command to prepare for NOOP command */1997rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);1998if (rc)1999return rc;20002001/* send the actual NOOP command */2002hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0);20032004return 0;2005}20062007/**2008* hl_fw_compat_crc32 - CRC compatible with FW2009*2010* @data: pointer to the data2011* @size: size of the data2012*2013* @return the CRC32 result2014*2015* NOTE: kernel's CRC32 differs from standard CRC32 calculation.2016* in order to be aligned we need to flip the bits of both the input2017* initial CRC and kernel's CRC32 result.2018* in addition both sides use initial CRC of 0,2019*/2020static u32 hl_fw_compat_crc32(u8 *data, size_t size)2021{2022return ~crc32_le(~((u32)0), data, size);2023}20242025/**2026* hl_fw_dynamic_validate_memory_bound - validate memory bounds for memory2027* transfer (image or descriptor) between2028* host and FW2029*2030* @hdev: pointer to the habanalabs device structure2031* @addr: device address of memory transfer2032* @size: memory transfer size2033* @region: PCI memory region2034*2035* @return 0 on success, otherwise non-zero error code2036*/2037static int hl_fw_dynamic_validate_memory_bound(struct hl_device *hdev,2038u64 addr, size_t size,2039struct pci_mem_region *region)2040{2041u64 end_addr;20422043/* now make sure that the memory transfer is within region's bounds */2044end_addr = addr + size;2045if (end_addr >= region->region_base + region->region_size) {2046dev_err(hdev->dev,2047"dynamic FW load: memory transfer end address out of memory region bounds. addr: %llx\n",2048end_addr);2049return -EIO;2050}20512052/*2053* now make sure memory transfer is within predefined BAR bounds.2054* this is to make sure we do not need to set the bar (e.g. for DRAM2055* memory transfers)2056*/2057if (end_addr >= region->region_base - region->offset_in_bar +2058region->bar_size) {2059dev_err(hdev->dev,2060"FW image beyond PCI BAR bounds\n");2061return -EIO;2062}20632064return 0;2065}20662067/**2068* hl_fw_dynamic_validate_descriptor - validate FW descriptor2069*2070* @hdev: pointer to the habanalabs device structure2071* @fw_loader: managing structure for loading device's FW2072* @fw_desc: the descriptor from FW2073*2074* @return 0 on success, otherwise non-zero error code2075*/2076static int hl_fw_dynamic_validate_descriptor(struct hl_device *hdev,2077struct fw_load_mgr *fw_loader,2078struct lkd_fw_comms_desc *fw_desc)2079{2080struct pci_mem_region *region;2081enum pci_region region_id;2082size_t data_size;2083u32 data_crc32;2084u8 *data_ptr;2085u64 addr;2086int rc;20872088if (le32_to_cpu(fw_desc->header.magic) != HL_COMMS_DESC_MAGIC)2089dev_dbg(hdev->dev, "Invalid magic for dynamic FW descriptor (%x)\n",2090fw_desc->header.magic);20912092if (fw_desc->header.version != HL_COMMS_DESC_VER)2093dev_dbg(hdev->dev, "Invalid version for dynamic FW descriptor (%x)\n",2094fw_desc->header.version);20952096/*2097* Calc CRC32 of data without header. use the size of the descriptor2098* reported by firmware, without calculating it ourself, to allow adding2099* more fields to the lkd_fw_comms_desc structure.2100* note that no alignment/stride address issues here as all structures2101* are 64 bit padded.2102*/2103data_ptr = (u8 *)fw_desc + sizeof(struct comms_msg_header);2104data_size = le16_to_cpu(fw_desc->header.size);21052106data_crc32 = hl_fw_compat_crc32(data_ptr, data_size);2107if (data_crc32 != le32_to_cpu(fw_desc->header.crc32)) {2108dev_err(hdev->dev, "CRC32 mismatch for dynamic FW descriptor (%x:%x)\n",2109data_crc32, fw_desc->header.crc32);2110return -EIO;2111}21122113/* find memory region to which to copy the image */2114addr = le64_to_cpu(fw_desc->img_addr);2115region_id = hl_get_pci_memory_region(hdev, addr);2116if ((region_id != PCI_REGION_SRAM) && ((region_id != PCI_REGION_DRAM))) {2117dev_err(hdev->dev, "Invalid region to copy FW image address=%llx\n", addr);2118return -EIO;2119}21202121region = &hdev->pci_mem_region[region_id];21222123/* store the region for the copy stage */2124fw_loader->dynamic_loader.image_region = region;21252126/*2127* here we know that the start address is valid, now make sure that the2128* image is within region's bounds2129*/2130rc = hl_fw_dynamic_validate_memory_bound(hdev, addr,2131fw_loader->dynamic_loader.fw_image_size,2132region);2133if (rc) {2134dev_err(hdev->dev, "invalid mem transfer request for FW image\n");2135return rc;2136}21372138/* here we can mark the descriptor as valid as the content has been validated */2139fw_loader->dynamic_loader.fw_desc_valid = true;21402141return 0;2142}21432144static int hl_fw_dynamic_validate_response(struct hl_device *hdev,2145struct fw_response *response,2146struct pci_mem_region *region)2147{2148u64 device_addr;2149int rc;21502151device_addr = region->region_base + response->ram_offset;21522153/*2154* validate that the descriptor is within region's bounds2155* Note that as the start address was supplied according to the RAM2156* type- testing only the end address is enough2157*/2158rc = hl_fw_dynamic_validate_memory_bound(hdev, device_addr,2159sizeof(struct lkd_fw_comms_desc),2160region);2161return rc;2162}21632164/*2165* hl_fw_dynamic_read_descriptor_msg - read and show the ascii msg that sent by fw2166*2167* @hdev: pointer to the habanalabs device structure2168* @fw_desc: the descriptor from FW2169*/2170static void hl_fw_dynamic_read_descriptor_msg(struct hl_device *hdev,2171struct lkd_fw_comms_desc *fw_desc)2172{2173int i;2174char *msg;21752176for (i = 0 ; i < LKD_FW_ASCII_MSG_MAX ; i++) {2177if (!fw_desc->ascii_msg[i].valid)2178return;21792180/* force NULL termination */2181msg = fw_desc->ascii_msg[i].msg;2182msg[LKD_FW_ASCII_MSG_MAX_LEN - 1] = '\0';21832184switch (fw_desc->ascii_msg[i].msg_lvl) {2185case LKD_FW_ASCII_MSG_ERR:2186dev_err(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2187break;2188case LKD_FW_ASCII_MSG_WRN:2189dev_warn(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2190break;2191case LKD_FW_ASCII_MSG_INF:2192dev_info(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2193break;2194default:2195dev_dbg(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2196break;2197}2198}2199}22002201/**2202* hl_fw_dynamic_read_and_validate_descriptor - read and validate FW descriptor2203*2204* @hdev: pointer to the habanalabs device structure2205* @fw_loader: managing structure for loading device's FW2206*2207* @return 0 on success, otherwise non-zero error code2208*/2209static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,2210struct fw_load_mgr *fw_loader)2211{2212struct lkd_fw_comms_desc *fw_desc;2213struct pci_mem_region *region;2214struct fw_response *response;2215void *temp_fw_desc;2216void __iomem *src;2217u16 fw_data_size;2218enum pci_region region_id;2219int rc;22202221fw_desc = &fw_loader->dynamic_loader.comm_desc;2222response = &fw_loader->dynamic_loader.response;22232224region_id = (response->ram_type == COMMS_SRAM) ?2225PCI_REGION_SRAM : PCI_REGION_DRAM;22262227region = &hdev->pci_mem_region[region_id];22282229rc = hl_fw_dynamic_validate_response(hdev, response, region);2230if (rc) {2231dev_err(hdev->dev,2232"invalid mem transfer request for FW descriptor\n");2233return rc;2234}22352236/*2237* extract address to copy the descriptor from2238* in addition, as the descriptor value is going to be over-ridden by new data- we mark it2239* as invalid.2240* it will be marked again as valid once validated2241*/2242fw_loader->dynamic_loader.fw_desc_valid = false;2243src = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +2244response->ram_offset;22452246/*2247* We do the copy of the fw descriptor in 2 phases:2248* 1. copy the header + data info according to our lkd_fw_comms_desc definition.2249* then we're able to read the actual data size provided by fw.2250* this is needed for cases where data in descriptor was changed(add/remove)2251* in embedded specs header file before updating lkd copy of the header file2252* 2. copy descriptor to temporary buffer with aligned size and send it to validation2253*/2254memcpy_fromio(fw_desc, src, sizeof(struct lkd_fw_comms_desc));2255fw_data_size = le16_to_cpu(fw_desc->header.size);22562257temp_fw_desc = vzalloc(sizeof(struct comms_msg_header) + fw_data_size);2258if (!temp_fw_desc)2259return -ENOMEM;22602261memcpy_fromio(temp_fw_desc, src, sizeof(struct comms_msg_header) + fw_data_size);22622263rc = hl_fw_dynamic_validate_descriptor(hdev, fw_loader,2264(struct lkd_fw_comms_desc *) temp_fw_desc);22652266if (!rc)2267hl_fw_dynamic_read_descriptor_msg(hdev, temp_fw_desc);22682269vfree(temp_fw_desc);22702271return rc;2272}22732274/**2275* hl_fw_dynamic_request_descriptor - handshake with CPU to get FW descriptor2276*2277* @hdev: pointer to the habanalabs device structure2278* @fw_loader: managing structure for loading device's FW2279* @next_image_size: size to allocate for next FW component2280*2281* @return 0 on success, otherwise non-zero error code2282*/2283static int hl_fw_dynamic_request_descriptor(struct hl_device *hdev,2284struct fw_load_mgr *fw_loader,2285size_t next_image_size)2286{2287int rc;22882289rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_PREP_DESC,2290next_image_size, true,2291fw_loader->cpu_timeout);2292if (rc)2293return rc;22942295return hl_fw_dynamic_read_and_validate_descriptor(hdev, fw_loader);2296}22972298/**2299* hl_fw_dynamic_read_device_fw_version - read FW version to exposed properties2300*2301* @hdev: pointer to the habanalabs device structure2302* @fwc: the firmware component2303* @fw_version: fw component's version string2304*/2305static int hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev,2306enum hl_fw_component fwc,2307const char *fw_version)2308{2309struct asic_fixed_properties *prop = &hdev->asic_prop;2310char *preboot_ver, *boot_ver;2311char btl_ver[32];2312int rc;23132314switch (fwc) {2315case FW_COMP_BOOT_FIT:2316strscpy(prop->uboot_ver, fw_version, VERSION_MAX_LEN);2317boot_ver = extract_fw_ver_from_str(prop->uboot_ver);2318if (boot_ver) {2319dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);2320kfree(boot_ver);2321}23222323break;2324case FW_COMP_PREBOOT:2325strscpy(prop->preboot_ver, fw_version, VERSION_MAX_LEN);2326preboot_ver = strnstr(prop->preboot_ver, "Preboot", VERSION_MAX_LEN);2327dev_info(hdev->dev, "preboot full version: '%s'\n", preboot_ver);23282329if (preboot_ver && preboot_ver != prop->preboot_ver) {2330strscpy(btl_ver, prop->preboot_ver,2331min((int) (preboot_ver - prop->preboot_ver), 31));2332dev_info(hdev->dev, "%s\n", btl_ver);2333}23342335rc = hl_get_sw_major_minor_subminor(hdev, preboot_ver);2336if (rc)2337return rc;2338preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);2339if (preboot_ver) {2340rc = hl_get_preboot_major_minor(hdev, preboot_ver);2341kfree(preboot_ver);2342if (rc)2343return rc;2344}23452346break;2347default:2348dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);2349return -EINVAL;2350}23512352return 0;2353}23542355/**2356* hl_fw_dynamic_copy_image - copy image to memory allocated by the FW2357*2358* @hdev: pointer to the habanalabs device structure2359* @fw: fw descriptor2360* @fw_loader: managing structure for loading device's FW2361*/2362static int hl_fw_dynamic_copy_image(struct hl_device *hdev,2363const struct firmware *fw,2364struct fw_load_mgr *fw_loader)2365{2366struct lkd_fw_comms_desc *fw_desc;2367struct pci_mem_region *region;2368void __iomem *dest;2369u64 addr;2370int rc;23712372fw_desc = &fw_loader->dynamic_loader.comm_desc;2373addr = le64_to_cpu(fw_desc->img_addr);23742375/* find memory region to which to copy the image */2376region = fw_loader->dynamic_loader.image_region;23772378dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +2379(addr - region->region_base);23802381rc = hl_fw_copy_fw_to_device(hdev, fw, dest,2382fw_loader->boot_fit_img.src_off,2383fw_loader->boot_fit_img.copy_size);23842385return rc;2386}23872388/**2389* hl_fw_dynamic_copy_msg - copy msg to memory allocated by the FW2390*2391* @hdev: pointer to the habanalabs device structure2392* @msg: message2393* @fw_loader: managing structure for loading device's FW2394*/2395static int hl_fw_dynamic_copy_msg(struct hl_device *hdev,2396struct lkd_msg_comms *msg, struct fw_load_mgr *fw_loader)2397{2398struct lkd_fw_comms_desc *fw_desc;2399struct pci_mem_region *region;2400void __iomem *dest;2401u64 addr;2402int rc;24032404fw_desc = &fw_loader->dynamic_loader.comm_desc;2405addr = le64_to_cpu(fw_desc->img_addr);24062407/* find memory region to which to copy the image */2408region = fw_loader->dynamic_loader.image_region;24092410dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +2411(addr - region->region_base);24122413rc = hl_fw_copy_msg_to_device(hdev, msg, dest, 0, 0);24142415return rc;2416}24172418/**2419* hl_fw_boot_fit_update_state - update internal data structures after boot-fit2420* is loaded2421*2422* @hdev: pointer to the habanalabs device structure2423* @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 02424* @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 12425*2426* @return 0 on success, otherwise non-zero error code2427*/2428static void hl_fw_boot_fit_update_state(struct hl_device *hdev,2429u32 cpu_boot_dev_sts0_reg,2430u32 cpu_boot_dev_sts1_reg)2431{2432struct asic_fixed_properties *prop = &hdev->asic_prop;24332434hdev->fw_loader.fw_comp_loaded |= FW_TYPE_BOOT_CPU;24352436/* Read boot_cpu status bits */2437if (prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) {2438prop->fw_bootfit_cpu_boot_dev_sts0 =2439RREG32(cpu_boot_dev_sts0_reg);24402441prop->hard_reset_done_by_fw = !!(prop->fw_bootfit_cpu_boot_dev_sts0 &2442CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);24432444dev_dbg(hdev->dev, "Firmware boot CPU status0 %#x\n",2445prop->fw_bootfit_cpu_boot_dev_sts0);2446}24472448if (prop->fw_cpu_boot_dev_sts1_valid) {2449prop->fw_bootfit_cpu_boot_dev_sts1 =2450RREG32(cpu_boot_dev_sts1_reg);24512452dev_dbg(hdev->dev, "Firmware boot CPU status1 %#x\n",2453prop->fw_bootfit_cpu_boot_dev_sts1);2454}24552456dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n",2457prop->hard_reset_done_by_fw ? "enabled" : "disabled");2458}24592460static void hl_fw_dynamic_update_linux_interrupt_if(struct hl_device *hdev)2461{2462struct cpu_dyn_regs *dyn_regs =2463&hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;24642465/* Check whether all 3 interrupt interfaces are set, if not use a2466* single interface2467*/2468if (!hdev->asic_prop.gic_interrupts_enable &&2469!(hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &2470CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN)) {2471dyn_regs->gic_host_halt_irq = dyn_regs->gic_host_pi_upd_irq;2472dyn_regs->gic_host_ints_irq = dyn_regs->gic_host_pi_upd_irq;24732474dev_warn(hdev->dev,2475"Using a single interrupt interface towards cpucp");2476}2477}2478/**2479* hl_fw_dynamic_load_image - load FW image using dynamic protocol2480*2481* @hdev: pointer to the habanalabs device structure2482* @fw_loader: managing structure for loading device's FW2483* @load_fwc: the FW component to be loaded2484* @img_ld_timeout: image load timeout2485*2486* @return 0 on success, otherwise non-zero error code2487*/2488static int hl_fw_dynamic_load_image(struct hl_device *hdev,2489struct fw_load_mgr *fw_loader,2490enum hl_fw_component load_fwc,2491u32 img_ld_timeout)2492{2493enum hl_fw_component cur_fwc;2494const struct firmware *fw;2495char *fw_name;2496int rc = 0;24972498/*2499* when loading image we have one of 2 scenarios:2500* 1. current FW component is preboot and we want to load boot-fit2501* 2. current FW component is boot-fit and we want to load linux2502*/2503if (load_fwc == FW_COMP_BOOT_FIT) {2504cur_fwc = FW_COMP_PREBOOT;2505fw_name = fw_loader->boot_fit_img.image_name;2506} else {2507cur_fwc = FW_COMP_BOOT_FIT;2508fw_name = fw_loader->linux_img.image_name;2509}25102511/* request FW in order to communicate to FW the size to be allocated */2512rc = hl_request_fw(hdev, &fw, fw_name);2513if (rc)2514return rc;25152516/* store the image size for future validation */2517fw_loader->dynamic_loader.fw_image_size = fw->size;25182519rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, fw->size);2520if (rc)2521goto release_fw;25222523/* read preboot version */2524rc = hl_fw_dynamic_read_device_fw_version(hdev, cur_fwc,2525fw_loader->dynamic_loader.comm_desc.cur_fw_ver);2526if (rc)2527goto release_fw;25282529/* copy boot fit to space allocated by FW */2530rc = hl_fw_dynamic_copy_image(hdev, fw, fw_loader);2531if (rc)2532goto release_fw;25332534rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,25350, true,2536fw_loader->cpu_timeout);2537if (rc)2538goto release_fw;25392540rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,25410, false,2542img_ld_timeout);25432544release_fw:2545hl_release_firmware(fw);2546return rc;2547}25482549static int hl_fw_dynamic_wait_for_boot_fit_active(struct hl_device *hdev,2550struct fw_load_mgr *fw_loader)2551{2552struct dynamic_fw_load_mgr *dyn_loader;2553u32 status;2554int rc;25552556dyn_loader = &fw_loader->dynamic_loader;25572558/*2559* Make sure CPU boot-loader is running2560* Note that the CPU_BOOT_STATUS_SRAM_AVAIL is generally set by Linux2561* yet there is a debug scenario in which we loading uboot (without Linux)2562* which at later stage is relocated to DRAM. In this case we expect2563* uboot to set the CPU_BOOT_STATUS_SRAM_AVAIL and so we add it to the2564* poll flags2565*/2566rc = hl_poll_timeout(2567hdev,2568le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status),2569status,2570(status == CPU_BOOT_STATUS_READY_TO_BOOT) ||2571(status == CPU_BOOT_STATUS_SRAM_AVAIL),2572hdev->fw_poll_interval_usec,2573dyn_loader->wait_for_bl_timeout);2574if (rc) {2575dev_err(hdev->dev, "failed to wait for boot (status = %d)\n", status);2576return rc;2577}25782579dev_dbg(hdev->dev, "uboot status = %d\n", status);2580return 0;2581}25822583static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev,2584struct fw_load_mgr *fw_loader)2585{2586struct dynamic_fw_load_mgr *dyn_loader;2587u32 status;2588int rc;25892590dyn_loader = &fw_loader->dynamic_loader;25912592/* Make sure CPU linux is running */25932594rc = hl_poll_timeout(2595hdev,2596le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status),2597status,2598(status == CPU_BOOT_STATUS_SRAM_AVAIL),2599hdev->fw_poll_interval_usec,2600fw_loader->cpu_timeout);2601if (rc) {2602dev_err(hdev->dev, "failed to wait for Linux (status = %d)\n", status);2603return rc;2604}26052606dev_dbg(hdev->dev, "Boot status = %d\n", status);2607return 0;2608}26092610/**2611* hl_fw_linux_update_state - update internal data structures after Linux2612* is loaded.2613* Note: Linux initialization is comprised mainly2614* of two stages - loading kernel (SRAM_AVAIL)2615* & loading ARMCP.2616* Therefore reading boot device status in any of2617* these stages might result in different values.2618*2619* @hdev: pointer to the habanalabs device structure2620* @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 02621* @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 12622*2623* @return 0 on success, otherwise non-zero error code2624*/2625static void hl_fw_linux_update_state(struct hl_device *hdev,2626u32 cpu_boot_dev_sts0_reg,2627u32 cpu_boot_dev_sts1_reg)2628{2629struct asic_fixed_properties *prop = &hdev->asic_prop;26302631hdev->fw_loader.fw_comp_loaded |= FW_TYPE_LINUX;26322633/* Read FW application security bits */2634if (prop->fw_cpu_boot_dev_sts0_valid) {2635prop->fw_app_cpu_boot_dev_sts0 = RREG32(cpu_boot_dev_sts0_reg);26362637prop->hard_reset_done_by_fw = !!(prop->fw_app_cpu_boot_dev_sts0 &2638CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);26392640if (prop->fw_app_cpu_boot_dev_sts0 &2641CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN)2642prop->gic_interrupts_enable = false;26432644dev_dbg(hdev->dev,2645"Firmware application CPU status0 %#x\n",2646prop->fw_app_cpu_boot_dev_sts0);26472648dev_dbg(hdev->dev, "GIC controller is %s\n",2649prop->gic_interrupts_enable ?2650"enabled" : "disabled");2651}26522653if (prop->fw_cpu_boot_dev_sts1_valid) {2654prop->fw_app_cpu_boot_dev_sts1 = RREG32(cpu_boot_dev_sts1_reg);26552656dev_dbg(hdev->dev,2657"Firmware application CPU status1 %#x\n",2658prop->fw_app_cpu_boot_dev_sts1);2659}26602661dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n",2662prop->hard_reset_done_by_fw ? "enabled" : "disabled");26632664dev_info(hdev->dev, "Successfully loaded firmware to device\n");2665}26662667/**2668* hl_fw_dynamic_send_msg - send a COMMS message with attached data2669*2670* @hdev: pointer to the habanalabs device structure2671* @fw_loader: managing structure for loading device's FW2672* @msg_type: message type2673* @data: data to be sent2674*2675* @return 0 on success, otherwise non-zero error code2676*/2677static int hl_fw_dynamic_send_msg(struct hl_device *hdev,2678struct fw_load_mgr *fw_loader, u8 msg_type, void *data)2679{2680struct lkd_msg_comms *msg;2681int rc;26822683msg = kzalloc(sizeof(*msg), GFP_KERNEL);2684if (!msg)2685return -ENOMEM;26862687/* create message to be sent */2688msg->header.type = msg_type;2689msg->header.size = cpu_to_le16(sizeof(struct comms_msg_header));2690msg->header.magic = cpu_to_le32(HL_COMMS_MSG_MAGIC);26912692switch (msg_type) {2693case HL_COMMS_RESET_CAUSE_TYPE:2694msg->reset_cause = *(__u8 *) data;2695break;26962697default:2698dev_err(hdev->dev,2699"Send COMMS message - invalid message type %u\n",2700msg_type);2701rc = -EINVAL;2702goto out;2703}27042705rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader,2706sizeof(struct lkd_msg_comms));2707if (rc)2708goto out;27092710/* copy message to space allocated by FW */2711rc = hl_fw_dynamic_copy_msg(hdev, msg, fw_loader);2712if (rc)2713goto out;27142715rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,27160, true,2717fw_loader->cpu_timeout);2718if (rc)2719goto out;27202721rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,27220, true,2723fw_loader->cpu_timeout);27242725out:2726kfree(msg);2727return rc;2728}27292730/**2731* hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol2732*2733* @hdev: pointer to the habanalabs device structure2734* @fw_loader: managing structure for loading device's FW2735*2736* @return 0 on success, otherwise non-zero error code2737*2738* brief: the dynamic protocol is master (LKD) slave (FW CPU) protocol.2739* the communication is done using registers:2740* - LKD command register2741* - FW status register2742* the protocol is race free. this goal is achieved by splitting the requests2743* and response to known synchronization points between the LKD and the FW.2744* each response to LKD request is known and bound to a predefined timeout.2745* in case of timeout expiration without the desired status from FW- the2746* protocol (and hence the boot) will fail.2747*/2748static int hl_fw_dynamic_init_cpu(struct hl_device *hdev,2749struct fw_load_mgr *fw_loader)2750{2751struct cpu_dyn_regs *dyn_regs;2752int rc, fw_error_rc;27532754dev_info(hdev->dev,2755"Loading %sfirmware to device, may take some time...\n",2756hdev->asic_prop.fw_security_enabled ? "secured " : "");27572758/* initialize FW descriptor as invalid */2759fw_loader->dynamic_loader.fw_desc_valid = false;27602761/*2762* In this stage, "cpu_dyn_regs" contains only LKD's hard coded values!2763* It will be updated from FW after hl_fw_dynamic_request_descriptor().2764*/2765dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;27662767rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE,27680, true,2769fw_loader->cpu_timeout);2770if (rc)2771goto protocol_err;27722773if (hdev->reset_info.curr_reset_cause) {2774rc = hl_fw_dynamic_send_msg(hdev, fw_loader,2775HL_COMMS_RESET_CAUSE_TYPE, &hdev->reset_info.curr_reset_cause);2776if (rc)2777goto protocol_err;27782779/* Clear current reset cause */2780hdev->reset_info.curr_reset_cause = HL_RESET_CAUSE_UNKNOWN;2781}27822783rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, sizeof(struct lkd_msg_comms));2784if (rc)2785goto protocol_err;27862787if (hdev->asic_prop.support_dynamic_resereved_fw_size)2788hdev->asic_prop.reserved_fw_mem_size =2789le32_to_cpu(fw_loader->dynamic_loader.comm_desc.rsvd_mem_size_mb) * SZ_1M;27902791if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) {2792struct lkd_fw_binning_info *binning_info;27932794/* read preboot version */2795rc = hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT,2796fw_loader->dynamic_loader.comm_desc.cur_fw_ver);2797if (rc)2798return rc;27992800/* read binning info from preboot */2801if (hdev->support_preboot_binning) {2802binning_info = &fw_loader->dynamic_loader.comm_desc.binning_info;2803hdev->tpc_binning = le64_to_cpu(binning_info->tpc_mask_l);2804hdev->dram_binning = le32_to_cpu(binning_info->dram_mask);2805hdev->edma_binning = le32_to_cpu(binning_info->edma_mask);2806hdev->decoder_binning = le32_to_cpu(binning_info->dec_mask);2807hdev->rotator_binning = le32_to_cpu(binning_info->rot_mask);28082809rc = hdev->asic_funcs->set_dram_properties(hdev);2810if (rc)2811return rc;28122813rc = hdev->asic_funcs->set_binning_masks(hdev);2814if (rc)2815return rc;28162817dev_dbg(hdev->dev,2818"Read binning masks: tpc: 0x%llx, dram: 0x%llx, edma: 0x%x, dec: 0x%x, rot:0x%x\n",2819hdev->tpc_binning, hdev->dram_binning, hdev->edma_binning,2820hdev->decoder_binning, hdev->rotator_binning);2821}28222823return 0;2824}28252826/* load boot fit to FW */2827rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_BOOT_FIT,2828fw_loader->boot_fit_timeout);2829if (rc) {2830dev_err(hdev->dev, "failed to load boot fit\n");2831goto protocol_err;2832}28332834rc = hl_fw_dynamic_wait_for_boot_fit_active(hdev, fw_loader);2835if (rc)2836goto protocol_err;28372838hl_fw_boot_fit_update_state(hdev,2839le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),2840le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));28412842/*2843* when testing FW load (without Linux) on PLDM we don't want to2844* wait until boot fit is active as it may take several hours.2845* instead, we load the bootfit and let it do all initialization in2846* the background.2847*/2848if (hdev->pldm && !(hdev->fw_components & FW_TYPE_LINUX))2849return 0;28502851/* Enable DRAM scrambling before Linux boot and after successful2852* UBoot2853*/2854hdev->asic_funcs->init_cpu_scrambler_dram(hdev);28552856if (!(hdev->fw_components & FW_TYPE_LINUX)) {2857dev_dbg(hdev->dev, "Skip loading Linux F/W\n");2858return 0;2859}28602861if (fw_loader->skip_bmc) {2862rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader,2863COMMS_SKIP_BMC, 0,2864true,2865fw_loader->cpu_timeout);2866if (rc) {2867dev_err(hdev->dev, "failed to load boot fit\n");2868goto protocol_err;2869}2870}28712872/* load Linux image to FW */2873rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_LINUX,2874fw_loader->cpu_timeout);2875if (rc) {2876dev_err(hdev->dev, "failed to load Linux\n");2877goto protocol_err;2878}28792880rc = hl_fw_dynamic_wait_for_linux_active(hdev, fw_loader);2881if (rc)2882goto protocol_err;28832884hl_fw_linux_update_state(hdev,2885le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),2886le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));28872888hl_fw_dynamic_update_linux_interrupt_if(hdev);28892890protocol_err:2891if (fw_loader->dynamic_loader.fw_desc_valid) {2892fw_error_rc = fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0),2893le32_to_cpu(dyn_regs->cpu_boot_err1),2894le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),2895le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));28962897if (fw_error_rc)2898return fw_error_rc;2899}29002901return rc;2902}29032904/**2905* hl_fw_static_init_cpu - initialize the device CPU using static protocol2906*2907* @hdev: pointer to the habanalabs device structure2908* @fw_loader: managing structure for loading device's FW2909*2910* @return 0 on success, otherwise non-zero error code2911*/2912static int hl_fw_static_init_cpu(struct hl_device *hdev,2913struct fw_load_mgr *fw_loader)2914{2915u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status;2916u32 cpu_boot_dev_status0_reg, cpu_boot_dev_status1_reg;2917struct static_fw_load_mgr *static_loader;2918u32 cpu_boot_status_reg;2919int rc;29202921if (!(hdev->fw_components & FW_TYPE_BOOT_CPU))2922return 0;29232924/* init common loader parameters */2925cpu_timeout = fw_loader->cpu_timeout;29262927/* init static loader parameters */2928static_loader = &fw_loader->static_loader;2929cpu_msg_status_reg = static_loader->cpu_cmd_status_to_host_reg;2930msg_to_cpu_reg = static_loader->kmd_msg_to_cpu_reg;2931cpu_boot_dev_status0_reg = static_loader->cpu_boot_dev_status0_reg;2932cpu_boot_dev_status1_reg = static_loader->cpu_boot_dev_status1_reg;2933cpu_boot_status_reg = static_loader->cpu_boot_status_reg;29342935dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n",2936cpu_timeout / USEC_PER_SEC);29372938/* Wait for boot FIT request */2939rc = hl_poll_timeout(2940hdev,2941cpu_boot_status_reg,2942status,2943status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT,2944hdev->fw_poll_interval_usec,2945fw_loader->boot_fit_timeout);29462947if (rc) {2948dev_dbg(hdev->dev,2949"No boot fit request received (status = %d), resuming boot\n", status);2950} else {2951rc = hdev->asic_funcs->load_boot_fit_to_device(hdev);2952if (rc)2953goto out;29542955/* Clear device CPU message status */2956WREG32(cpu_msg_status_reg, CPU_MSG_CLR);29572958/* Signal device CPU that boot loader is ready */2959WREG32(msg_to_cpu_reg, KMD_MSG_FIT_RDY);29602961/* Poll for CPU device ack */2962rc = hl_poll_timeout(2963hdev,2964cpu_msg_status_reg,2965status,2966status == CPU_MSG_OK,2967hdev->fw_poll_interval_usec,2968fw_loader->boot_fit_timeout);29692970if (rc) {2971dev_err(hdev->dev,2972"Timeout waiting for boot fit load ack (status = %d)\n", status);2973goto out;2974}29752976/* Clear message */2977WREG32(msg_to_cpu_reg, KMD_MSG_NA);2978}29792980/*2981* Make sure CPU boot-loader is running2982* Note that the CPU_BOOT_STATUS_SRAM_AVAIL is generally set by Linux2983* yet there is a debug scenario in which we loading uboot (without Linux)2984* which at later stage is relocated to DRAM. In this case we expect2985* uboot to set the CPU_BOOT_STATUS_SRAM_AVAIL and so we add it to the2986* poll flags2987*/2988rc = hl_poll_timeout(2989hdev,2990cpu_boot_status_reg,2991status,2992(status == CPU_BOOT_STATUS_DRAM_RDY) ||2993(status == CPU_BOOT_STATUS_NIC_FW_RDY) ||2994(status == CPU_BOOT_STATUS_READY_TO_BOOT) ||2995(status == CPU_BOOT_STATUS_SRAM_AVAIL),2996hdev->fw_poll_interval_usec,2997cpu_timeout);29982999dev_dbg(hdev->dev, "uboot status = %d\n", status);30003001/* Read U-Boot version now in case we will later fail */3002hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT);30033004/* update state according to boot stage */3005hl_fw_boot_fit_update_state(hdev, cpu_boot_dev_status0_reg,3006cpu_boot_dev_status1_reg);30073008if (rc) {3009detect_cpu_boot_status(hdev, status);3010rc = -EIO;3011goto out;3012}30133014/* Enable DRAM scrambling before Linux boot and after successful3015* UBoot3016*/3017hdev->asic_funcs->init_cpu_scrambler_dram(hdev);30183019if (!(hdev->fw_components & FW_TYPE_LINUX)) {3020dev_info(hdev->dev, "Skip loading Linux F/W\n");3021rc = 0;3022goto out;3023}30243025if (status == CPU_BOOT_STATUS_SRAM_AVAIL) {3026rc = 0;3027goto out;3028}30293030dev_info(hdev->dev,3031"Loading firmware to device, may take some time...\n");30323033rc = hdev->asic_funcs->load_firmware_to_device(hdev);3034if (rc)3035goto out;30363037if (fw_loader->skip_bmc) {3038WREG32(msg_to_cpu_reg, KMD_MSG_SKIP_BMC);30393040rc = hl_poll_timeout(3041hdev,3042cpu_boot_status_reg,3043status,3044(status == CPU_BOOT_STATUS_BMC_WAITING_SKIPPED),3045hdev->fw_poll_interval_usec,3046cpu_timeout);30473048if (rc) {3049dev_err(hdev->dev,3050"Failed to get ACK on skipping BMC (status = %d)\n",3051status);3052WREG32(msg_to_cpu_reg, KMD_MSG_NA);3053rc = -EIO;3054goto out;3055}3056}30573058WREG32(msg_to_cpu_reg, KMD_MSG_FIT_RDY);30593060rc = hl_poll_timeout(3061hdev,3062cpu_boot_status_reg,3063status,3064(status == CPU_BOOT_STATUS_SRAM_AVAIL),3065hdev->fw_poll_interval_usec,3066cpu_timeout);30673068/* Clear message */3069WREG32(msg_to_cpu_reg, KMD_MSG_NA);30703071if (rc) {3072if (status == CPU_BOOT_STATUS_FIT_CORRUPTED)3073dev_err(hdev->dev,3074"Device reports FIT image is corrupted\n");3075else3076dev_err(hdev->dev,3077"Failed to load firmware to device (status = %d)\n",3078status);30793080rc = -EIO;3081goto out;3082}30833084rc = fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,3085fw_loader->static_loader.boot_err1_reg,3086cpu_boot_dev_status0_reg,3087cpu_boot_dev_status1_reg);3088if (rc)3089return rc;30903091hl_fw_linux_update_state(hdev, cpu_boot_dev_status0_reg,3092cpu_boot_dev_status1_reg);30933094return 0;30953096out:3097fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,3098fw_loader->static_loader.boot_err1_reg,3099cpu_boot_dev_status0_reg,3100cpu_boot_dev_status1_reg);31013102return rc;3103}31043105/**3106* hl_fw_init_cpu - initialize the device CPU3107*3108* @hdev: pointer to the habanalabs device structure3109*3110* @return 0 on success, otherwise non-zero error code3111*3112* perform necessary initializations for device's CPU. takes into account if3113* init protocol is static or dynamic.3114*/3115int hl_fw_init_cpu(struct hl_device *hdev)3116{3117struct asic_fixed_properties *prop = &hdev->asic_prop;3118struct fw_load_mgr *fw_loader = &hdev->fw_loader;31193120return prop->dynamic_fw_load ?3121hl_fw_dynamic_init_cpu(hdev, fw_loader) :3122hl_fw_static_init_cpu(hdev, fw_loader);3123}31243125void hl_fw_set_pll_profile(struct hl_device *hdev)3126{3127hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index,3128hdev->asic_prop.max_freq_value);3129}31303131int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk)3132{3133long value;31343135if (!hl_device_operational(hdev, NULL))3136return -ENODEV;31373138if (!hdev->pdev) {3139*cur_clk = 0;3140*max_clk = 0;3141return 0;3142}31433144value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);31453146if (value < 0) {3147dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value);3148return value;3149}31503151*max_clk = (value / 1000 / 1000);31523153value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);31543155if (value < 0) {3156dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value);3157return value;3158}31593160*cur_clk = (value / 1000 / 1000);31613162return 0;3163}31643165long hl_fw_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr)3166{3167struct cpucp_packet pkt;3168u32 used_pll_idx;3169u64 result;3170int rc;31713172rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);3173if (rc)3174return rc;31753176memset(&pkt, 0, sizeof(pkt));31773178if (curr)3179pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_CURR_GET <<3180CPUCP_PKT_CTL_OPCODE_SHIFT);3181else3182pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);31833184pkt.pll_index = cpu_to_le32((u32)used_pll_idx);31853186rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);3187if (rc) {3188if (rc != -EAGAIN)3189dev_err(hdev->dev, "Failed to get frequency of PLL %d, error %d\n",3190used_pll_idx, rc);3191return rc;3192}31933194return (long) result;3195}31963197void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq)3198{3199struct cpucp_packet pkt;3200u32 used_pll_idx;3201int rc;32023203rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);3204if (rc)3205return;32063207memset(&pkt, 0, sizeof(pkt));32083209pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);3210pkt.pll_index = cpu_to_le32((u32)used_pll_idx);3211pkt.value = cpu_to_le64(freq);32123213rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);3214if (rc && rc != -EAGAIN)3215dev_err(hdev->dev, "Failed to set frequency to PLL %d, error %d\n",3216used_pll_idx, rc);3217}32183219long hl_fw_get_max_power(struct hl_device *hdev)3220{3221struct cpucp_packet pkt;3222u64 result;3223int rc;32243225memset(&pkt, 0, sizeof(pkt));32263227pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);32283229rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);3230if (rc) {3231if (rc != -EAGAIN)3232dev_err(hdev->dev, "Failed to get max power, error %d\n", rc);3233return rc;3234}32353236return result;3237}32383239void hl_fw_set_max_power(struct hl_device *hdev)3240{3241struct cpucp_packet pkt;3242int rc;32433244/* TODO: remove this after simulator supports this packet */3245if (!hdev->pdev)3246return;32473248memset(&pkt, 0, sizeof(pkt));32493250pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);3251pkt.value = cpu_to_le64(hdev->max_power);32523253rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);3254if (rc && rc != -EAGAIN)3255dev_err(hdev->dev, "Failed to set max power, error %d\n", rc);3256}32573258static int hl_fw_get_sec_attest_data(struct hl_device *hdev, u32 packet_id, void *data, u32 size,3259u32 nonce, u32 timeout)3260{3261struct cpucp_packet pkt = {};3262dma_addr_t req_dma_addr;3263void *req_cpu_addr;3264int rc;32653266req_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, size, &req_dma_addr);3267if (!req_cpu_addr) {3268dev_err(hdev->dev,3269"Failed to allocate DMA memory for CPU-CP packet %u\n", packet_id);3270return -ENOMEM;3271}32723273memset(data, 0, size);32743275pkt.ctl = cpu_to_le32(packet_id << CPUCP_PKT_CTL_OPCODE_SHIFT);3276pkt.addr = cpu_to_le64(req_dma_addr);3277pkt.data_max_size = cpu_to_le32(size);3278pkt.nonce = cpu_to_le32(nonce);32793280rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), timeout, NULL);3281if (rc) {3282if (rc != -EAGAIN)3283dev_err(hdev->dev,3284"Failed to handle CPU-CP pkt %u, error %d\n", packet_id, rc);3285goto out;3286}32873288memcpy(data, req_cpu_addr, size);32893290out:3291hl_cpu_accessible_dma_pool_free(hdev, size, req_cpu_addr);32923293return rc;3294}32953296int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_info *sec_attest_info,3297u32 nonce)3298{3299return hl_fw_get_sec_attest_data(hdev, CPUCP_PACKET_SEC_ATTEST_GET, sec_attest_info,3300sizeof(struct cpucp_sec_attest_info), nonce,3301HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC);3302}33033304int hl_fw_get_dev_info_signed(struct hl_device *hdev,3305struct cpucp_dev_info_signed *dev_info_signed, u32 nonce)3306{3307return hl_fw_get_sec_attest_data(hdev, CPUCP_PACKET_INFO_SIGNED_GET, dev_info_signed,3308sizeof(struct cpucp_dev_info_signed), nonce,3309HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC);3310}33113312int hl_fw_send_generic_request(struct hl_device *hdev, enum hl_passthrough_type sub_opcode,3313dma_addr_t buff, u32 *size)3314{3315struct cpucp_packet pkt = {};3316u64 result;3317int rc = 0;33183319pkt.ctl = cpu_to_le32(CPUCP_PACKET_GENERIC_PASSTHROUGH << CPUCP_PKT_CTL_OPCODE_SHIFT);3320pkt.addr = cpu_to_le64(buff);3321pkt.data_max_size = cpu_to_le32(*size);3322pkt.pkt_subidx = cpu_to_le32(sub_opcode);33233324rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)&pkt, sizeof(pkt),3325HL_CPUCP_INFO_TIMEOUT_USEC, &result);3326if (rc) {3327if (rc != -EAGAIN)3328dev_err(hdev->dev, "failed to send CPUCP data of generic fw pkt\n");3329} else {3330dev_dbg(hdev->dev, "generic pkt was successful, result: 0x%llx\n", result);3331}33323333*size = (u32)result;33343335return rc;3336}333733383339