3338 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Copyright 2016-2022 HabanaLabs, Ltd.5 * All Rights Reserved.6 */7 8#include "habanalabs.h"9#include <linux/habanalabs/hl_boot_if.h>10 11#include <linux/pci.h>12#include <linux/firmware.h>13#include <linux/crc32.h>14#include <linux/slab.h>15#include <linux/ctype.h>16#include <linux/vmalloc.h>17 18#include <trace/events/habanalabs.h>19 20#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */21 22static char *comms_cmd_str_arr[COMMS_INVLD_LAST] = {23 [COMMS_NOOP] = __stringify(COMMS_NOOP),24 [COMMS_CLR_STS] = __stringify(COMMS_CLR_STS),25 [COMMS_RST_STATE] = __stringify(COMMS_RST_STATE),26 [COMMS_PREP_DESC] = __stringify(COMMS_PREP_DESC),27 [COMMS_DATA_RDY] = __stringify(COMMS_DATA_RDY),28 [COMMS_EXEC] = __stringify(COMMS_EXEC),29 [COMMS_RST_DEV] = __stringify(COMMS_RST_DEV),30 [COMMS_GOTO_WFE] = __stringify(COMMS_GOTO_WFE),31 [COMMS_SKIP_BMC] = __stringify(COMMS_SKIP_BMC),32 [COMMS_PREP_DESC_ELBI] = __stringify(COMMS_PREP_DESC_ELBI),33};34 35static char *comms_sts_str_arr[COMMS_STS_INVLD_LAST] = {36 [COMMS_STS_NOOP] = __stringify(COMMS_STS_NOOP),37 [COMMS_STS_ACK] = __stringify(COMMS_STS_ACK),38 [COMMS_STS_OK] = __stringify(COMMS_STS_OK),39 [COMMS_STS_ERR] = __stringify(COMMS_STS_ERR),40 [COMMS_STS_VALID_ERR] = __stringify(COMMS_STS_VALID_ERR),41 [COMMS_STS_TIMEOUT_ERR] = __stringify(COMMS_STS_TIMEOUT_ERR),42};43 44/**45 * hl_fw_version_cmp() - compares the FW version to a specific version46 *47 * @hdev: pointer to hl_device structure48 * @major: major number of a reference version49 * @minor: minor number of a reference version50 * @subminor: sub-minor number of a reference version51 *52 * Return 1 if FW version greater than the reference version, -1 if it's53 * smaller and 0 if versions are identical.54 */55int hl_fw_version_cmp(struct hl_device *hdev, u32 major, u32 minor, u32 subminor)56{57 if (hdev->fw_sw_major_ver != major)58 return (hdev->fw_sw_major_ver > major) ? 1 : -1;59 60 if (hdev->fw_sw_minor_ver != minor)61 return (hdev->fw_sw_minor_ver > minor) ? 1 : -1;62 63 if (hdev->fw_sw_sub_minor_ver != subminor)64 return (hdev->fw_sw_sub_minor_ver > subminor) ? 1 : -1;65 66 return 0;67}68 69static char *extract_fw_ver_from_str(const char *fw_str)70{71 char *str, *fw_ver, *whitespace;72 u32 ver_offset;73 74 fw_ver = kmalloc(VERSION_MAX_LEN, GFP_KERNEL);75 if (!fw_ver)76 return NULL;77 78 str = strnstr(fw_str, "fw-", VERSION_MAX_LEN);79 if (!str)80 goto free_fw_ver;81 82 /* Skip the fw- part */83 str += 3;84 ver_offset = str - fw_str;85 86 /* Copy until the next whitespace */87 whitespace = strnstr(str, " ", VERSION_MAX_LEN - ver_offset);88 if (!whitespace)89 goto free_fw_ver;90 91 strscpy(fw_ver, str, whitespace - str + 1);92 93 return fw_ver;94 95free_fw_ver:96 kfree(fw_ver);97 return NULL;98}99 100/**101 * extract_u32_until_given_char() - given a string of the format "<u32><char>*", extract the u32.102 * @str: the given string103 * @ver_num: the pointer to the extracted u32 to be returned to the caller.104 * @given_char: the given char at the end of the u32 in the string105 *106 * Return: Upon success, return a pointer to the given_char in the string. Upon failure, return NULL107 */108static char *extract_u32_until_given_char(char *str, u32 *ver_num, char given_char)109{110 char num_str[8] = {}, *ch;111 112 ch = strchrnul(str, given_char);113 if (*ch == '\0' || ch == str || ch - str >= sizeof(num_str))114 return NULL;115 116 memcpy(num_str, str, ch - str);117 if (kstrtou32(num_str, 10, ver_num))118 return NULL;119 return ch;120}121 122/**123 * hl_get_sw_major_minor_subminor() - extract the FW's SW version major, minor, sub-minor124 * from the version string125 * @hdev: pointer to the hl_device126 * @fw_str: the FW's version string127 *128 * The extracted version is set in the hdev fields: fw_sw_{major/minor/sub_minor}_ver.129 *130 * fw_str is expected to have one of two possible formats, examples:131 * 1) 'Preboot version hl-gaudi2-1.9.0-fw-42.0.1-sec-3'132 * 2) 'Preboot version hl-gaudi2-1.9.0-rc-fw-42.0.1-sec-3'133 * In those examples, the SW major,minor,subminor are correspondingly: 1,9,0.134 *135 * Return: 0 for success or a negative error code for failure.136 */137static int hl_get_sw_major_minor_subminor(struct hl_device *hdev, const char *fw_str)138{139 char *end, *start;140 141 end = strnstr(fw_str, "-rc-", VERSION_MAX_LEN);142 if (end == fw_str)143 return -EINVAL;144 145 if (!end)146 end = strnstr(fw_str, "-fw-", VERSION_MAX_LEN);147 148 if (end == fw_str)149 return -EINVAL;150 151 if (!end)152 return -EINVAL;153 154 for (start = end - 1; start != fw_str; start--) {155 if (*start == '-')156 break;157 }158 159 if (start == fw_str)160 return -EINVAL;161 162 /* start/end point each to the starting and ending hyphen of the sw version e.g. -1.9.0- */163 start++;164 start = extract_u32_until_given_char(start, &hdev->fw_sw_major_ver, '.');165 if (!start)166 goto err_zero_ver;167 168 start++;169 start = extract_u32_until_given_char(start, &hdev->fw_sw_minor_ver, '.');170 if (!start)171 goto err_zero_ver;172 173 start++;174 start = extract_u32_until_given_char(start, &hdev->fw_sw_sub_minor_ver, '-');175 if (!start)176 goto err_zero_ver;177 178 return 0;179 180err_zero_ver:181 hdev->fw_sw_major_ver = 0;182 hdev->fw_sw_minor_ver = 0;183 hdev->fw_sw_sub_minor_ver = 0;184 return -EINVAL;185}186 187/**188 * hl_get_preboot_major_minor() - extract the FW's version major, minor from the version string.189 * @hdev: pointer to the hl_device190 * @preboot_ver: the FW's version string191 *192 * preboot_ver is expected to be the format of <major>.<minor>.<sub minor>*, e.g: 42.0.1-sec-3193 * The extracted version is set in the hdev fields: fw_inner_{major/minor}_ver.194 *195 * Return: 0 on success, negative error code for failure.196 */197static int hl_get_preboot_major_minor(struct hl_device *hdev, char *preboot_ver)198{199 preboot_ver = extract_u32_until_given_char(preboot_ver, &hdev->fw_inner_major_ver, '.');200 if (!preboot_ver) {201 dev_err(hdev->dev, "Error parsing preboot major version\n");202 goto err_zero_ver;203 }204 205 preboot_ver++;206 207 preboot_ver = extract_u32_until_given_char(preboot_ver, &hdev->fw_inner_minor_ver, '.');208 if (!preboot_ver) {209 dev_err(hdev->dev, "Error parsing preboot minor version\n");210 goto err_zero_ver;211 }212 return 0;213 214err_zero_ver:215 hdev->fw_inner_major_ver = 0;216 hdev->fw_inner_minor_ver = 0;217 return -EINVAL;218}219 220static int hl_request_fw(struct hl_device *hdev,221 const struct firmware **firmware_p,222 const char *fw_name)223{224 size_t fw_size;225 int rc;226 227 rc = request_firmware(firmware_p, fw_name, hdev->dev);228 if (rc) {229 dev_err(hdev->dev, "Firmware file %s is not found! (error %d)\n",230 fw_name, rc);231 goto out;232 }233 234 fw_size = (*firmware_p)->size;235 if ((fw_size % 4) != 0) {236 dev_err(hdev->dev, "Illegal %s firmware size %zu\n",237 fw_name, fw_size);238 rc = -EINVAL;239 goto release_fw;240 }241 242 dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);243 244 if (fw_size > FW_FILE_MAX_SIZE) {245 dev_err(hdev->dev,246 "FW file size %zu exceeds maximum of %u bytes\n",247 fw_size, FW_FILE_MAX_SIZE);248 rc = -EINVAL;249 goto release_fw;250 }251 252 return 0;253 254release_fw:255 release_firmware(*firmware_p);256out:257 return rc;258}259 260/**261 * hl_release_firmware() - release FW262 *263 * @fw: fw descriptor264 *265 * note: this inline function added to serve as a comprehensive mirror for the266 * hl_request_fw function.267 */268static inline void hl_release_firmware(const struct firmware *fw)269{270 release_firmware(fw);271}272 273/**274 * hl_fw_copy_fw_to_device() - copy FW to device275 *276 * @hdev: pointer to hl_device structure.277 * @fw: fw descriptor278 * @dst: IO memory mapped address space to copy firmware to279 * @src_offset: offset in src FW to copy from280 * @size: amount of bytes to copy (0 to copy the whole binary)281 *282 * actual copy of FW binary data to device, shared by static and dynamic loaders283 */284static int hl_fw_copy_fw_to_device(struct hl_device *hdev,285 const struct firmware *fw, void __iomem *dst,286 u32 src_offset, u32 size)287{288 const void *fw_data;289 290 /* size 0 indicates to copy the whole file */291 if (!size)292 size = fw->size;293 294 if (src_offset + size > fw->size) {295 dev_err(hdev->dev,296 "size to copy(%u) and offset(%u) are invalid\n",297 size, src_offset);298 return -EINVAL;299 }300 301 fw_data = (const void *) fw->data;302 303 memcpy_toio(dst, fw_data + src_offset, size);304 return 0;305}306 307/**308 * hl_fw_copy_msg_to_device() - copy message to device309 *310 * @hdev: pointer to hl_device structure.311 * @msg: message312 * @dst: IO memory mapped address space to copy firmware to313 * @src_offset: offset in src message to copy from314 * @size: amount of bytes to copy (0 to copy the whole binary)315 *316 * actual copy of message data to device.317 */318static int hl_fw_copy_msg_to_device(struct hl_device *hdev,319 struct lkd_msg_comms *msg, void __iomem *dst,320 u32 src_offset, u32 size)321{322 void *msg_data;323 324 /* size 0 indicates to copy the whole file */325 if (!size)326 size = sizeof(struct lkd_msg_comms);327 328 if (src_offset + size > sizeof(struct lkd_msg_comms)) {329 dev_err(hdev->dev,330 "size to copy(%u) and offset(%u) are invalid\n",331 size, src_offset);332 return -EINVAL;333 }334 335 msg_data = (void *) msg;336 337 memcpy_toio(dst, msg_data + src_offset, size);338 339 return 0;340}341 342/**343 * hl_fw_load_fw_to_device() - Load F/W code to device's memory.344 *345 * @hdev: pointer to hl_device structure.346 * @fw_name: the firmware image name347 * @dst: IO memory mapped address space to copy firmware to348 * @src_offset: offset in src FW to copy from349 * @size: amount of bytes to copy (0 to copy the whole binary)350 *351 * Copy fw code from firmware file to device memory.352 *353 * Return: 0 on success, non-zero for failure.354 */355int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,356 void __iomem *dst, u32 src_offset, u32 size)357{358 const struct firmware *fw;359 int rc;360 361 rc = hl_request_fw(hdev, &fw, fw_name);362 if (rc)363 return rc;364 365 rc = hl_fw_copy_fw_to_device(hdev, fw, dst, src_offset, size);366 367 hl_release_firmware(fw);368 return rc;369}370 371int hl_fw_send_pci_access_msg(struct hl_device *hdev, u32 opcode, u64 value)372{373 struct cpucp_packet pkt = {};374 int rc;375 376 pkt.ctl = cpu_to_le32(opcode << CPUCP_PKT_CTL_OPCODE_SHIFT);377 pkt.value = cpu_to_le64(value);378 379 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);380 if (rc)381 dev_err(hdev->dev, "Failed to disable FW's PCI access\n");382 383 return rc;384}385 386/**387 * hl_fw_send_cpu_message() - send CPU message to the device.388 *389 * @hdev: pointer to hl_device structure.390 * @hw_queue_id: HW queue ID391 * @msg: raw data of the message/packet392 * @size: size of @msg in bytes393 * @timeout_us: timeout in usec to wait for CPU reply on the message394 * @result: return code reported by FW395 *396 * send message to the device CPU.397 *398 * Return: 0 on success, non-zero for failure.399 * -ENOMEM: memory allocation failure400 * -EAGAIN: CPU is disabled (try again when enabled)401 * -ETIMEDOUT: timeout waiting for FW response402 * -EIO: protocol error403 */404int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,405 u16 size, u32 timeout_us, u64 *result)406{407 struct hl_hw_queue *queue = &hdev->kernel_queues[hw_queue_id];408 struct asic_fixed_properties *prop = &hdev->asic_prop;409 u32 tmp, expected_ack_val, pi, opcode;410 struct cpucp_packet *pkt;411 dma_addr_t pkt_dma_addr;412 struct hl_bd *sent_bd;413 int rc = 0, fw_rc;414 415 pkt = hl_cpu_accessible_dma_pool_alloc(hdev, size, &pkt_dma_addr);416 if (!pkt) {417 dev_err(hdev->dev, "Failed to allocate DMA memory for packet to CPU\n");418 return -ENOMEM;419 }420 421 memcpy(pkt, msg, size);422 423 mutex_lock(&hdev->send_cpu_message_lock);424 425 /* CPU-CP messages can be sent during soft-reset */426 if (hdev->disabled && !hdev->reset_info.in_compute_reset)427 goto out;428 429 if (hdev->device_cpu_disabled) {430 rc = -EAGAIN;431 goto out;432 }433 434 /* set fence to a non valid value */435 pkt->fence = cpu_to_le32(UINT_MAX);436 pi = queue->pi;437 438 /*439 * The CPU queue is a synchronous queue with an effective depth of440 * a single entry (although it is allocated with room for multiple441 * entries). We lock on it using 'send_cpu_message_lock' which442 * serializes accesses to the CPU queue.443 * Which means that we don't need to lock the access to the entire H/W444 * queues module when submitting a JOB to the CPU queue.445 */446 hl_hw_queue_submit_bd(hdev, queue, hl_queue_inc_ptr(queue->pi), size, pkt_dma_addr);447 448 if (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN)449 expected_ack_val = queue->pi;450 else451 expected_ack_val = CPUCP_PACKET_FENCE_VAL;452 453 rc = hl_poll_timeout_memory(hdev, &pkt->fence, tmp,454 (tmp == expected_ack_val), 1000,455 timeout_us, true);456 457 hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);458 459 if (rc == -ETIMEDOUT) {460 /* If FW performed reset just before sending it a packet, we will get a timeout.461 * This is expected behavior, hence no need for error message.462 */463 if (!hl_device_operational(hdev, NULL) && !hdev->reset_info.in_compute_reset) {464 dev_dbg(hdev->dev, "Device CPU packet timeout (0x%x) due to FW reset\n",465 tmp);466 } else {467 struct hl_bd *bd = queue->kernel_address;468 469 bd += hl_pi_2_offset(pi);470 471 dev_err(hdev->dev, "Device CPU packet timeout (status = 0x%x)\n"472 "Pkt info[%u]: dma_addr: 0x%llx, kernel_addr: %p, len:0x%x, ctl: 0x%x, ptr:0x%llx, dram_bd:%u\n",473 tmp, pi, pkt_dma_addr, (void *)pkt, bd->len, bd->ctl, bd->ptr,474 queue->dram_bd);475 }476 hdev->device_cpu_disabled = true;477 goto out;478 }479 480 tmp = le32_to_cpu(pkt->ctl);481 482 fw_rc = (tmp & CPUCP_PKT_CTL_RC_MASK) >> CPUCP_PKT_CTL_RC_SHIFT;483 if (fw_rc) {484 opcode = (tmp & CPUCP_PKT_CTL_OPCODE_MASK) >> CPUCP_PKT_CTL_OPCODE_SHIFT;485 486 if (!prop->supports_advanced_cpucp_rc) {487 dev_dbg(hdev->dev, "F/W ERROR %d for CPU packet %d\n", rc, opcode);488 rc = -EIO;489 goto scrub_descriptor;490 }491 492 switch (fw_rc) {493 case cpucp_packet_invalid:494 dev_err(hdev->dev,495 "CPU packet %d is not supported by F/W\n", opcode);496 break;497 case cpucp_packet_fault:498 dev_err(hdev->dev,499 "F/W failed processing CPU packet %d\n", opcode);500 break;501 case cpucp_packet_invalid_pkt:502 dev_dbg(hdev->dev,503 "CPU packet %d is not supported by F/W\n", opcode);504 break;505 case cpucp_packet_invalid_params:506 dev_err(hdev->dev,507 "F/W reports invalid parameters for CPU packet %d\n", opcode);508 break;509 510 default:511 dev_err(hdev->dev,512 "Unknown F/W ERROR %d for CPU packet %d\n", rc, opcode);513 }514 515 /* propagate the return code from the f/w to the callers who want to check it */516 if (result)517 *result = fw_rc;518 519 rc = -EIO;520 521 } else if (result) {522 *result = le64_to_cpu(pkt->result);523 }524 525scrub_descriptor:526 /* Scrub previous buffer descriptor 'ctl' field which contains the527 * previous PI value written during packet submission.528 * We must do this or else F/W can read an old value upon queue wraparound.529 */530 sent_bd = queue->kernel_address;531 sent_bd += hl_pi_2_offset(pi);532 sent_bd->ctl = cpu_to_le32(UINT_MAX);533 534out:535 mutex_unlock(&hdev->send_cpu_message_lock);536 537 hl_cpu_accessible_dma_pool_free(hdev, size, pkt);538 539 return rc;540}541 542int hl_fw_unmask_irq(struct hl_device *hdev, u16 event_type)543{544 struct cpucp_packet pkt;545 u64 result;546 int rc;547 548 memset(&pkt, 0, sizeof(pkt));549 550 pkt.ctl = cpu_to_le32(CPUCP_PACKET_UNMASK_RAZWI_IRQ <<551 CPUCP_PKT_CTL_OPCODE_SHIFT);552 pkt.value = cpu_to_le64(event_type);553 554 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),555 0, &result);556 557 if (rc)558 dev_err(hdev->dev, "failed to unmask event %d", event_type);559 560 return rc;561}562 563int hl_fw_unmask_irq_arr(struct hl_device *hdev, const u32 *irq_arr,564 size_t irq_arr_size)565{566 struct cpucp_unmask_irq_arr_packet *pkt;567 size_t total_pkt_size;568 u64 result;569 int rc;570 571 total_pkt_size = sizeof(struct cpucp_unmask_irq_arr_packet) +572 irq_arr_size;573 574 /* data should be aligned to 8 bytes in order to CPU-CP to copy it */575 total_pkt_size = (total_pkt_size + 0x7) & ~0x7;576 577 /* total_pkt_size is casted to u16 later on */578 if (total_pkt_size > USHRT_MAX) {579 dev_err(hdev->dev, "too many elements in IRQ array\n");580 return -EINVAL;581 }582 583 pkt = kzalloc(total_pkt_size, GFP_KERNEL);584 if (!pkt)585 return -ENOMEM;586 587 pkt->length = cpu_to_le32(irq_arr_size / sizeof(irq_arr[0]));588 memcpy(&pkt->irqs, irq_arr, irq_arr_size);589 590 pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_UNMASK_RAZWI_IRQ_ARRAY <<591 CPUCP_PKT_CTL_OPCODE_SHIFT);592 593 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) pkt,594 total_pkt_size, 0, &result);595 596 if (rc)597 dev_err(hdev->dev, "failed to unmask event array\n");598 599 kfree(pkt);600 601 return rc;602}603 604int hl_fw_test_cpu_queue(struct hl_device *hdev)605{606 struct cpucp_packet test_pkt = {};607 u64 result = 0;608 int rc;609 610 test_pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEST <<611 CPUCP_PKT_CTL_OPCODE_SHIFT);612 test_pkt.value = cpu_to_le64(CPUCP_PACKET_FENCE_VAL);613 614 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &test_pkt,615 sizeof(test_pkt), 0, &result);616 617 if (!rc) {618 if (result != CPUCP_PACKET_FENCE_VAL)619 dev_err(hdev->dev,620 "CPU queue test failed (%#08llx)\n", result);621 } else {622 dev_err(hdev->dev, "CPU queue test failed, error %d\n", rc);623 }624 625 return rc;626}627 628void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,629 dma_addr_t *dma_handle)630{631 u64 kernel_addr;632 633 kernel_addr = gen_pool_alloc(hdev->cpu_accessible_dma_pool, size);634 635 *dma_handle = hdev->cpu_accessible_dma_address +636 (kernel_addr - (u64) (uintptr_t) hdev->cpu_accessible_dma_mem);637 638 return (void *) (uintptr_t) kernel_addr;639}640 641void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,642 void *vaddr)643{644 gen_pool_free(hdev->cpu_accessible_dma_pool, (u64) (uintptr_t) vaddr,645 size);646}647 648int hl_fw_send_soft_reset(struct hl_device *hdev)649{650 struct cpucp_packet pkt;651 int rc;652 653 memset(&pkt, 0, sizeof(pkt));654 pkt.ctl = cpu_to_le32(CPUCP_PACKET_SOFT_RESET << CPUCP_PKT_CTL_OPCODE_SHIFT);655 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);656 if (rc)657 dev_err(hdev->dev, "failed to send soft-reset msg (err = %d)\n", rc);658 659 return rc;660}661 662int hl_fw_send_device_activity(struct hl_device *hdev, bool open)663{664 struct cpucp_packet pkt;665 int rc;666 667 memset(&pkt, 0, sizeof(pkt));668 pkt.ctl = cpu_to_le32(CPUCP_PACKET_ACTIVE_STATUS_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);669 pkt.value = cpu_to_le64(open);670 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);671 if (rc)672 dev_err(hdev->dev, "failed to send device activity msg(%u)\n", open);673 674 return rc;675}676 677int hl_fw_send_heartbeat(struct hl_device *hdev)678{679 struct cpucp_packet hb_pkt;680 u64 result = 0;681 int rc;682 683 memset(&hb_pkt, 0, sizeof(hb_pkt));684 hb_pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEST << CPUCP_PKT_CTL_OPCODE_SHIFT);685 hb_pkt.value = cpu_to_le64(CPUCP_PACKET_FENCE_VAL);686 687 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &hb_pkt, sizeof(hb_pkt), 0, &result);688 689 if ((rc) || (result != CPUCP_PACKET_FENCE_VAL))690 return -EIO;691 692 if (le32_to_cpu(hb_pkt.status_mask) &693 CPUCP_PKT_HB_STATUS_EQ_FAULT_MASK) {694 dev_warn(hdev->dev, "FW reported EQ fault during heartbeat\n");695 rc = -EIO;696 }697 698 hdev->heartbeat_debug_info.last_pq_heartbeat_ts = ktime_get_real_seconds();699 700 return rc;701}702 703static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, u32 sts_val)704{705 bool err_exists = false;706 707 if (!(err_val & CPU_BOOT_ERR0_ENABLED))708 return false;709 710 if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL)711 dev_err(hdev->dev, "Device boot error - DRAM initialization failed\n");712 713 if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED)714 dev_err(hdev->dev, "Device boot error - FIT image corrupted\n");715 716 if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL)717 dev_err(hdev->dev, "Device boot error - Thermal Sensor initialization failed\n");718 719 if (err_val & CPU_BOOT_ERR0_BMC_WAIT_SKIPPED) {720 if (hdev->bmc_enable) {721 dev_err(hdev->dev, "Device boot error - Skipped waiting for BMC\n");722 } else {723 dev_info(hdev->dev, "Device boot message - Skipped waiting for BMC\n");724 /* This is an info so we don't want it to disable the725 * device726 */727 err_val &= ~CPU_BOOT_ERR0_BMC_WAIT_SKIPPED;728 }729 }730 731 if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY)732 dev_err(hdev->dev, "Device boot error - Serdes data from BMC not available\n");733 734 if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL)735 dev_err(hdev->dev, "Device boot error - NIC F/W initialization failed\n");736 737 if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY)738 dev_err(hdev->dev, "Device boot warning - security not ready\n");739 740 if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL)741 dev_err(hdev->dev, "Device boot error - security failure\n");742 743 if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL)744 dev_err(hdev->dev, "Device boot error - eFuse failure\n");745 746 if (err_val & CPU_BOOT_ERR0_SEC_IMG_VER_FAIL)747 dev_err(hdev->dev, "Device boot error - Failed to load preboot secondary image\n");748 749 if (err_val & CPU_BOOT_ERR0_PLL_FAIL)750 dev_err(hdev->dev, "Device boot error - PLL failure\n");751 752 if (err_val & CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL)753 dev_err(hdev->dev, "Device boot error - Failed to set threshold for temperature sensor\n");754 755 if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) {756 /* Ignore this bit, don't prevent driver loading */757 dev_dbg(hdev->dev, "device unusable status is set\n");758 err_val &= ~CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL;759 }760 761 if (err_val & CPU_BOOT_ERR0_BINNING_FAIL)762 dev_err(hdev->dev, "Device boot error - binning failure\n");763 764 if (sts_val & CPU_BOOT_DEV_STS0_ENABLED)765 dev_dbg(hdev->dev, "Device status0 %#x\n", sts_val);766 767 if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED)768 dev_err(hdev->dev, "Device boot warning - Skipped DRAM initialization\n");769 770 if (err_val & CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL)771 dev_err(hdev->dev, "Device boot error - ARC memory scrub failed\n");772 773 /* All warnings should go here in order not to reach the unknown error validation */774 if (err_val & CPU_BOOT_ERR0_EEPROM_FAIL) {775 dev_err(hdev->dev, "Device boot error - EEPROM failure detected\n");776 err_exists = true;777 }778 779 if (err_val & CPU_BOOT_ERR0_PRI_IMG_VER_FAIL)780 dev_warn(hdev->dev, "Device boot warning - Failed to load preboot primary image\n");781 782 if (err_val & CPU_BOOT_ERR0_TPM_FAIL)783 dev_warn(hdev->dev, "Device boot warning - TPM failure\n");784 785 if (err_val & CPU_BOOT_ERR_FATAL_MASK)786 err_exists = true;787 788 /* return error only if it's in the predefined mask */789 if (err_exists && ((err_val & ~CPU_BOOT_ERR0_ENABLED) &790 lower_32_bits(hdev->boot_error_status_mask)))791 return true;792 793 return false;794}795 796/* placeholder for ERR1 as no errors defined there yet */797static bool fw_report_boot_dev1(struct hl_device *hdev, u32 err_val,798 u32 sts_val)799{800 /*801 * keep this variable to preserve the logic of the function.802 * this way it would require less modifications when error will be803 * added to DEV_ERR1804 */805 bool err_exists = false;806 807 if (!(err_val & CPU_BOOT_ERR1_ENABLED))808 return false;809 810 if (sts_val & CPU_BOOT_DEV_STS1_ENABLED)811 dev_dbg(hdev->dev, "Device status1 %#x\n", sts_val);812 813 if (!err_exists && (err_val & ~CPU_BOOT_ERR1_ENABLED)) {814 dev_err(hdev->dev,815 "Device boot error - unknown ERR1 error 0x%08x\n",816 err_val);817 err_exists = true;818 }819 820 /* return error only if it's in the predefined mask */821 if (err_exists && ((err_val & ~CPU_BOOT_ERR1_ENABLED) &822 upper_32_bits(hdev->boot_error_status_mask)))823 return true;824 825 return false;826}827 828static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg,829 u32 boot_err1_reg, u32 cpu_boot_dev_status0_reg,830 u32 cpu_boot_dev_status1_reg)831{832 u32 err_val, status_val;833 bool err_exists = false;834 835 /* Some of the firmware status codes are deprecated in newer f/w836 * versions. In those versions, the errors are reported837 * in different registers. Therefore, we need to check those838 * registers and print the exact errors. Moreover, there839 * may be multiple errors, so we need to report on each error840 * separately. Some of the error codes might indicate a state841 * that is not an error per-se, but it is an error in production842 * environment843 */844 err_val = RREG32(boot_err0_reg);845 status_val = RREG32(cpu_boot_dev_status0_reg);846 err_exists = fw_report_boot_dev0(hdev, err_val, status_val);847 848 err_val = RREG32(boot_err1_reg);849 status_val = RREG32(cpu_boot_dev_status1_reg);850 err_exists |= fw_report_boot_dev1(hdev, err_val, status_val);851 852 if (err_exists)853 return -EIO;854 855 return 0;856}857 858int hl_fw_cpucp_info_get(struct hl_device *hdev,859 u32 sts_boot_dev_sts0_reg,860 u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,861 u32 boot_err1_reg)862{863 struct asic_fixed_properties *prop = &hdev->asic_prop;864 struct cpucp_packet pkt = {};865 dma_addr_t cpucp_info_dma_addr;866 void *cpucp_info_cpu_addr;867 char *kernel_ver;868 u64 result;869 int rc;870 871 cpucp_info_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, sizeof(struct cpucp_info),872 &cpucp_info_dma_addr);873 if (!cpucp_info_cpu_addr) {874 dev_err(hdev->dev,875 "Failed to allocate DMA memory for CPU-CP info packet\n");876 return -ENOMEM;877 }878 879 memset(cpucp_info_cpu_addr, 0, sizeof(struct cpucp_info));880 881 pkt.ctl = cpu_to_le32(CPUCP_PACKET_INFO_GET <<882 CPUCP_PKT_CTL_OPCODE_SHIFT);883 pkt.addr = cpu_to_le64(cpucp_info_dma_addr);884 pkt.data_max_size = cpu_to_le32(sizeof(struct cpucp_info));885 886 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),887 HL_CPUCP_INFO_TIMEOUT_USEC, &result);888 if (rc) {889 dev_err(hdev->dev,890 "Failed to handle CPU-CP info pkt, error %d\n", rc);891 goto out;892 }893 894 rc = fw_read_errors(hdev, boot_err0_reg, boot_err1_reg,895 sts_boot_dev_sts0_reg, sts_boot_dev_sts1_reg);896 if (rc) {897 dev_err(hdev->dev, "Errors in device boot\n");898 goto out;899 }900 901 memcpy(&prop->cpucp_info, cpucp_info_cpu_addr,902 sizeof(prop->cpucp_info));903 904 rc = hl_build_hwmon_channel_info(hdev, prop->cpucp_info.sensors);905 if (rc) {906 dev_err(hdev->dev,907 "Failed to build hwmon channel info, error %d\n", rc);908 rc = -EFAULT;909 goto out;910 }911 912 kernel_ver = extract_fw_ver_from_str(prop->cpucp_info.kernel_version);913 if (kernel_ver) {914 dev_info(hdev->dev, "Linux version %s", kernel_ver);915 kfree(kernel_ver);916 }917 918 /* assume EQ code doesn't need to check eqe index */919 hdev->event_queue.check_eqe_index = false;920 921 /* Read FW application security bits again */922 if (prop->fw_cpu_boot_dev_sts0_valid) {923 prop->fw_app_cpu_boot_dev_sts0 = RREG32(sts_boot_dev_sts0_reg);924 if (prop->fw_app_cpu_boot_dev_sts0 &925 CPU_BOOT_DEV_STS0_EQ_INDEX_EN)926 hdev->event_queue.check_eqe_index = true;927 }928 929 if (prop->fw_cpu_boot_dev_sts1_valid)930 prop->fw_app_cpu_boot_dev_sts1 = RREG32(sts_boot_dev_sts1_reg);931 932out:933 hl_cpu_accessible_dma_pool_free(hdev, sizeof(struct cpucp_info), cpucp_info_cpu_addr);934 935 return rc;936}937 938static int hl_fw_send_msi_info_msg(struct hl_device *hdev)939{940 struct cpucp_array_data_packet *pkt;941 size_t total_pkt_size, data_size;942 u64 result = 0;943 int rc;944 945 /* skip sending this info for unsupported ASICs */946 if (!hdev->asic_funcs->get_msi_info)947 return 0;948 949 data_size = CPUCP_NUM_OF_MSI_TYPES * sizeof(u32);950 total_pkt_size = sizeof(struct cpucp_array_data_packet) + data_size;951 952 /* data should be aligned to 8 bytes in order to CPU-CP to copy it */953 total_pkt_size = (total_pkt_size + 0x7) & ~0x7;954 955 /* total_pkt_size is casted to u16 later on */956 if (total_pkt_size > USHRT_MAX) {957 dev_err(hdev->dev, "CPUCP array data is too big\n");958 return -EINVAL;959 }960 961 pkt = kzalloc(total_pkt_size, GFP_KERNEL);962 if (!pkt)963 return -ENOMEM;964 965 pkt->length = cpu_to_le32(CPUCP_NUM_OF_MSI_TYPES);966 967 memset((void *) &pkt->data, 0xFF, data_size);968 hdev->asic_funcs->get_msi_info(pkt->data);969 970 pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_MSI_INFO_SET <<971 CPUCP_PKT_CTL_OPCODE_SHIFT);972 973 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)pkt,974 total_pkt_size, 0, &result);975 976 /*977 * in case packet result is invalid it means that FW does not support978 * this feature and will use default/hard coded MSI values. no reason979 * to stop the boot980 */981 if (rc && result == cpucp_packet_invalid)982 rc = 0;983 984 if (rc)985 dev_err(hdev->dev, "failed to send CPUCP array data\n");986 987 kfree(pkt);988 989 return rc;990}991 992int hl_fw_cpucp_handshake(struct hl_device *hdev,993 u32 sts_boot_dev_sts0_reg,994 u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,995 u32 boot_err1_reg)996{997 int rc;998 999 rc = hl_fw_cpucp_info_get(hdev, sts_boot_dev_sts0_reg,1000 sts_boot_dev_sts1_reg, boot_err0_reg,1001 boot_err1_reg);1002 if (rc)1003 return rc;1004 1005 return hl_fw_send_msi_info_msg(hdev);1006}1007 1008int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)1009{1010 struct cpucp_packet pkt = {};1011 void *eeprom_info_cpu_addr;1012 dma_addr_t eeprom_info_dma_addr;1013 u64 result;1014 int rc;1015 1016 eeprom_info_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, max_size,1017 &eeprom_info_dma_addr);1018 if (!eeprom_info_cpu_addr) {1019 dev_err(hdev->dev,1020 "Failed to allocate DMA memory for CPU-CP EEPROM packet\n");1021 return -ENOMEM;1022 }1023 1024 memset(eeprom_info_cpu_addr, 0, max_size);1025 1026 pkt.ctl = cpu_to_le32(CPUCP_PACKET_EEPROM_DATA_GET <<1027 CPUCP_PKT_CTL_OPCODE_SHIFT);1028 pkt.addr = cpu_to_le64(eeprom_info_dma_addr);1029 pkt.data_max_size = cpu_to_le32(max_size);1030 1031 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1032 HL_CPUCP_EEPROM_TIMEOUT_USEC, &result);1033 if (rc) {1034 if (rc != -EAGAIN)1035 dev_err(hdev->dev,1036 "Failed to handle CPU-CP EEPROM packet, error %d\n", rc);1037 goto out;1038 }1039 1040 /* result contains the actual size */1041 memcpy(data, eeprom_info_cpu_addr, min((size_t)result, max_size));1042 1043out:1044 hl_cpu_accessible_dma_pool_free(hdev, max_size, eeprom_info_cpu_addr);1045 1046 return rc;1047}1048 1049int hl_fw_get_monitor_dump(struct hl_device *hdev, void *data)1050{1051 struct cpucp_monitor_dump *mon_dump_cpu_addr;1052 dma_addr_t mon_dump_dma_addr;1053 struct cpucp_packet pkt = {};1054 size_t data_size;1055 __le32 *src_ptr;1056 u32 *dst_ptr;1057 u64 result;1058 int i, rc;1059 1060 data_size = sizeof(struct cpucp_monitor_dump);1061 mon_dump_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, data_size, &mon_dump_dma_addr);1062 if (!mon_dump_cpu_addr) {1063 dev_err(hdev->dev,1064 "Failed to allocate DMA memory for CPU-CP monitor-dump packet\n");1065 return -ENOMEM;1066 }1067 1068 memset(mon_dump_cpu_addr, 0, data_size);1069 1070 pkt.ctl = cpu_to_le32(CPUCP_PACKET_MONITOR_DUMP_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);1071 pkt.addr = cpu_to_le64(mon_dump_dma_addr);1072 pkt.data_max_size = cpu_to_le32(data_size);1073 1074 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1075 HL_CPUCP_MON_DUMP_TIMEOUT_USEC, &result);1076 if (rc) {1077 if (rc != -EAGAIN)1078 dev_err(hdev->dev,1079 "Failed to handle CPU-CP monitor-dump packet, error %d\n", rc);1080 goto out;1081 }1082 1083 /* result contains the actual size */1084 src_ptr = (__le32 *) mon_dump_cpu_addr;1085 dst_ptr = data;1086 for (i = 0; i < (data_size / sizeof(u32)); i++) {1087 *dst_ptr = le32_to_cpu(*src_ptr);1088 src_ptr++;1089 dst_ptr++;1090 }1091 1092out:1093 hl_cpu_accessible_dma_pool_free(hdev, data_size, mon_dump_cpu_addr);1094 1095 return rc;1096}1097 1098int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev,1099 struct hl_info_pci_counters *counters)1100{1101 struct cpucp_packet pkt = {};1102 u64 result;1103 int rc;1104 1105 pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_THROUGHPUT_GET <<1106 CPUCP_PKT_CTL_OPCODE_SHIFT);1107 1108 /* Fetch PCI rx counter */1109 pkt.index = cpu_to_le32(cpucp_pcie_throughput_rx);1110 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1111 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1112 if (rc) {1113 if (rc != -EAGAIN)1114 dev_err(hdev->dev,1115 "Failed to handle CPU-CP PCI info pkt, error %d\n", rc);1116 return rc;1117 }1118 counters->rx_throughput = result;1119 1120 memset(&pkt, 0, sizeof(pkt));1121 pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_THROUGHPUT_GET <<1122 CPUCP_PKT_CTL_OPCODE_SHIFT);1123 1124 /* Fetch PCI tx counter */1125 pkt.index = cpu_to_le32(cpucp_pcie_throughput_tx);1126 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1127 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1128 if (rc) {1129 if (rc != -EAGAIN)1130 dev_err(hdev->dev,1131 "Failed to handle CPU-CP PCI info pkt, error %d\n", rc);1132 return rc;1133 }1134 counters->tx_throughput = result;1135 1136 /* Fetch PCI replay counter */1137 memset(&pkt, 0, sizeof(pkt));1138 pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_REPLAY_CNT_GET <<1139 CPUCP_PKT_CTL_OPCODE_SHIFT);1140 1141 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1142 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1143 if (rc) {1144 if (rc != -EAGAIN)1145 dev_err(hdev->dev,1146 "Failed to handle CPU-CP PCI info pkt, error %d\n", rc);1147 return rc;1148 }1149 counters->replay_cnt = (u32) result;1150 1151 return rc;1152}1153 1154int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy)1155{1156 struct cpucp_packet pkt = {};1157 u64 result;1158 int rc;1159 1160 pkt.ctl = cpu_to_le32(CPUCP_PACKET_TOTAL_ENERGY_GET <<1161 CPUCP_PKT_CTL_OPCODE_SHIFT);1162 1163 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1164 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1165 if (rc) {1166 if (rc != -EAGAIN)1167 dev_err(hdev->dev,1168 "Failed to handle CpuCP total energy pkt, error %d\n", rc);1169 return rc;1170 }1171 1172 *total_energy = result;1173 1174 return rc;1175}1176 1177int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index,1178 enum pll_index *pll_index)1179{1180 struct asic_fixed_properties *prop = &hdev->asic_prop;1181 u8 pll_byte, pll_bit_off;1182 bool dynamic_pll;1183 int fw_pll_idx;1184 1185 dynamic_pll = !!(prop->fw_app_cpu_boot_dev_sts0 &1186 CPU_BOOT_DEV_STS0_DYN_PLL_EN);1187 1188 if (!dynamic_pll) {1189 /*1190 * in case we are working with legacy FW (each asic has unique1191 * PLL numbering) use the driver based index as they are1192 * aligned with fw legacy numbering1193 */1194 *pll_index = input_pll_index;1195 return 0;1196 }1197 1198 /* retrieve a FW compatible PLL index based on1199 * ASIC specific user request1200 */1201 fw_pll_idx = hdev->asic_funcs->map_pll_idx_to_fw_idx(input_pll_index);1202 if (fw_pll_idx < 0) {1203 dev_err(hdev->dev, "Invalid PLL index (%u) error %d\n",1204 input_pll_index, fw_pll_idx);1205 return -EINVAL;1206 }1207 1208 /* PLL map is a u8 array */1209 pll_byte = prop->cpucp_info.pll_map[fw_pll_idx >> 3];1210 pll_bit_off = fw_pll_idx & 0x7;1211 1212 if (!(pll_byte & BIT(pll_bit_off))) {1213 dev_err(hdev->dev, "PLL index %d is not supported\n",1214 fw_pll_idx);1215 return -EINVAL;1216 }1217 1218 *pll_index = fw_pll_idx;1219 1220 return 0;1221}1222 1223int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index,1224 u16 *pll_freq_arr)1225{1226 struct cpucp_packet pkt;1227 enum pll_index used_pll_idx;1228 u64 result;1229 int rc;1230 1231 rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);1232 if (rc)1233 return rc;1234 1235 memset(&pkt, 0, sizeof(pkt));1236 1237 pkt.ctl = cpu_to_le32(CPUCP_PACKET_PLL_INFO_GET <<1238 CPUCP_PKT_CTL_OPCODE_SHIFT);1239 pkt.pll_type = __cpu_to_le16((u16)used_pll_idx);1240 1241 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1242 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1243 if (rc) {1244 if (rc != -EAGAIN)1245 dev_err(hdev->dev, "Failed to read PLL info, error %d\n", rc);1246 return rc;1247 }1248 1249 pll_freq_arr[0] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT0_MASK, result);1250 pll_freq_arr[1] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT1_MASK, result);1251 pll_freq_arr[2] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT2_MASK, result);1252 pll_freq_arr[3] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT3_MASK, result);1253 1254 return 0;1255}1256 1257int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power)1258{1259 struct cpucp_packet pkt;1260 u64 result;1261 int rc;1262 1263 memset(&pkt, 0, sizeof(pkt));1264 1265 pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET <<1266 CPUCP_PKT_CTL_OPCODE_SHIFT);1267 pkt.type = cpu_to_le16(CPUCP_POWER_INPUT);1268 1269 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1270 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1271 if (rc) {1272 if (rc != -EAGAIN)1273 dev_err(hdev->dev, "Failed to read power, error %d\n", rc);1274 return rc;1275 }1276 1277 *power = result;1278 1279 return rc;1280}1281 1282int hl_fw_dram_replaced_row_get(struct hl_device *hdev,1283 struct cpucp_hbm_row_info *info)1284{1285 struct cpucp_hbm_row_info *cpucp_repl_rows_info_cpu_addr;1286 dma_addr_t cpucp_repl_rows_info_dma_addr;1287 struct cpucp_packet pkt = {};1288 u64 result;1289 int rc;1290 1291 cpucp_repl_rows_info_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev,1292 sizeof(struct cpucp_hbm_row_info),1293 &cpucp_repl_rows_info_dma_addr);1294 if (!cpucp_repl_rows_info_cpu_addr) {1295 dev_err(hdev->dev,1296 "Failed to allocate DMA memory for CPU-CP replaced rows info packet\n");1297 return -ENOMEM;1298 }1299 1300 memset(cpucp_repl_rows_info_cpu_addr, 0, sizeof(struct cpucp_hbm_row_info));1301 1302 pkt.ctl = cpu_to_le32(CPUCP_PACKET_HBM_REPLACED_ROWS_INFO_GET <<1303 CPUCP_PKT_CTL_OPCODE_SHIFT);1304 pkt.addr = cpu_to_le64(cpucp_repl_rows_info_dma_addr);1305 pkt.data_max_size = cpu_to_le32(sizeof(struct cpucp_hbm_row_info));1306 1307 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1308 HL_CPUCP_INFO_TIMEOUT_USEC, &result);1309 if (rc) {1310 if (rc != -EAGAIN)1311 dev_err(hdev->dev,1312 "Failed to handle CPU-CP replaced rows info pkt, error %d\n", rc);1313 goto out;1314 }1315 1316 memcpy(info, cpucp_repl_rows_info_cpu_addr, sizeof(*info));1317 1318out:1319 hl_cpu_accessible_dma_pool_free(hdev, sizeof(struct cpucp_hbm_row_info),1320 cpucp_repl_rows_info_cpu_addr);1321 1322 return rc;1323}1324 1325int hl_fw_dram_pending_row_get(struct hl_device *hdev, u32 *pend_rows_num)1326{1327 struct cpucp_packet pkt;1328 u64 result;1329 int rc;1330 1331 memset(&pkt, 0, sizeof(pkt));1332 1333 pkt.ctl = cpu_to_le32(CPUCP_PACKET_HBM_PENDING_ROWS_STATUS << CPUCP_PKT_CTL_OPCODE_SHIFT);1334 1335 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);1336 if (rc) {1337 if (rc != -EAGAIN)1338 dev_err(hdev->dev,1339 "Failed to handle CPU-CP pending rows info pkt, error %d\n", rc);1340 goto out;1341 }1342 1343 *pend_rows_num = (u32) result;1344out:1345 return rc;1346}1347 1348int hl_fw_cpucp_engine_core_asid_set(struct hl_device *hdev, u32 asid)1349{1350 struct cpucp_packet pkt;1351 int rc;1352 1353 memset(&pkt, 0, sizeof(pkt));1354 1355 pkt.ctl = cpu_to_le32(CPUCP_PACKET_ENGINE_CORE_ASID_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);1356 pkt.value = cpu_to_le64(asid);1357 1358 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),1359 HL_CPUCP_INFO_TIMEOUT_USEC, NULL);1360 if (rc)1361 dev_err(hdev->dev,1362 "Failed on ASID configuration request for engine core, error %d\n",1363 rc);1364 1365 return rc;1366}1367 1368void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev)1369{1370 struct static_fw_load_mgr *static_loader =1371 &hdev->fw_loader.static_loader;1372 int rc;1373 1374 if (hdev->asic_prop.dynamic_fw_load) {1375 rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader,1376 COMMS_RST_DEV, 0, false,1377 hdev->fw_loader.cpu_timeout);1378 if (rc)1379 dev_err(hdev->dev, "Failed sending COMMS_RST_DEV\n");1380 } else {1381 WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_RST_DEV);1382 }1383}1384 1385void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev)1386{1387 struct fw_load_mgr *fw_loader = &hdev->fw_loader;1388 u32 status, cpu_boot_status_reg, cpu_timeout;1389 struct static_fw_load_mgr *static_loader;1390 struct pre_fw_load_props *pre_fw_load;1391 int rc;1392 1393 if (hdev->device_cpu_is_halted)1394 return;1395 1396 /* Stop device CPU to make sure nothing bad happens */1397 if (hdev->asic_prop.dynamic_fw_load) {1398 pre_fw_load = &fw_loader->pre_fw_load;1399 cpu_timeout = fw_loader->cpu_timeout;1400 cpu_boot_status_reg = pre_fw_load->cpu_boot_status_reg;1401 1402 rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader,1403 COMMS_GOTO_WFE, 0, false, cpu_timeout);1404 if (rc) {1405 dev_err(hdev->dev, "Failed sending COMMS_GOTO_WFE\n");1406 } else {1407 rc = hl_poll_timeout(1408 hdev,1409 cpu_boot_status_reg,1410 status,1411 status == CPU_BOOT_STATUS_IN_WFE,1412 hdev->fw_poll_interval_usec,1413 cpu_timeout);1414 if (rc)1415 dev_err(hdev->dev, "Current status=%u. Timed-out updating to WFE\n",1416 status);1417 }1418 } else {1419 static_loader = &hdev->fw_loader.static_loader;1420 WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_GOTO_WFE);1421 msleep(static_loader->cpu_reset_wait_msec);1422 1423 /* Must clear this register in order to prevent preboot1424 * from reading WFE after reboot1425 */1426 WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_NA);1427 }1428 1429 hdev->device_cpu_is_halted = true;1430}1431 1432static void detect_cpu_boot_status(struct hl_device *hdev, u32 status)1433{1434 /* Some of the status codes below are deprecated in newer f/w1435 * versions but we keep them here for backward compatibility1436 */1437 switch (status) {1438 case CPU_BOOT_STATUS_NA:1439 dev_err(hdev->dev,1440 "Device boot progress - BTL/ROM did NOT run\n");1441 break;1442 case CPU_BOOT_STATUS_IN_WFE:1443 dev_err(hdev->dev,1444 "Device boot progress - Stuck inside WFE loop\n");1445 break;1446 case CPU_BOOT_STATUS_IN_BTL:1447 dev_err(hdev->dev,1448 "Device boot progress - Stuck in BTL\n");1449 break;1450 case CPU_BOOT_STATUS_IN_PREBOOT:1451 dev_err(hdev->dev,1452 "Device boot progress - Stuck in Preboot\n");1453 break;1454 case CPU_BOOT_STATUS_IN_SPL:1455 dev_err(hdev->dev,1456 "Device boot progress - Stuck in SPL\n");1457 break;1458 case CPU_BOOT_STATUS_IN_UBOOT:1459 dev_err(hdev->dev,1460 "Device boot progress - Stuck in u-boot\n");1461 break;1462 case CPU_BOOT_STATUS_DRAM_INIT_FAIL:1463 dev_err(hdev->dev,1464 "Device boot progress - DRAM initialization failed\n");1465 break;1466 case CPU_BOOT_STATUS_UBOOT_NOT_READY:1467 dev_err(hdev->dev,1468 "Device boot progress - Cannot boot\n");1469 break;1470 case CPU_BOOT_STATUS_TS_INIT_FAIL:1471 dev_err(hdev->dev,1472 "Device boot progress - Thermal Sensor initialization failed\n");1473 break;1474 case CPU_BOOT_STATUS_SECURITY_READY:1475 dev_err(hdev->dev,1476 "Device boot progress - Stuck in preboot after security initialization\n");1477 break;1478 case CPU_BOOT_STATUS_FW_SHUTDOWN_PREP:1479 dev_err(hdev->dev,1480 "Device boot progress - Stuck in preparation for shutdown\n");1481 break;1482 default:1483 dev_err(hdev->dev,1484 "Device boot progress - Invalid or unexpected status code %d\n", status);1485 break;1486 }1487}1488 1489int hl_fw_wait_preboot_ready(struct hl_device *hdev)1490{1491 struct pre_fw_load_props *pre_fw_load = &hdev->fw_loader.pre_fw_load;1492 u32 status = 0, timeout;1493 int rc, tries = 1, fw_err = 0;1494 bool preboot_still_runs;1495 1496 /* Need to check two possible scenarios:1497 *1498 * CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT - for newer firmwares where1499 * the preboot is waiting for the boot fit1500 *1501 * All other status values - for older firmwares where the uboot was1502 * loaded from the FLASH1503 */1504 timeout = pre_fw_load->wait_for_preboot_timeout;1505retry:1506 rc = hl_poll_timeout(1507 hdev,1508 pre_fw_load->cpu_boot_status_reg,1509 status,1510 (status == CPU_BOOT_STATUS_NIC_FW_RDY) ||1511 (status == CPU_BOOT_STATUS_READY_TO_BOOT) ||1512 (status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT),1513 hdev->fw_poll_interval_usec,1514 timeout);1515 /*1516 * if F/W reports "security-ready" it means preboot might take longer.1517 * If the field 'wait_for_preboot_extended_timeout' is non 0 we wait again1518 * with that timeout1519 */1520 preboot_still_runs = (status == CPU_BOOT_STATUS_SECURITY_READY ||1521 status == CPU_BOOT_STATUS_IN_PREBOOT ||1522 status == CPU_BOOT_STATUS_FW_SHUTDOWN_PREP ||1523 status == CPU_BOOT_STATUS_DRAM_RDY);1524 1525 if (rc && tries && preboot_still_runs) {1526 tries--;1527 if (pre_fw_load->wait_for_preboot_extended_timeout) {1528 timeout = pre_fw_load->wait_for_preboot_extended_timeout;1529 goto retry;1530 }1531 }1532 1533 /* If we read all FF, then something is totally wrong, no point1534 * of reading specific errors1535 */1536 if (status != -1)1537 fw_err = fw_read_errors(hdev, pre_fw_load->boot_err0_reg,1538 pre_fw_load->boot_err1_reg,1539 pre_fw_load->sts_boot_dev_sts0_reg,1540 pre_fw_load->sts_boot_dev_sts1_reg);1541 if (rc || fw_err) {1542 detect_cpu_boot_status(hdev, status);1543 dev_err(hdev->dev, "CPU boot %s (status = %d)\n",1544 fw_err ? "failed due to an error" : "ready timeout", status);1545 return -EIO;1546 }1547 1548 hdev->fw_loader.fw_comp_loaded |= FW_TYPE_PREBOOT_CPU;1549 1550 return 0;1551}1552 1553static int hl_fw_read_preboot_caps(struct hl_device *hdev)1554{1555 struct pre_fw_load_props *pre_fw_load;1556 struct asic_fixed_properties *prop;1557 u32 reg_val;1558 int rc;1559 1560 prop = &hdev->asic_prop;1561 pre_fw_load = &hdev->fw_loader.pre_fw_load;1562 1563 rc = hl_fw_wait_preboot_ready(hdev);1564 if (rc)1565 return rc;1566 1567 /*1568 * the registers DEV_STS* contain FW capabilities/features.1569 * We can rely on this registers only if bit CPU_BOOT_DEV_STS*_ENABLED1570 * is set.1571 * In the first read of this register we store the value of this1572 * register ONLY if the register is enabled (which will be propagated1573 * to next stages) and also mark the register as valid.1574 * In case it is not enabled the stored value will be left 0- all1575 * caps/features are off1576 */1577 reg_val = RREG32(pre_fw_load->sts_boot_dev_sts0_reg);1578 if (reg_val & CPU_BOOT_DEV_STS0_ENABLED) {1579 prop->fw_cpu_boot_dev_sts0_valid = true;1580 prop->fw_preboot_cpu_boot_dev_sts0 = reg_val;1581 }1582 1583 reg_val = RREG32(pre_fw_load->sts_boot_dev_sts1_reg);1584 if (reg_val & CPU_BOOT_DEV_STS1_ENABLED) {1585 prop->fw_cpu_boot_dev_sts1_valid = true;1586 prop->fw_preboot_cpu_boot_dev_sts1 = reg_val;1587 }1588 1589 prop->dynamic_fw_load = !!(prop->fw_preboot_cpu_boot_dev_sts0 &1590 CPU_BOOT_DEV_STS0_FW_LD_COM_EN);1591 1592 /* initialize FW loader once we know what load protocol is used */1593 hdev->asic_funcs->init_firmware_loader(hdev);1594 1595 dev_dbg(hdev->dev, "Attempting %s FW load\n",1596 prop->dynamic_fw_load ? "dynamic" : "legacy");1597 return 0;1598}1599 1600static int hl_fw_static_read_device_fw_version(struct hl_device *hdev,1601 enum hl_fw_component fwc)1602{1603 struct asic_fixed_properties *prop = &hdev->asic_prop;1604 struct fw_load_mgr *fw_loader = &hdev->fw_loader;1605 struct static_fw_load_mgr *static_loader;1606 char *dest, *boot_ver, *preboot_ver;1607 u32 ver_off, limit;1608 const char *name;1609 char btl_ver[32];1610 1611 static_loader = &hdev->fw_loader.static_loader;1612 1613 switch (fwc) {1614 case FW_COMP_BOOT_FIT:1615 ver_off = RREG32(static_loader->boot_fit_version_offset_reg);1616 dest = prop->uboot_ver;1617 name = "Boot-fit";1618 limit = static_loader->boot_fit_version_max_off;1619 break;1620 case FW_COMP_PREBOOT:1621 ver_off = RREG32(static_loader->preboot_version_offset_reg);1622 dest = prop->preboot_ver;1623 name = "Preboot";1624 limit = static_loader->preboot_version_max_off;1625 break;1626 default:1627 dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);1628 return -EIO;1629 }1630 1631 ver_off &= static_loader->sram_offset_mask;1632 1633 if (ver_off < limit) {1634 memcpy_fromio(dest,1635 hdev->pcie_bar[fw_loader->sram_bar_id] + ver_off,1636 VERSION_MAX_LEN);1637 } else {1638 dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n",1639 name, ver_off);1640 strscpy(dest, "unavailable", VERSION_MAX_LEN);1641 return -EIO;1642 }1643 1644 if (fwc == FW_COMP_BOOT_FIT) {1645 boot_ver = extract_fw_ver_from_str(prop->uboot_ver);1646 if (boot_ver) {1647 dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);1648 kfree(boot_ver);1649 }1650 } else if (fwc == FW_COMP_PREBOOT) {1651 preboot_ver = strnstr(prop->preboot_ver, "Preboot",1652 VERSION_MAX_LEN);1653 if (preboot_ver && preboot_ver != prop->preboot_ver) {1654 strscpy(btl_ver, prop->preboot_ver,1655 min((int) (preboot_ver - prop->preboot_ver),1656 31));1657 dev_info(hdev->dev, "%s\n", btl_ver);1658 }1659 1660 preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);1661 if (preboot_ver) {1662 dev_info(hdev->dev, "preboot version %s\n",1663 preboot_ver);1664 kfree(preboot_ver);1665 }1666 }1667 1668 return 0;1669}1670 1671/**1672 * hl_fw_preboot_update_state - update internal data structures during1673 * handshake with preboot1674 *1675 *1676 * @hdev: pointer to the habanalabs device structure1677 *1678 * @return 0 on success, otherwise non-zero error code1679 */1680static void hl_fw_preboot_update_state(struct hl_device *hdev)1681{1682 struct asic_fixed_properties *prop = &hdev->asic_prop;1683 u32 cpu_boot_dev_sts0, cpu_boot_dev_sts1;1684 1685 cpu_boot_dev_sts0 = prop->fw_preboot_cpu_boot_dev_sts0;1686 cpu_boot_dev_sts1 = prop->fw_preboot_cpu_boot_dev_sts1;1687 1688 /* We read boot_dev_sts registers multiple times during boot:1689 * 1. preboot - a. Check whether the security status bits are valid1690 * b. Check whether fw security is enabled1691 * c. Check whether hard reset is done by preboot1692 * 2. boot cpu - a. Fetch boot cpu security status1693 * b. Check whether hard reset is done by boot cpu1694 * 3. FW application - a. Fetch fw application security status1695 * b. Check whether hard reset is done by fw app1696 */1697 prop->hard_reset_done_by_fw = !!(cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);1698 1699 prop->fw_security_enabled = !!(cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_SECURITY_EN);1700 1701 dev_dbg(hdev->dev, "Firmware preboot boot device status0 %#x\n",1702 cpu_boot_dev_sts0);1703 1704 dev_dbg(hdev->dev, "Firmware preboot boot device status1 %#x\n",1705 cpu_boot_dev_sts1);1706 1707 dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n",1708 prop->hard_reset_done_by_fw ? "enabled" : "disabled");1709 1710 dev_dbg(hdev->dev, "firmware-level security is %s\n",1711 prop->fw_security_enabled ? "enabled" : "disabled");1712 1713 dev_dbg(hdev->dev, "GIC controller is %s\n",1714 prop->gic_interrupts_enable ? "enabled" : "disabled");1715}1716 1717static int hl_fw_static_read_preboot_status(struct hl_device *hdev)1718{1719 int rc;1720 1721 rc = hl_fw_static_read_device_fw_version(hdev, FW_COMP_PREBOOT);1722 if (rc)1723 return rc;1724 1725 return 0;1726}1727 1728int hl_fw_read_preboot_status(struct hl_device *hdev)1729{1730 int rc;1731 1732 if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU))1733 return 0;1734 1735 /* get FW pre-load parameters */1736 hdev->asic_funcs->init_firmware_preload_params(hdev);1737 1738 /*1739 * In order to determine boot method (static VS dynamic) we need to1740 * read the boot caps register1741 */1742 rc = hl_fw_read_preboot_caps(hdev);1743 if (rc)1744 return rc;1745 1746 hl_fw_preboot_update_state(hdev);1747 1748 /* no need to read preboot status in dynamic load */1749 if (hdev->asic_prop.dynamic_fw_load)1750 return 0;1751 1752 return hl_fw_static_read_preboot_status(hdev);1753}1754 1755/* associate string with COMM status */1756static char *hl_dynamic_fw_status_str[COMMS_STS_INVLD_LAST] = {1757 [COMMS_STS_NOOP] = "NOOP",1758 [COMMS_STS_ACK] = "ACK",1759 [COMMS_STS_OK] = "OK",1760 [COMMS_STS_ERR] = "ERR",1761 [COMMS_STS_VALID_ERR] = "VALID_ERR",1762 [COMMS_STS_TIMEOUT_ERR] = "TIMEOUT_ERR",1763};1764 1765/**1766 * hl_fw_dynamic_report_error_status - report error status1767 *1768 * @hdev: pointer to the habanalabs device structure1769 * @status: value of FW status register1770 * @expected_status: the expected status1771 */1772static void hl_fw_dynamic_report_error_status(struct hl_device *hdev,1773 u32 status,1774 enum comms_sts expected_status)1775{1776 enum comms_sts comm_status =1777 FIELD_GET(COMMS_STATUS_STATUS_MASK, status);1778 1779 if (comm_status < COMMS_STS_INVLD_LAST)1780 dev_err(hdev->dev, "Device status %s, expected status: %s\n",1781 hl_dynamic_fw_status_str[comm_status],1782 hl_dynamic_fw_status_str[expected_status]);1783 else1784 dev_err(hdev->dev, "Device status unknown %d, expected status: %s\n",1785 comm_status,1786 hl_dynamic_fw_status_str[expected_status]);1787}1788 1789/**1790 * hl_fw_dynamic_send_cmd - send LKD to FW cmd1791 *1792 * @hdev: pointer to the habanalabs device structure1793 * @fw_loader: managing structure for loading device's FW1794 * @cmd: LKD to FW cmd code1795 * @size: size of next FW component to be loaded (0 if not necessary)1796 *1797 * LDK to FW exact command layout is defined at struct comms_command.1798 * note: the size argument is used only when the next FW component should be1799 * loaded, otherwise it shall be 0. the size is used by the FW in later1800 * protocol stages and when sending only indicating the amount of memory1801 * to be allocated by the FW to receive the next boot component.1802 */1803static void hl_fw_dynamic_send_cmd(struct hl_device *hdev,1804 struct fw_load_mgr *fw_loader,1805 enum comms_cmd cmd, unsigned int size)1806{1807 struct cpu_dyn_regs *dyn_regs;1808 u32 val;1809 1810 dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;1811 1812 val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd);1813 val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size);1814 1815 trace_habanalabs_comms_send_cmd(&hdev->pdev->dev, comms_cmd_str_arr[cmd]);1816 WREG32(le32_to_cpu(dyn_regs->kmd_msg_to_cpu), val);1817}1818 1819/**1820 * hl_fw_dynamic_extract_fw_response - update the FW response1821 *1822 * @hdev: pointer to the habanalabs device structure1823 * @fw_loader: managing structure for loading device's FW1824 * @response: FW response1825 * @status: the status read from CPU status register1826 *1827 * @return 0 on success, otherwise non-zero error code1828 */1829static int hl_fw_dynamic_extract_fw_response(struct hl_device *hdev,1830 struct fw_load_mgr *fw_loader,1831 struct fw_response *response,1832 u32 status)1833{1834 response->status = FIELD_GET(COMMS_STATUS_STATUS_MASK, status);1835 response->ram_offset = FIELD_GET(COMMS_STATUS_OFFSET_MASK, status) <<1836 COMMS_STATUS_OFFSET_ALIGN_SHIFT;1837 response->ram_type = FIELD_GET(COMMS_STATUS_RAM_TYPE_MASK, status);1838 1839 if ((response->ram_type != COMMS_SRAM) &&1840 (response->ram_type != COMMS_DRAM)) {1841 dev_err(hdev->dev, "FW status: invalid RAM type %u\n",1842 response->ram_type);1843 return -EIO;1844 }1845 1846 return 0;1847}1848 1849/**1850 * hl_fw_dynamic_wait_for_status - wait for status in dynamic FW load1851 *1852 * @hdev: pointer to the habanalabs device structure1853 * @fw_loader: managing structure for loading device's FW1854 * @expected_status: expected status to wait for1855 * @timeout: timeout for status wait1856 *1857 * @return 0 on success, otherwise non-zero error code1858 *1859 * waiting for status from FW include polling the FW status register until1860 * expected status is received or timeout occurs (whatever occurs first).1861 */1862static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev,1863 struct fw_load_mgr *fw_loader,1864 enum comms_sts expected_status,1865 u32 timeout)1866{1867 struct cpu_dyn_regs *dyn_regs;1868 u32 status;1869 int rc;1870 1871 dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;1872 1873 trace_habanalabs_comms_wait_status(&hdev->pdev->dev, comms_sts_str_arr[expected_status]);1874 1875 /* Wait for expected status */1876 rc = hl_poll_timeout(1877 hdev,1878 le32_to_cpu(dyn_regs->cpu_cmd_status_to_host),1879 status,1880 FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status,1881 hdev->fw_comms_poll_interval_usec,1882 timeout);1883 1884 if (rc) {1885 hl_fw_dynamic_report_error_status(hdev, status,1886 expected_status);1887 return -EIO;1888 }1889 1890 trace_habanalabs_comms_wait_status_done(&hdev->pdev->dev,1891 comms_sts_str_arr[expected_status]);1892 1893 /*1894 * skip storing FW response for NOOP to preserve the actual desired1895 * FW status1896 */1897 if (expected_status == COMMS_STS_NOOP)1898 return 0;1899 1900 rc = hl_fw_dynamic_extract_fw_response(hdev, fw_loader,1901 &fw_loader->dynamic_loader.response,1902 status);1903 return rc;1904}1905 1906/**1907 * hl_fw_dynamic_send_clear_cmd - send clear command to FW1908 *1909 * @hdev: pointer to the habanalabs device structure1910 * @fw_loader: managing structure for loading device's FW1911 *1912 * @return 0 on success, otherwise non-zero error code1913 *1914 * after command cycle between LKD to FW CPU (i.e. LKD got an expected status1915 * from FW) we need to clear the CPU status register in order to avoid garbage1916 * between command cycles.1917 * This is done by sending clear command and polling the CPU to LKD status1918 * register to hold the status NOOP1919 */1920static int hl_fw_dynamic_send_clear_cmd(struct hl_device *hdev,1921 struct fw_load_mgr *fw_loader)1922{1923 hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_CLR_STS, 0);1924 1925 return hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_NOOP,1926 fw_loader->cpu_timeout);1927}1928 1929/**1930 * hl_fw_dynamic_send_protocol_cmd - send LKD to FW cmd and wait for ACK1931 *1932 * @hdev: pointer to the habanalabs device structure1933 * @fw_loader: managing structure for loading device's FW1934 * @cmd: LKD to FW cmd code1935 * @size: size of next FW component to be loaded (0 if not necessary)1936 * @wait_ok: if true also wait for OK response from FW1937 * @timeout: timeout for status wait1938 *1939 * @return 0 on success, otherwise non-zero error code1940 *1941 * brief:1942 * when sending protocol command we have the following steps:1943 * - send clear (clear command and verify clear status register)1944 * - send the actual protocol command1945 * - wait for ACK on the protocol command1946 * - send clear1947 * - send NOOP1948 * if, in addition, the specific protocol command should wait for OK then:1949 * - wait for OK1950 * - send clear1951 * - send NOOP1952 *1953 * NOTES:1954 * send clear: this is necessary in order to clear the status register to avoid1955 * leftovers between command1956 * NOOP command: necessary to avoid loop on the clear command by the FW1957 */1958int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,1959 struct fw_load_mgr *fw_loader,1960 enum comms_cmd cmd, unsigned int size,1961 bool wait_ok, u32 timeout)1962{1963 int rc;1964 1965 trace_habanalabs_comms_protocol_cmd(&hdev->pdev->dev, comms_cmd_str_arr[cmd]);1966 1967 /* first send clear command to clean former commands */1968 rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);1969 if (rc)1970 return rc;1971 1972 /* send the actual command */1973 hl_fw_dynamic_send_cmd(hdev, fw_loader, cmd, size);1974 1975 /* wait for ACK for the command */1976 rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_ACK,1977 timeout);1978 if (rc)1979 return rc;1980 1981 /* clear command to prepare for NOOP command */1982 rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);1983 if (rc)1984 return rc;1985 1986 /* send the actual NOOP command */1987 hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0);1988 1989 if (!wait_ok)1990 return 0;1991 1992 rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_OK,1993 timeout);1994 if (rc)1995 return rc;1996 1997 /* clear command to prepare for NOOP command */1998 rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);1999 if (rc)2000 return rc;2001 2002 /* send the actual NOOP command */2003 hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0);2004 2005 return 0;2006}2007 2008/**2009 * hl_fw_compat_crc32 - CRC compatible with FW2010 *2011 * @data: pointer to the data2012 * @size: size of the data2013 *2014 * @return the CRC32 result2015 *2016 * NOTE: kernel's CRC32 differs from standard CRC32 calculation.2017 * in order to be aligned we need to flip the bits of both the input2018 * initial CRC and kernel's CRC32 result.2019 * in addition both sides use initial CRC of 0,2020 */2021static u32 hl_fw_compat_crc32(u8 *data, size_t size)2022{2023 return ~crc32_le(~((u32)0), data, size);2024}2025 2026/**2027 * hl_fw_dynamic_validate_memory_bound - validate memory bounds for memory2028 * transfer (image or descriptor) between2029 * host and FW2030 *2031 * @hdev: pointer to the habanalabs device structure2032 * @addr: device address of memory transfer2033 * @size: memory transfer size2034 * @region: PCI memory region2035 *2036 * @return 0 on success, otherwise non-zero error code2037 */2038static int hl_fw_dynamic_validate_memory_bound(struct hl_device *hdev,2039 u64 addr, size_t size,2040 struct pci_mem_region *region)2041{2042 u64 end_addr;2043 2044 /* now make sure that the memory transfer is within region's bounds */2045 end_addr = addr + size;2046 if (end_addr >= region->region_base + region->region_size) {2047 dev_err(hdev->dev,2048 "dynamic FW load: memory transfer end address out of memory region bounds. addr: %llx\n",2049 end_addr);2050 return -EIO;2051 }2052 2053 /*2054 * now make sure memory transfer is within predefined BAR bounds.2055 * this is to make sure we do not need to set the bar (e.g. for DRAM2056 * memory transfers)2057 */2058 if (end_addr >= region->region_base - region->offset_in_bar +2059 region->bar_size) {2060 dev_err(hdev->dev,2061 "FW image beyond PCI BAR bounds\n");2062 return -EIO;2063 }2064 2065 return 0;2066}2067 2068/**2069 * hl_fw_dynamic_validate_descriptor - validate FW descriptor2070 *2071 * @hdev: pointer to the habanalabs device structure2072 * @fw_loader: managing structure for loading device's FW2073 * @fw_desc: the descriptor from FW2074 *2075 * @return 0 on success, otherwise non-zero error code2076 */2077static int hl_fw_dynamic_validate_descriptor(struct hl_device *hdev,2078 struct fw_load_mgr *fw_loader,2079 struct lkd_fw_comms_desc *fw_desc)2080{2081 struct pci_mem_region *region;2082 enum pci_region region_id;2083 size_t data_size;2084 u32 data_crc32;2085 u8 *data_ptr;2086 u64 addr;2087 int rc;2088 2089 if (le32_to_cpu(fw_desc->header.magic) != HL_COMMS_DESC_MAGIC)2090 dev_dbg(hdev->dev, "Invalid magic for dynamic FW descriptor (%x)\n",2091 fw_desc->header.magic);2092 2093 if (fw_desc->header.version != HL_COMMS_DESC_VER)2094 dev_dbg(hdev->dev, "Invalid version for dynamic FW descriptor (%x)\n",2095 fw_desc->header.version);2096 2097 /*2098 * Calc CRC32 of data without header. use the size of the descriptor2099 * reported by firmware, without calculating it ourself, to allow adding2100 * more fields to the lkd_fw_comms_desc structure.2101 * note that no alignment/stride address issues here as all structures2102 * are 64 bit padded.2103 */2104 data_ptr = (u8 *)fw_desc + sizeof(struct comms_msg_header);2105 data_size = le16_to_cpu(fw_desc->header.size);2106 2107 data_crc32 = hl_fw_compat_crc32(data_ptr, data_size);2108 if (data_crc32 != le32_to_cpu(fw_desc->header.crc32)) {2109 dev_err(hdev->dev, "CRC32 mismatch for dynamic FW descriptor (%x:%x)\n",2110 data_crc32, fw_desc->header.crc32);2111 return -EIO;2112 }2113 2114 /* find memory region to which to copy the image */2115 addr = le64_to_cpu(fw_desc->img_addr);2116 region_id = hl_get_pci_memory_region(hdev, addr);2117 if ((region_id != PCI_REGION_SRAM) && ((region_id != PCI_REGION_DRAM))) {2118 dev_err(hdev->dev, "Invalid region to copy FW image address=%llx\n", addr);2119 return -EIO;2120 }2121 2122 region = &hdev->pci_mem_region[region_id];2123 2124 /* store the region for the copy stage */2125 fw_loader->dynamic_loader.image_region = region;2126 2127 /*2128 * here we know that the start address is valid, now make sure that the2129 * image is within region's bounds2130 */2131 rc = hl_fw_dynamic_validate_memory_bound(hdev, addr,2132 fw_loader->dynamic_loader.fw_image_size,2133 region);2134 if (rc) {2135 dev_err(hdev->dev, "invalid mem transfer request for FW image\n");2136 return rc;2137 }2138 2139 /* here we can mark the descriptor as valid as the content has been validated */2140 fw_loader->dynamic_loader.fw_desc_valid = true;2141 2142 return 0;2143}2144 2145static int hl_fw_dynamic_validate_response(struct hl_device *hdev,2146 struct fw_response *response,2147 struct pci_mem_region *region)2148{2149 u64 device_addr;2150 int rc;2151 2152 device_addr = region->region_base + response->ram_offset;2153 2154 /*2155 * validate that the descriptor is within region's bounds2156 * Note that as the start address was supplied according to the RAM2157 * type- testing only the end address is enough2158 */2159 rc = hl_fw_dynamic_validate_memory_bound(hdev, device_addr,2160 sizeof(struct lkd_fw_comms_desc),2161 region);2162 return rc;2163}2164 2165/*2166 * hl_fw_dynamic_read_descriptor_msg - read and show the ascii msg that sent by fw2167 *2168 * @hdev: pointer to the habanalabs device structure2169 * @fw_desc: the descriptor from FW2170 */2171static void hl_fw_dynamic_read_descriptor_msg(struct hl_device *hdev,2172 struct lkd_fw_comms_desc *fw_desc)2173{2174 int i;2175 char *msg;2176 2177 for (i = 0 ; i < LKD_FW_ASCII_MSG_MAX ; i++) {2178 if (!fw_desc->ascii_msg[i].valid)2179 return;2180 2181 /* force NULL termination */2182 msg = fw_desc->ascii_msg[i].msg;2183 msg[LKD_FW_ASCII_MSG_MAX_LEN - 1] = '\0';2184 2185 switch (fw_desc->ascii_msg[i].msg_lvl) {2186 case LKD_FW_ASCII_MSG_ERR:2187 dev_err(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2188 break;2189 case LKD_FW_ASCII_MSG_WRN:2190 dev_warn(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2191 break;2192 case LKD_FW_ASCII_MSG_INF:2193 dev_info(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2194 break;2195 default:2196 dev_dbg(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);2197 break;2198 }2199 }2200}2201 2202/**2203 * hl_fw_dynamic_read_and_validate_descriptor - read and validate FW descriptor2204 *2205 * @hdev: pointer to the habanalabs device structure2206 * @fw_loader: managing structure for loading device's FW2207 *2208 * @return 0 on success, otherwise non-zero error code2209 */2210static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,2211 struct fw_load_mgr *fw_loader)2212{2213 struct lkd_fw_comms_desc *fw_desc;2214 struct pci_mem_region *region;2215 struct fw_response *response;2216 void *temp_fw_desc;2217 void __iomem *src;2218 u16 fw_data_size;2219 enum pci_region region_id;2220 int rc;2221 2222 fw_desc = &fw_loader->dynamic_loader.comm_desc;2223 response = &fw_loader->dynamic_loader.response;2224 2225 region_id = (response->ram_type == COMMS_SRAM) ?2226 PCI_REGION_SRAM : PCI_REGION_DRAM;2227 2228 region = &hdev->pci_mem_region[region_id];2229 2230 rc = hl_fw_dynamic_validate_response(hdev, response, region);2231 if (rc) {2232 dev_err(hdev->dev,2233 "invalid mem transfer request for FW descriptor\n");2234 return rc;2235 }2236 2237 /*2238 * extract address to copy the descriptor from2239 * in addition, as the descriptor value is going to be over-ridden by new data- we mark it2240 * as invalid.2241 * it will be marked again as valid once validated2242 */2243 fw_loader->dynamic_loader.fw_desc_valid = false;2244 src = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +2245 response->ram_offset;2246 2247 /*2248 * We do the copy of the fw descriptor in 2 phases:2249 * 1. copy the header + data info according to our lkd_fw_comms_desc definition.2250 * then we're able to read the actual data size provided by fw.2251 * this is needed for cases where data in descriptor was changed(add/remove)2252 * in embedded specs header file before updating lkd copy of the header file2253 * 2. copy descriptor to temporary buffer with aligned size and send it to validation2254 */2255 memcpy_fromio(fw_desc, src, sizeof(struct lkd_fw_comms_desc));2256 fw_data_size = le16_to_cpu(fw_desc->header.size);2257 2258 temp_fw_desc = vzalloc(sizeof(struct comms_msg_header) + fw_data_size);2259 if (!temp_fw_desc)2260 return -ENOMEM;2261 2262 memcpy_fromio(temp_fw_desc, src, sizeof(struct comms_msg_header) + fw_data_size);2263 2264 rc = hl_fw_dynamic_validate_descriptor(hdev, fw_loader,2265 (struct lkd_fw_comms_desc *) temp_fw_desc);2266 2267 if (!rc)2268 hl_fw_dynamic_read_descriptor_msg(hdev, temp_fw_desc);2269 2270 vfree(temp_fw_desc);2271 2272 return rc;2273}2274 2275/**2276 * hl_fw_dynamic_request_descriptor - handshake with CPU to get FW descriptor2277 *2278 * @hdev: pointer to the habanalabs device structure2279 * @fw_loader: managing structure for loading device's FW2280 * @next_image_size: size to allocate for next FW component2281 *2282 * @return 0 on success, otherwise non-zero error code2283 */2284static int hl_fw_dynamic_request_descriptor(struct hl_device *hdev,2285 struct fw_load_mgr *fw_loader,2286 size_t next_image_size)2287{2288 int rc;2289 2290 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_PREP_DESC,2291 next_image_size, true,2292 fw_loader->cpu_timeout);2293 if (rc)2294 return rc;2295 2296 return hl_fw_dynamic_read_and_validate_descriptor(hdev, fw_loader);2297}2298 2299/**2300 * hl_fw_dynamic_read_device_fw_version - read FW version to exposed properties2301 *2302 * @hdev: pointer to the habanalabs device structure2303 * @fwc: the firmware component2304 * @fw_version: fw component's version string2305 */2306static int hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev,2307 enum hl_fw_component fwc,2308 const char *fw_version)2309{2310 struct asic_fixed_properties *prop = &hdev->asic_prop;2311 char *preboot_ver, *boot_ver;2312 char btl_ver[32];2313 int rc;2314 2315 switch (fwc) {2316 case FW_COMP_BOOT_FIT:2317 strscpy(prop->uboot_ver, fw_version, VERSION_MAX_LEN);2318 boot_ver = extract_fw_ver_from_str(prop->uboot_ver);2319 if (boot_ver) {2320 dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);2321 kfree(boot_ver);2322 }2323 2324 break;2325 case FW_COMP_PREBOOT:2326 strscpy(prop->preboot_ver, fw_version, VERSION_MAX_LEN);2327 preboot_ver = strnstr(prop->preboot_ver, "Preboot", VERSION_MAX_LEN);2328 dev_info(hdev->dev, "preboot full version: '%s'\n", preboot_ver);2329 2330 if (preboot_ver && preboot_ver != prop->preboot_ver) {2331 strscpy(btl_ver, prop->preboot_ver,2332 min((int) (preboot_ver - prop->preboot_ver), 31));2333 dev_info(hdev->dev, "%s\n", btl_ver);2334 }2335 2336 rc = hl_get_sw_major_minor_subminor(hdev, preboot_ver);2337 if (rc)2338 return rc;2339 preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);2340 if (preboot_ver) {2341 rc = hl_get_preboot_major_minor(hdev, preboot_ver);2342 kfree(preboot_ver);2343 if (rc)2344 return rc;2345 }2346 2347 break;2348 default:2349 dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);2350 return -EINVAL;2351 }2352 2353 return 0;2354}2355 2356/**2357 * hl_fw_dynamic_copy_image - copy image to memory allocated by the FW2358 *2359 * @hdev: pointer to the habanalabs device structure2360 * @fw: fw descriptor2361 * @fw_loader: managing structure for loading device's FW2362 */2363static int hl_fw_dynamic_copy_image(struct hl_device *hdev,2364 const struct firmware *fw,2365 struct fw_load_mgr *fw_loader)2366{2367 struct lkd_fw_comms_desc *fw_desc;2368 struct pci_mem_region *region;2369 void __iomem *dest;2370 u64 addr;2371 int rc;2372 2373 fw_desc = &fw_loader->dynamic_loader.comm_desc;2374 addr = le64_to_cpu(fw_desc->img_addr);2375 2376 /* find memory region to which to copy the image */2377 region = fw_loader->dynamic_loader.image_region;2378 2379 dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +2380 (addr - region->region_base);2381 2382 rc = hl_fw_copy_fw_to_device(hdev, fw, dest,2383 fw_loader->boot_fit_img.src_off,2384 fw_loader->boot_fit_img.copy_size);2385 2386 return rc;2387}2388 2389/**2390 * hl_fw_dynamic_copy_msg - copy msg to memory allocated by the FW2391 *2392 * @hdev: pointer to the habanalabs device structure2393 * @msg: message2394 * @fw_loader: managing structure for loading device's FW2395 */2396static int hl_fw_dynamic_copy_msg(struct hl_device *hdev,2397 struct lkd_msg_comms *msg, struct fw_load_mgr *fw_loader)2398{2399 struct lkd_fw_comms_desc *fw_desc;2400 struct pci_mem_region *region;2401 void __iomem *dest;2402 u64 addr;2403 int rc;2404 2405 fw_desc = &fw_loader->dynamic_loader.comm_desc;2406 addr = le64_to_cpu(fw_desc->img_addr);2407 2408 /* find memory region to which to copy the image */2409 region = fw_loader->dynamic_loader.image_region;2410 2411 dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +2412 (addr - region->region_base);2413 2414 rc = hl_fw_copy_msg_to_device(hdev, msg, dest, 0, 0);2415 2416 return rc;2417}2418 2419/**2420 * hl_fw_boot_fit_update_state - update internal data structures after boot-fit2421 * is loaded2422 *2423 * @hdev: pointer to the habanalabs device structure2424 * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 02425 * @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 12426 *2427 * @return 0 on success, otherwise non-zero error code2428 */2429static void hl_fw_boot_fit_update_state(struct hl_device *hdev,2430 u32 cpu_boot_dev_sts0_reg,2431 u32 cpu_boot_dev_sts1_reg)2432{2433 struct asic_fixed_properties *prop = &hdev->asic_prop;2434 2435 hdev->fw_loader.fw_comp_loaded |= FW_TYPE_BOOT_CPU;2436 2437 /* Read boot_cpu status bits */2438 if (prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) {2439 prop->fw_bootfit_cpu_boot_dev_sts0 =2440 RREG32(cpu_boot_dev_sts0_reg);2441 2442 prop->hard_reset_done_by_fw = !!(prop->fw_bootfit_cpu_boot_dev_sts0 &2443 CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);2444 2445 dev_dbg(hdev->dev, "Firmware boot CPU status0 %#x\n",2446 prop->fw_bootfit_cpu_boot_dev_sts0);2447 }2448 2449 if (prop->fw_cpu_boot_dev_sts1_valid) {2450 prop->fw_bootfit_cpu_boot_dev_sts1 =2451 RREG32(cpu_boot_dev_sts1_reg);2452 2453 dev_dbg(hdev->dev, "Firmware boot CPU status1 %#x\n",2454 prop->fw_bootfit_cpu_boot_dev_sts1);2455 }2456 2457 dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n",2458 prop->hard_reset_done_by_fw ? "enabled" : "disabled");2459}2460 2461static void hl_fw_dynamic_update_linux_interrupt_if(struct hl_device *hdev)2462{2463 struct cpu_dyn_regs *dyn_regs =2464 &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;2465 2466 /* Check whether all 3 interrupt interfaces are set, if not use a2467 * single interface2468 */2469 if (!hdev->asic_prop.gic_interrupts_enable &&2470 !(hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &2471 CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN)) {2472 dyn_regs->gic_host_halt_irq = dyn_regs->gic_host_pi_upd_irq;2473 dyn_regs->gic_host_ints_irq = dyn_regs->gic_host_pi_upd_irq;2474 2475 dev_warn(hdev->dev,2476 "Using a single interrupt interface towards cpucp");2477 }2478}2479/**2480 * hl_fw_dynamic_load_image - load FW image using dynamic protocol2481 *2482 * @hdev: pointer to the habanalabs device structure2483 * @fw_loader: managing structure for loading device's FW2484 * @load_fwc: the FW component to be loaded2485 * @img_ld_timeout: image load timeout2486 *2487 * @return 0 on success, otherwise non-zero error code2488 */2489static int hl_fw_dynamic_load_image(struct hl_device *hdev,2490 struct fw_load_mgr *fw_loader,2491 enum hl_fw_component load_fwc,2492 u32 img_ld_timeout)2493{2494 enum hl_fw_component cur_fwc;2495 const struct firmware *fw;2496 char *fw_name;2497 int rc = 0;2498 2499 /*2500 * when loading image we have one of 2 scenarios:2501 * 1. current FW component is preboot and we want to load boot-fit2502 * 2. current FW component is boot-fit and we want to load linux2503 */2504 if (load_fwc == FW_COMP_BOOT_FIT) {2505 cur_fwc = FW_COMP_PREBOOT;2506 fw_name = fw_loader->boot_fit_img.image_name;2507 } else {2508 cur_fwc = FW_COMP_BOOT_FIT;2509 fw_name = fw_loader->linux_img.image_name;2510 }2511 2512 /* request FW in order to communicate to FW the size to be allocated */2513 rc = hl_request_fw(hdev, &fw, fw_name);2514 if (rc)2515 return rc;2516 2517 /* store the image size for future validation */2518 fw_loader->dynamic_loader.fw_image_size = fw->size;2519 2520 rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, fw->size);2521 if (rc)2522 goto release_fw;2523 2524 /* read preboot version */2525 rc = hl_fw_dynamic_read_device_fw_version(hdev, cur_fwc,2526 fw_loader->dynamic_loader.comm_desc.cur_fw_ver);2527 if (rc)2528 goto release_fw;2529 2530 /* copy boot fit to space allocated by FW */2531 rc = hl_fw_dynamic_copy_image(hdev, fw, fw_loader);2532 if (rc)2533 goto release_fw;2534 2535 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,2536 0, true,2537 fw_loader->cpu_timeout);2538 if (rc)2539 goto release_fw;2540 2541 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,2542 0, false,2543 img_ld_timeout);2544 2545release_fw:2546 hl_release_firmware(fw);2547 return rc;2548}2549 2550static int hl_fw_dynamic_wait_for_boot_fit_active(struct hl_device *hdev,2551 struct fw_load_mgr *fw_loader)2552{2553 struct dynamic_fw_load_mgr *dyn_loader;2554 u32 status;2555 int rc;2556 2557 dyn_loader = &fw_loader->dynamic_loader;2558 2559 /*2560 * Make sure CPU boot-loader is running2561 * Note that the CPU_BOOT_STATUS_SRAM_AVAIL is generally set by Linux2562 * yet there is a debug scenario in which we loading uboot (without Linux)2563 * which at later stage is relocated to DRAM. In this case we expect2564 * uboot to set the CPU_BOOT_STATUS_SRAM_AVAIL and so we add it to the2565 * poll flags2566 */2567 rc = hl_poll_timeout(2568 hdev,2569 le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status),2570 status,2571 (status == CPU_BOOT_STATUS_READY_TO_BOOT) ||2572 (status == CPU_BOOT_STATUS_SRAM_AVAIL),2573 hdev->fw_poll_interval_usec,2574 dyn_loader->wait_for_bl_timeout);2575 if (rc) {2576 dev_err(hdev->dev, "failed to wait for boot (status = %d)\n", status);2577 return rc;2578 }2579 2580 dev_dbg(hdev->dev, "uboot status = %d\n", status);2581 return 0;2582}2583 2584static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev,2585 struct fw_load_mgr *fw_loader)2586{2587 struct dynamic_fw_load_mgr *dyn_loader;2588 u32 status;2589 int rc;2590 2591 dyn_loader = &fw_loader->dynamic_loader;2592 2593 /* Make sure CPU linux is running */2594 2595 rc = hl_poll_timeout(2596 hdev,2597 le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status),2598 status,2599 (status == CPU_BOOT_STATUS_SRAM_AVAIL),2600 hdev->fw_poll_interval_usec,2601 fw_loader->cpu_timeout);2602 if (rc) {2603 dev_err(hdev->dev, "failed to wait for Linux (status = %d)\n", status);2604 return rc;2605 }2606 2607 dev_dbg(hdev->dev, "Boot status = %d\n", status);2608 return 0;2609}2610 2611/**2612 * hl_fw_linux_update_state - update internal data structures after Linux2613 * is loaded.2614 * Note: Linux initialization is comprised mainly2615 * of two stages - loading kernel (SRAM_AVAIL)2616 * & loading ARMCP.2617 * Therefore reading boot device status in any of2618 * these stages might result in different values.2619 *2620 * @hdev: pointer to the habanalabs device structure2621 * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 02622 * @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 12623 *2624 * @return 0 on success, otherwise non-zero error code2625 */2626static void hl_fw_linux_update_state(struct hl_device *hdev,2627 u32 cpu_boot_dev_sts0_reg,2628 u32 cpu_boot_dev_sts1_reg)2629{2630 struct asic_fixed_properties *prop = &hdev->asic_prop;2631 2632 hdev->fw_loader.fw_comp_loaded |= FW_TYPE_LINUX;2633 2634 /* Read FW application security bits */2635 if (prop->fw_cpu_boot_dev_sts0_valid) {2636 prop->fw_app_cpu_boot_dev_sts0 = RREG32(cpu_boot_dev_sts0_reg);2637 2638 prop->hard_reset_done_by_fw = !!(prop->fw_app_cpu_boot_dev_sts0 &2639 CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);2640 2641 if (prop->fw_app_cpu_boot_dev_sts0 &2642 CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN)2643 prop->gic_interrupts_enable = false;2644 2645 dev_dbg(hdev->dev,2646 "Firmware application CPU status0 %#x\n",2647 prop->fw_app_cpu_boot_dev_sts0);2648 2649 dev_dbg(hdev->dev, "GIC controller is %s\n",2650 prop->gic_interrupts_enable ?2651 "enabled" : "disabled");2652 }2653 2654 if (prop->fw_cpu_boot_dev_sts1_valid) {2655 prop->fw_app_cpu_boot_dev_sts1 = RREG32(cpu_boot_dev_sts1_reg);2656 2657 dev_dbg(hdev->dev,2658 "Firmware application CPU status1 %#x\n",2659 prop->fw_app_cpu_boot_dev_sts1);2660 }2661 2662 dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n",2663 prop->hard_reset_done_by_fw ? "enabled" : "disabled");2664 2665 dev_info(hdev->dev, "Successfully loaded firmware to device\n");2666}2667 2668/**2669 * hl_fw_dynamic_send_msg - send a COMMS message with attached data2670 *2671 * @hdev: pointer to the habanalabs device structure2672 * @fw_loader: managing structure for loading device's FW2673 * @msg_type: message type2674 * @data: data to be sent2675 *2676 * @return 0 on success, otherwise non-zero error code2677 */2678static int hl_fw_dynamic_send_msg(struct hl_device *hdev,2679 struct fw_load_mgr *fw_loader, u8 msg_type, void *data)2680{2681 struct lkd_msg_comms *msg;2682 int rc;2683 2684 msg = kzalloc(sizeof(*msg), GFP_KERNEL);2685 if (!msg)2686 return -ENOMEM;2687 2688 /* create message to be sent */2689 msg->header.type = msg_type;2690 msg->header.size = cpu_to_le16(sizeof(struct comms_msg_header));2691 msg->header.magic = cpu_to_le32(HL_COMMS_MSG_MAGIC);2692 2693 switch (msg_type) {2694 case HL_COMMS_RESET_CAUSE_TYPE:2695 msg->reset_cause = *(__u8 *) data;2696 break;2697 2698 default:2699 dev_err(hdev->dev,2700 "Send COMMS message - invalid message type %u\n",2701 msg_type);2702 rc = -EINVAL;2703 goto out;2704 }2705 2706 rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader,2707 sizeof(struct lkd_msg_comms));2708 if (rc)2709 goto out;2710 2711 /* copy message to space allocated by FW */2712 rc = hl_fw_dynamic_copy_msg(hdev, msg, fw_loader);2713 if (rc)2714 goto out;2715 2716 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,2717 0, true,2718 fw_loader->cpu_timeout);2719 if (rc)2720 goto out;2721 2722 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,2723 0, true,2724 fw_loader->cpu_timeout);2725 2726out:2727 kfree(msg);2728 return rc;2729}2730 2731/**2732 * hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol2733 *2734 * @hdev: pointer to the habanalabs device structure2735 * @fw_loader: managing structure for loading device's FW2736 *2737 * @return 0 on success, otherwise non-zero error code2738 *2739 * brief: the dynamic protocol is master (LKD) slave (FW CPU) protocol.2740 * the communication is done using registers:2741 * - LKD command register2742 * - FW status register2743 * the protocol is race free. this goal is achieved by splitting the requests2744 * and response to known synchronization points between the LKD and the FW.2745 * each response to LKD request is known and bound to a predefined timeout.2746 * in case of timeout expiration without the desired status from FW- the2747 * protocol (and hence the boot) will fail.2748 */2749static int hl_fw_dynamic_init_cpu(struct hl_device *hdev,2750 struct fw_load_mgr *fw_loader)2751{2752 struct cpu_dyn_regs *dyn_regs;2753 int rc, fw_error_rc;2754 2755 dev_info(hdev->dev,2756 "Loading %sfirmware to device, may take some time...\n",2757 hdev->asic_prop.fw_security_enabled ? "secured " : "");2758 2759 /* initialize FW descriptor as invalid */2760 fw_loader->dynamic_loader.fw_desc_valid = false;2761 2762 /*2763 * In this stage, "cpu_dyn_regs" contains only LKD's hard coded values!2764 * It will be updated from FW after hl_fw_dynamic_request_descriptor().2765 */2766 dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;2767 2768 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE,2769 0, true,2770 fw_loader->cpu_timeout);2771 if (rc)2772 goto protocol_err;2773 2774 if (hdev->reset_info.curr_reset_cause) {2775 rc = hl_fw_dynamic_send_msg(hdev, fw_loader,2776 HL_COMMS_RESET_CAUSE_TYPE, &hdev->reset_info.curr_reset_cause);2777 if (rc)2778 goto protocol_err;2779 2780 /* Clear current reset cause */2781 hdev->reset_info.curr_reset_cause = HL_RESET_CAUSE_UNKNOWN;2782 }2783 2784 rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, sizeof(struct lkd_msg_comms));2785 if (rc)2786 goto protocol_err;2787 2788 if (hdev->asic_prop.support_dynamic_resereved_fw_size)2789 hdev->asic_prop.reserved_fw_mem_size =2790 le32_to_cpu(fw_loader->dynamic_loader.comm_desc.rsvd_mem_size_mb) * SZ_1M;2791 2792 if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) {2793 struct lkd_fw_binning_info *binning_info;2794 2795 /* read preboot version */2796 rc = hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT,2797 fw_loader->dynamic_loader.comm_desc.cur_fw_ver);2798 if (rc)2799 return rc;2800 2801 /* read binning info from preboot */2802 if (hdev->support_preboot_binning) {2803 binning_info = &fw_loader->dynamic_loader.comm_desc.binning_info;2804 hdev->tpc_binning = le64_to_cpu(binning_info->tpc_mask_l);2805 hdev->dram_binning = le32_to_cpu(binning_info->dram_mask);2806 hdev->edma_binning = le32_to_cpu(binning_info->edma_mask);2807 hdev->decoder_binning = le32_to_cpu(binning_info->dec_mask);2808 hdev->rotator_binning = le32_to_cpu(binning_info->rot_mask);2809 2810 rc = hdev->asic_funcs->set_dram_properties(hdev);2811 if (rc)2812 return rc;2813 2814 rc = hdev->asic_funcs->set_binning_masks(hdev);2815 if (rc)2816 return rc;2817 2818 dev_dbg(hdev->dev,2819 "Read binning masks: tpc: 0x%llx, dram: 0x%llx, edma: 0x%x, dec: 0x%x, rot:0x%x\n",2820 hdev->tpc_binning, hdev->dram_binning, hdev->edma_binning,2821 hdev->decoder_binning, hdev->rotator_binning);2822 }2823 2824 return 0;2825 }2826 2827 /* load boot fit to FW */2828 rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_BOOT_FIT,2829 fw_loader->boot_fit_timeout);2830 if (rc) {2831 dev_err(hdev->dev, "failed to load boot fit\n");2832 goto protocol_err;2833 }2834 2835 rc = hl_fw_dynamic_wait_for_boot_fit_active(hdev, fw_loader);2836 if (rc)2837 goto protocol_err;2838 2839 hl_fw_boot_fit_update_state(hdev,2840 le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),2841 le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));2842 2843 /*2844 * when testing FW load (without Linux) on PLDM we don't want to2845 * wait until boot fit is active as it may take several hours.2846 * instead, we load the bootfit and let it do all initialization in2847 * the background.2848 */2849 if (hdev->pldm && !(hdev->fw_components & FW_TYPE_LINUX))2850 return 0;2851 2852 /* Enable DRAM scrambling before Linux boot and after successful2853 * UBoot2854 */2855 hdev->asic_funcs->init_cpu_scrambler_dram(hdev);2856 2857 if (!(hdev->fw_components & FW_TYPE_LINUX)) {2858 dev_dbg(hdev->dev, "Skip loading Linux F/W\n");2859 return 0;2860 }2861 2862 if (fw_loader->skip_bmc) {2863 rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader,2864 COMMS_SKIP_BMC, 0,2865 true,2866 fw_loader->cpu_timeout);2867 if (rc) {2868 dev_err(hdev->dev, "failed to load boot fit\n");2869 goto protocol_err;2870 }2871 }2872 2873 /* load Linux image to FW */2874 rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_LINUX,2875 fw_loader->cpu_timeout);2876 if (rc) {2877 dev_err(hdev->dev, "failed to load Linux\n");2878 goto protocol_err;2879 }2880 2881 rc = hl_fw_dynamic_wait_for_linux_active(hdev, fw_loader);2882 if (rc)2883 goto protocol_err;2884 2885 hl_fw_linux_update_state(hdev,2886 le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),2887 le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));2888 2889 hl_fw_dynamic_update_linux_interrupt_if(hdev);2890 2891protocol_err:2892 if (fw_loader->dynamic_loader.fw_desc_valid) {2893 fw_error_rc = fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0),2894 le32_to_cpu(dyn_regs->cpu_boot_err1),2895 le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),2896 le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));2897 2898 if (fw_error_rc)2899 return fw_error_rc;2900 }2901 2902 return rc;2903}2904 2905/**2906 * hl_fw_static_init_cpu - initialize the device CPU using static protocol2907 *2908 * @hdev: pointer to the habanalabs device structure2909 * @fw_loader: managing structure for loading device's FW2910 *2911 * @return 0 on success, otherwise non-zero error code2912 */2913static int hl_fw_static_init_cpu(struct hl_device *hdev,2914 struct fw_load_mgr *fw_loader)2915{2916 u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status;2917 u32 cpu_boot_dev_status0_reg, cpu_boot_dev_status1_reg;2918 struct static_fw_load_mgr *static_loader;2919 u32 cpu_boot_status_reg;2920 int rc;2921 2922 if (!(hdev->fw_components & FW_TYPE_BOOT_CPU))2923 return 0;2924 2925 /* init common loader parameters */2926 cpu_timeout = fw_loader->cpu_timeout;2927 2928 /* init static loader parameters */2929 static_loader = &fw_loader->static_loader;2930 cpu_msg_status_reg = static_loader->cpu_cmd_status_to_host_reg;2931 msg_to_cpu_reg = static_loader->kmd_msg_to_cpu_reg;2932 cpu_boot_dev_status0_reg = static_loader->cpu_boot_dev_status0_reg;2933 cpu_boot_dev_status1_reg = static_loader->cpu_boot_dev_status1_reg;2934 cpu_boot_status_reg = static_loader->cpu_boot_status_reg;2935 2936 dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n",2937 cpu_timeout / USEC_PER_SEC);2938 2939 /* Wait for boot FIT request */2940 rc = hl_poll_timeout(2941 hdev,2942 cpu_boot_status_reg,2943 status,2944 status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT,2945 hdev->fw_poll_interval_usec,2946 fw_loader->boot_fit_timeout);2947 2948 if (rc) {2949 dev_dbg(hdev->dev,2950 "No boot fit request received (status = %d), resuming boot\n", status);2951 } else {2952 rc = hdev->asic_funcs->load_boot_fit_to_device(hdev);2953 if (rc)2954 goto out;2955 2956 /* Clear device CPU message status */2957 WREG32(cpu_msg_status_reg, CPU_MSG_CLR);2958 2959 /* Signal device CPU that boot loader is ready */2960 WREG32(msg_to_cpu_reg, KMD_MSG_FIT_RDY);2961 2962 /* Poll for CPU device ack */2963 rc = hl_poll_timeout(2964 hdev,2965 cpu_msg_status_reg,2966 status,2967 status == CPU_MSG_OK,2968 hdev->fw_poll_interval_usec,2969 fw_loader->boot_fit_timeout);2970 2971 if (rc) {2972 dev_err(hdev->dev,2973 "Timeout waiting for boot fit load ack (status = %d)\n", status);2974 goto out;2975 }2976 2977 /* Clear message */2978 WREG32(msg_to_cpu_reg, KMD_MSG_NA);2979 }2980 2981 /*2982 * Make sure CPU boot-loader is running2983 * Note that the CPU_BOOT_STATUS_SRAM_AVAIL is generally set by Linux2984 * yet there is a debug scenario in which we loading uboot (without Linux)2985 * which at later stage is relocated to DRAM. In this case we expect2986 * uboot to set the CPU_BOOT_STATUS_SRAM_AVAIL and so we add it to the2987 * poll flags2988 */2989 rc = hl_poll_timeout(2990 hdev,2991 cpu_boot_status_reg,2992 status,2993 (status == CPU_BOOT_STATUS_DRAM_RDY) ||2994 (status == CPU_BOOT_STATUS_NIC_FW_RDY) ||2995 (status == CPU_BOOT_STATUS_READY_TO_BOOT) ||2996 (status == CPU_BOOT_STATUS_SRAM_AVAIL),2997 hdev->fw_poll_interval_usec,2998 cpu_timeout);2999 3000 dev_dbg(hdev->dev, "uboot status = %d\n", status);3001 3002 /* Read U-Boot version now in case we will later fail */3003 hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT);3004 3005 /* update state according to boot stage */3006 hl_fw_boot_fit_update_state(hdev, cpu_boot_dev_status0_reg,3007 cpu_boot_dev_status1_reg);3008 3009 if (rc) {3010 detect_cpu_boot_status(hdev, status);3011 rc = -EIO;3012 goto out;3013 }3014 3015 /* Enable DRAM scrambling before Linux boot and after successful3016 * UBoot3017 */3018 hdev->asic_funcs->init_cpu_scrambler_dram(hdev);3019 3020 if (!(hdev->fw_components & FW_TYPE_LINUX)) {3021 dev_info(hdev->dev, "Skip loading Linux F/W\n");3022 rc = 0;3023 goto out;3024 }3025 3026 if (status == CPU_BOOT_STATUS_SRAM_AVAIL) {3027 rc = 0;3028 goto out;3029 }3030 3031 dev_info(hdev->dev,3032 "Loading firmware to device, may take some time...\n");3033 3034 rc = hdev->asic_funcs->load_firmware_to_device(hdev);3035 if (rc)3036 goto out;3037 3038 if (fw_loader->skip_bmc) {3039 WREG32(msg_to_cpu_reg, KMD_MSG_SKIP_BMC);3040 3041 rc = hl_poll_timeout(3042 hdev,3043 cpu_boot_status_reg,3044 status,3045 (status == CPU_BOOT_STATUS_BMC_WAITING_SKIPPED),3046 hdev->fw_poll_interval_usec,3047 cpu_timeout);3048 3049 if (rc) {3050 dev_err(hdev->dev,3051 "Failed to get ACK on skipping BMC (status = %d)\n",3052 status);3053 WREG32(msg_to_cpu_reg, KMD_MSG_NA);3054 rc = -EIO;3055 goto out;3056 }3057 }3058 3059 WREG32(msg_to_cpu_reg, KMD_MSG_FIT_RDY);3060 3061 rc = hl_poll_timeout(3062 hdev,3063 cpu_boot_status_reg,3064 status,3065 (status == CPU_BOOT_STATUS_SRAM_AVAIL),3066 hdev->fw_poll_interval_usec,3067 cpu_timeout);3068 3069 /* Clear message */3070 WREG32(msg_to_cpu_reg, KMD_MSG_NA);3071 3072 if (rc) {3073 if (status == CPU_BOOT_STATUS_FIT_CORRUPTED)3074 dev_err(hdev->dev,3075 "Device reports FIT image is corrupted\n");3076 else3077 dev_err(hdev->dev,3078 "Failed to load firmware to device (status = %d)\n",3079 status);3080 3081 rc = -EIO;3082 goto out;3083 }3084 3085 rc = fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,3086 fw_loader->static_loader.boot_err1_reg,3087 cpu_boot_dev_status0_reg,3088 cpu_boot_dev_status1_reg);3089 if (rc)3090 return rc;3091 3092 hl_fw_linux_update_state(hdev, cpu_boot_dev_status0_reg,3093 cpu_boot_dev_status1_reg);3094 3095 return 0;3096 3097out:3098 fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,3099 fw_loader->static_loader.boot_err1_reg,3100 cpu_boot_dev_status0_reg,3101 cpu_boot_dev_status1_reg);3102 3103 return rc;3104}3105 3106/**3107 * hl_fw_init_cpu - initialize the device CPU3108 *3109 * @hdev: pointer to the habanalabs device structure3110 *3111 * @return 0 on success, otherwise non-zero error code3112 *3113 * perform necessary initializations for device's CPU. takes into account if3114 * init protocol is static or dynamic.3115 */3116int hl_fw_init_cpu(struct hl_device *hdev)3117{3118 struct asic_fixed_properties *prop = &hdev->asic_prop;3119 struct fw_load_mgr *fw_loader = &hdev->fw_loader;3120 3121 return prop->dynamic_fw_load ?3122 hl_fw_dynamic_init_cpu(hdev, fw_loader) :3123 hl_fw_static_init_cpu(hdev, fw_loader);3124}3125 3126void hl_fw_set_pll_profile(struct hl_device *hdev)3127{3128 hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index,3129 hdev->asic_prop.max_freq_value);3130}3131 3132int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk)3133{3134 long value;3135 3136 if (!hl_device_operational(hdev, NULL))3137 return -ENODEV;3138 3139 if (!hdev->pdev) {3140 *cur_clk = 0;3141 *max_clk = 0;3142 return 0;3143 }3144 3145 value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);3146 3147 if (value < 0) {3148 dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value);3149 return value;3150 }3151 3152 *max_clk = (value / 1000 / 1000);3153 3154 value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);3155 3156 if (value < 0) {3157 dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value);3158 return value;3159 }3160 3161 *cur_clk = (value / 1000 / 1000);3162 3163 return 0;3164}3165 3166long hl_fw_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr)3167{3168 struct cpucp_packet pkt;3169 u32 used_pll_idx;3170 u64 result;3171 int rc;3172 3173 rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);3174 if (rc)3175 return rc;3176 3177 memset(&pkt, 0, sizeof(pkt));3178 3179 if (curr)3180 pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_CURR_GET <<3181 CPUCP_PKT_CTL_OPCODE_SHIFT);3182 else3183 pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);3184 3185 pkt.pll_index = cpu_to_le32((u32)used_pll_idx);3186 3187 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);3188 if (rc) {3189 if (rc != -EAGAIN)3190 dev_err(hdev->dev, "Failed to get frequency of PLL %d, error %d\n",3191 used_pll_idx, rc);3192 return rc;3193 }3194 3195 return (long) result;3196}3197 3198void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq)3199{3200 struct cpucp_packet pkt;3201 u32 used_pll_idx;3202 int rc;3203 3204 rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);3205 if (rc)3206 return;3207 3208 memset(&pkt, 0, sizeof(pkt));3209 3210 pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);3211 pkt.pll_index = cpu_to_le32((u32)used_pll_idx);3212 pkt.value = cpu_to_le64(freq);3213 3214 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);3215 if (rc && rc != -EAGAIN)3216 dev_err(hdev->dev, "Failed to set frequency to PLL %d, error %d\n",3217 used_pll_idx, rc);3218}3219 3220long hl_fw_get_max_power(struct hl_device *hdev)3221{3222 struct cpucp_packet pkt;3223 u64 result;3224 int rc;3225 3226 memset(&pkt, 0, sizeof(pkt));3227 3228 pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);3229 3230 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);3231 if (rc) {3232 if (rc != -EAGAIN)3233 dev_err(hdev->dev, "Failed to get max power, error %d\n", rc);3234 return rc;3235 }3236 3237 return result;3238}3239 3240void hl_fw_set_max_power(struct hl_device *hdev)3241{3242 struct cpucp_packet pkt;3243 int rc;3244 3245 /* TODO: remove this after simulator supports this packet */3246 if (!hdev->pdev)3247 return;3248 3249 memset(&pkt, 0, sizeof(pkt));3250 3251 pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);3252 pkt.value = cpu_to_le64(hdev->max_power);3253 3254 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);3255 if (rc && rc != -EAGAIN)3256 dev_err(hdev->dev, "Failed to set max power, error %d\n", rc);3257}3258 3259static int hl_fw_get_sec_attest_data(struct hl_device *hdev, u32 packet_id, void *data, u32 size,3260 u32 nonce, u32 timeout)3261{3262 struct cpucp_packet pkt = {};3263 dma_addr_t req_dma_addr;3264 void *req_cpu_addr;3265 int rc;3266 3267 req_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, size, &req_dma_addr);3268 if (!req_cpu_addr) {3269 dev_err(hdev->dev,3270 "Failed to allocate DMA memory for CPU-CP packet %u\n", packet_id);3271 return -ENOMEM;3272 }3273 3274 memset(data, 0, size);3275 3276 pkt.ctl = cpu_to_le32(packet_id << CPUCP_PKT_CTL_OPCODE_SHIFT);3277 pkt.addr = cpu_to_le64(req_dma_addr);3278 pkt.data_max_size = cpu_to_le32(size);3279 pkt.nonce = cpu_to_le32(nonce);3280 3281 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), timeout, NULL);3282 if (rc) {3283 if (rc != -EAGAIN)3284 dev_err(hdev->dev,3285 "Failed to handle CPU-CP pkt %u, error %d\n", packet_id, rc);3286 goto out;3287 }3288 3289 memcpy(data, req_cpu_addr, size);3290 3291out:3292 hl_cpu_accessible_dma_pool_free(hdev, size, req_cpu_addr);3293 3294 return rc;3295}3296 3297int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_info *sec_attest_info,3298 u32 nonce)3299{3300 return hl_fw_get_sec_attest_data(hdev, CPUCP_PACKET_SEC_ATTEST_GET, sec_attest_info,3301 sizeof(struct cpucp_sec_attest_info), nonce,3302 HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC);3303}3304 3305int hl_fw_get_dev_info_signed(struct hl_device *hdev,3306 struct cpucp_dev_info_signed *dev_info_signed, u32 nonce)3307{3308 return hl_fw_get_sec_attest_data(hdev, CPUCP_PACKET_INFO_SIGNED_GET, dev_info_signed,3309 sizeof(struct cpucp_dev_info_signed), nonce,3310 HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC);3311}3312 3313int hl_fw_send_generic_request(struct hl_device *hdev, enum hl_passthrough_type sub_opcode,3314 dma_addr_t buff, u32 *size)3315{3316 struct cpucp_packet pkt = {};3317 u64 result;3318 int rc = 0;3319 3320 pkt.ctl = cpu_to_le32(CPUCP_PACKET_GENERIC_PASSTHROUGH << CPUCP_PKT_CTL_OPCODE_SHIFT);3321 pkt.addr = cpu_to_le64(buff);3322 pkt.data_max_size = cpu_to_le32(*size);3323 pkt.pkt_subidx = cpu_to_le32(sub_opcode);3324 3325 rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)&pkt, sizeof(pkt),3326 HL_CPUCP_INFO_TIMEOUT_USEC, &result);3327 if (rc) {3328 if (rc != -EAGAIN)3329 dev_err(hdev->dev, "failed to send CPUCP data of generic fw pkt\n");3330 } else {3331 dev_dbg(hdev->dev, "generic pkt was successful, result: 0x%llx\n", result);3332 }3333 3334 *size = (u32)result;3335 3336 return rc;3337}3338