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