162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Copyright 2020 HabanaLabs, Ltd. 562306a36Sopenharmony_ci * All Rights Reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "habanalabs.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic const char * const hl_glbl_error_cause[HL_MAX_NUM_OF_GLBL_ERR_CAUSE] = { 1162306a36Sopenharmony_ci "Error due to un-priv read", 1262306a36Sopenharmony_ci "Error due to un-secure read", 1362306a36Sopenharmony_ci "Error due to read from unmapped reg", 1462306a36Sopenharmony_ci "Error due to un-priv write", 1562306a36Sopenharmony_ci "Error due to un-secure write", 1662306a36Sopenharmony_ci "Error due to write to unmapped reg", 1762306a36Sopenharmony_ci "External I/F write sec violation", 1862306a36Sopenharmony_ci "External I/F write to un-mapped reg", 1962306a36Sopenharmony_ci "Read to write only", 2062306a36Sopenharmony_ci "Write to read only" 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * hl_get_pb_block - return the relevant block within the block array 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 2762306a36Sopenharmony_ci * @mm_reg_addr: register address in the desired block 2862306a36Sopenharmony_ci * @pb_blocks: blocks array 2962306a36Sopenharmony_ci * @array_size: blocks array size 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic int hl_get_pb_block(struct hl_device *hdev, u32 mm_reg_addr, 3362306a36Sopenharmony_ci const u32 pb_blocks[], int array_size) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci int i; 3662306a36Sopenharmony_ci u32 start_addr, end_addr; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci for (i = 0 ; i < array_size ; i++) { 3962306a36Sopenharmony_ci start_addr = pb_blocks[i]; 4062306a36Sopenharmony_ci end_addr = start_addr + HL_BLOCK_SIZE; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if ((mm_reg_addr >= start_addr) && (mm_reg_addr < end_addr)) 4362306a36Sopenharmony_ci return i; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci dev_err(hdev->dev, "No protection domain was found for 0x%x\n", 4762306a36Sopenharmony_ci mm_reg_addr); 4862306a36Sopenharmony_ci return -EDOM; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * hl_unset_pb_in_block - clear a specific protection bit in a block 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 5562306a36Sopenharmony_ci * @reg_offset: register offset will be converted to bit offset in pb block 5662306a36Sopenharmony_ci * @sgs_entry: pb array 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_cistatic int hl_unset_pb_in_block(struct hl_device *hdev, u32 reg_offset, 6062306a36Sopenharmony_ci struct hl_block_glbl_sec *sgs_entry) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci if ((reg_offset >= HL_BLOCK_SIZE) || (reg_offset & 0x3)) { 6362306a36Sopenharmony_ci dev_err(hdev->dev, 6462306a36Sopenharmony_ci "Register offset(%d) is out of range(%d) or invalid\n", 6562306a36Sopenharmony_ci reg_offset, HL_BLOCK_SIZE); 6662306a36Sopenharmony_ci return -EINVAL; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci UNSET_GLBL_SEC_BIT(sgs_entry->sec_array, 7062306a36Sopenharmony_ci (reg_offset & (HL_BLOCK_SIZE - 1)) >> 2); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * hl_unsecure_register - locate the relevant block for this register and 7762306a36Sopenharmony_ci * remove corresponding protection bit 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 8062306a36Sopenharmony_ci * @mm_reg_addr: register address to unsecure 8162306a36Sopenharmony_ci * @offset: additional offset to the register address 8262306a36Sopenharmony_ci * @pb_blocks: blocks array 8362306a36Sopenharmony_ci * @sgs_array: pb array 8462306a36Sopenharmony_ci * @array_size: blocks array size 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ciint hl_unsecure_register(struct hl_device *hdev, u32 mm_reg_addr, int offset, 8862306a36Sopenharmony_ci const u32 pb_blocks[], struct hl_block_glbl_sec sgs_array[], 8962306a36Sopenharmony_ci int array_size) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci u32 reg_offset; 9262306a36Sopenharmony_ci int block_num; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci block_num = hl_get_pb_block(hdev, mm_reg_addr + offset, pb_blocks, 9562306a36Sopenharmony_ci array_size); 9662306a36Sopenharmony_ci if (block_num < 0) 9762306a36Sopenharmony_ci return block_num; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci reg_offset = (mm_reg_addr + offset) - pb_blocks[block_num]; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return hl_unset_pb_in_block(hdev, reg_offset, &sgs_array[block_num]); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * hl_unsecure_register_range - locate the relevant block for this register 10662306a36Sopenharmony_ci * range and remove corresponding protection bit 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 10962306a36Sopenharmony_ci * @mm_reg_range: register address range to unsecure 11062306a36Sopenharmony_ci * @offset: additional offset to the register address 11162306a36Sopenharmony_ci * @pb_blocks: blocks array 11262306a36Sopenharmony_ci * @sgs_array: pb array 11362306a36Sopenharmony_ci * @array_size: blocks array size 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic int hl_unsecure_register_range(struct hl_device *hdev, 11762306a36Sopenharmony_ci struct range mm_reg_range, int offset, const u32 pb_blocks[], 11862306a36Sopenharmony_ci struct hl_block_glbl_sec sgs_array[], 11962306a36Sopenharmony_ci int array_size) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci u32 reg_offset; 12262306a36Sopenharmony_ci int i, block_num, rc = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci block_num = hl_get_pb_block(hdev, 12562306a36Sopenharmony_ci mm_reg_range.start + offset, pb_blocks, 12662306a36Sopenharmony_ci array_size); 12762306a36Sopenharmony_ci if (block_num < 0) 12862306a36Sopenharmony_ci return block_num; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci for (i = mm_reg_range.start ; i <= mm_reg_range.end ; i += 4) { 13162306a36Sopenharmony_ci reg_offset = (i + offset) - pb_blocks[block_num]; 13262306a36Sopenharmony_ci rc |= hl_unset_pb_in_block(hdev, reg_offset, 13362306a36Sopenharmony_ci &sgs_array[block_num]); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return rc; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * hl_unsecure_registers - locate the relevant block for all registers and 14162306a36Sopenharmony_ci * remove corresponding protection bit 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 14462306a36Sopenharmony_ci * @mm_reg_array: register address array to unsecure 14562306a36Sopenharmony_ci * @mm_array_size: register array size 14662306a36Sopenharmony_ci * @offset: additional offset to the register address 14762306a36Sopenharmony_ci * @pb_blocks: blocks array 14862306a36Sopenharmony_ci * @sgs_array: pb array 14962306a36Sopenharmony_ci * @blocks_array_size: blocks array size 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ciint hl_unsecure_registers(struct hl_device *hdev, const u32 mm_reg_array[], 15362306a36Sopenharmony_ci int mm_array_size, int offset, const u32 pb_blocks[], 15462306a36Sopenharmony_ci struct hl_block_glbl_sec sgs_array[], int blocks_array_size) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci int i, rc = 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci for (i = 0 ; i < mm_array_size ; i++) { 15962306a36Sopenharmony_ci rc = hl_unsecure_register(hdev, mm_reg_array[i], offset, 16062306a36Sopenharmony_ci pb_blocks, sgs_array, blocks_array_size); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (rc) 16362306a36Sopenharmony_ci return rc; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return rc; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * hl_unsecure_registers_range - locate the relevant block for all register 17162306a36Sopenharmony_ci * ranges and remove corresponding protection bit 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 17462306a36Sopenharmony_ci * @mm_reg_range_array: register address range array to unsecure 17562306a36Sopenharmony_ci * @mm_array_size: register array size 17662306a36Sopenharmony_ci * @offset: additional offset to the register address 17762306a36Sopenharmony_ci * @pb_blocks: blocks array 17862306a36Sopenharmony_ci * @sgs_array: pb array 17962306a36Sopenharmony_ci * @blocks_array_size: blocks array size 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_cistatic int hl_unsecure_registers_range(struct hl_device *hdev, 18362306a36Sopenharmony_ci const struct range mm_reg_range_array[], int mm_array_size, 18462306a36Sopenharmony_ci int offset, const u32 pb_blocks[], 18562306a36Sopenharmony_ci struct hl_block_glbl_sec sgs_array[], int blocks_array_size) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci int i, rc = 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0 ; i < mm_array_size ; i++) { 19062306a36Sopenharmony_ci rc = hl_unsecure_register_range(hdev, mm_reg_range_array[i], 19162306a36Sopenharmony_ci offset, pb_blocks, sgs_array, blocks_array_size); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (rc) 19462306a36Sopenharmony_ci return rc; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return rc; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/** 20162306a36Sopenharmony_ci * hl_ack_pb_security_violations - Ack security violation 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 20462306a36Sopenharmony_ci * @pb_blocks: blocks array 20562306a36Sopenharmony_ci * @block_offset: additional offset to the block 20662306a36Sopenharmony_ci * @array_size: blocks array size 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic void hl_ack_pb_security_violations(struct hl_device *hdev, 21062306a36Sopenharmony_ci const u32 pb_blocks[], u32 block_offset, int array_size) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci int i; 21362306a36Sopenharmony_ci u32 cause, addr, block_base; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci for (i = 0 ; i < array_size ; i++) { 21662306a36Sopenharmony_ci block_base = pb_blocks[i] + block_offset; 21762306a36Sopenharmony_ci cause = RREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE); 21862306a36Sopenharmony_ci if (cause) { 21962306a36Sopenharmony_ci addr = RREG32(block_base + HL_BLOCK_GLBL_ERR_ADDR); 22062306a36Sopenharmony_ci hdev->asic_funcs->pb_print_security_errors(hdev, 22162306a36Sopenharmony_ci block_base, cause, addr); 22262306a36Sopenharmony_ci WREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE, cause); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * hl_config_glbl_sec - set pb in HW according to given pb array 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 23162306a36Sopenharmony_ci * @pb_blocks: blocks array 23262306a36Sopenharmony_ci * @sgs_array: pb array 23362306a36Sopenharmony_ci * @block_offset: additional offset to the block 23462306a36Sopenharmony_ci * @array_size: blocks array size 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_civoid hl_config_glbl_sec(struct hl_device *hdev, const u32 pb_blocks[], 23862306a36Sopenharmony_ci struct hl_block_glbl_sec sgs_array[], u32 block_offset, 23962306a36Sopenharmony_ci int array_size) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci int i, j; 24262306a36Sopenharmony_ci u32 sgs_base; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (hdev->pldm) 24562306a36Sopenharmony_ci usleep_range(100, 1000); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci for (i = 0 ; i < array_size ; i++) { 24862306a36Sopenharmony_ci sgs_base = block_offset + pb_blocks[i] + 24962306a36Sopenharmony_ci HL_BLOCK_GLBL_SEC_OFFS; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci for (j = 0 ; j < HL_BLOCK_GLBL_SEC_LEN ; j++) 25262306a36Sopenharmony_ci WREG32(sgs_base + j * sizeof(u32), 25362306a36Sopenharmony_ci sgs_array[i].sec_array[j]); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * hl_secure_block - locally memsets a block to 0 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 26162306a36Sopenharmony_ci * @sgs_array: pb array to clear 26262306a36Sopenharmony_ci * @array_size: blocks array size 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_civoid hl_secure_block(struct hl_device *hdev, 26662306a36Sopenharmony_ci struct hl_block_glbl_sec sgs_array[], int array_size) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int i; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci for (i = 0 ; i < array_size ; i++) 27162306a36Sopenharmony_ci memset((char *)(sgs_array[i].sec_array), 0, 27262306a36Sopenharmony_ci HL_BLOCK_GLBL_SEC_SIZE); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/** 27662306a36Sopenharmony_ci * hl_init_pb_with_mask - set selected pb instances with mask in HW according 27762306a36Sopenharmony_ci * to given configuration 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 28062306a36Sopenharmony_ci * @num_dcores: number of decores to apply configuration to 28162306a36Sopenharmony_ci * set to HL_PB_SHARED if need to apply only once 28262306a36Sopenharmony_ci * @dcore_offset: offset between dcores 28362306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 28462306a36Sopenharmony_ci * @instance_offset: offset between instances 28562306a36Sopenharmony_ci * @pb_blocks: blocks array 28662306a36Sopenharmony_ci * @blocks_array_size: blocks array size 28762306a36Sopenharmony_ci * @user_regs_array: unsecured register array 28862306a36Sopenharmony_ci * @user_regs_array_size: unsecured register array size 28962306a36Sopenharmony_ci * @mask: enabled instances mask: 1- enabled, 0- disabled 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ciint hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores, 29262306a36Sopenharmony_ci u32 dcore_offset, u32 num_instances, u32 instance_offset, 29362306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, 29462306a36Sopenharmony_ci const u32 *user_regs_array, u32 user_regs_array_size, u64 mask) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci int i, j; 29762306a36Sopenharmony_ci struct hl_block_glbl_sec *glbl_sec; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci glbl_sec = kcalloc(blocks_array_size, 30062306a36Sopenharmony_ci sizeof(struct hl_block_glbl_sec), 30162306a36Sopenharmony_ci GFP_KERNEL); 30262306a36Sopenharmony_ci if (!glbl_sec) 30362306a36Sopenharmony_ci return -ENOMEM; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci hl_secure_block(hdev, glbl_sec, blocks_array_size); 30662306a36Sopenharmony_ci hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 0, 30762306a36Sopenharmony_ci pb_blocks, glbl_sec, blocks_array_size); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Fill all blocks with the same configuration */ 31062306a36Sopenharmony_ci for (i = 0 ; i < num_dcores ; i++) { 31162306a36Sopenharmony_ci for (j = 0 ; j < num_instances ; j++) { 31262306a36Sopenharmony_ci int seq = i * num_instances + j; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!(mask & BIT_ULL(seq))) 31562306a36Sopenharmony_ci continue; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 31862306a36Sopenharmony_ci i * dcore_offset + j * instance_offset, 31962306a36Sopenharmony_ci blocks_array_size); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci kfree(glbl_sec); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/** 32962306a36Sopenharmony_ci * hl_init_pb - set pb in HW according to given configuration 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 33262306a36Sopenharmony_ci * @num_dcores: number of decores to apply configuration to 33362306a36Sopenharmony_ci * set to HL_PB_SHARED if need to apply only once 33462306a36Sopenharmony_ci * @dcore_offset: offset between dcores 33562306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 33662306a36Sopenharmony_ci * @instance_offset: offset between instances 33762306a36Sopenharmony_ci * @pb_blocks: blocks array 33862306a36Sopenharmony_ci * @blocks_array_size: blocks array size 33962306a36Sopenharmony_ci * @user_regs_array: unsecured register array 34062306a36Sopenharmony_ci * @user_regs_array_size: unsecured register array size 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ciint hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, 34462306a36Sopenharmony_ci u32 num_instances, u32 instance_offset, 34562306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, 34662306a36Sopenharmony_ci const u32 *user_regs_array, u32 user_regs_array_size) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci return hl_init_pb_with_mask(hdev, num_dcores, dcore_offset, 34962306a36Sopenharmony_ci num_instances, instance_offset, pb_blocks, 35062306a36Sopenharmony_ci blocks_array_size, user_regs_array, 35162306a36Sopenharmony_ci user_regs_array_size, ULLONG_MAX); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/** 35562306a36Sopenharmony_ci * hl_init_pb_ranges_with_mask - set pb instances using mask in HW according to 35662306a36Sopenharmony_ci * given configuration unsecurring registers 35762306a36Sopenharmony_ci * ranges instead of specific registers 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 36062306a36Sopenharmony_ci * @num_dcores: number of decores to apply configuration to 36162306a36Sopenharmony_ci * set to HL_PB_SHARED if need to apply only once 36262306a36Sopenharmony_ci * @dcore_offset: offset between dcores 36362306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 36462306a36Sopenharmony_ci * @instance_offset: offset between instances 36562306a36Sopenharmony_ci * @pb_blocks: blocks array 36662306a36Sopenharmony_ci * @blocks_array_size: blocks array size 36762306a36Sopenharmony_ci * @user_regs_range_array: unsecured register range array 36862306a36Sopenharmony_ci * @user_regs_range_array_size: unsecured register range array size 36962306a36Sopenharmony_ci * @mask: enabled instances mask: 1- enabled, 0- disabled 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ciint hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores, 37262306a36Sopenharmony_ci u32 dcore_offset, u32 num_instances, u32 instance_offset, 37362306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, 37462306a36Sopenharmony_ci const struct range *user_regs_range_array, 37562306a36Sopenharmony_ci u32 user_regs_range_array_size, u64 mask) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci int i, j, rc = 0; 37862306a36Sopenharmony_ci struct hl_block_glbl_sec *glbl_sec; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci glbl_sec = kcalloc(blocks_array_size, 38162306a36Sopenharmony_ci sizeof(struct hl_block_glbl_sec), 38262306a36Sopenharmony_ci GFP_KERNEL); 38362306a36Sopenharmony_ci if (!glbl_sec) 38462306a36Sopenharmony_ci return -ENOMEM; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci hl_secure_block(hdev, glbl_sec, blocks_array_size); 38762306a36Sopenharmony_ci rc = hl_unsecure_registers_range(hdev, user_regs_range_array, 38862306a36Sopenharmony_ci user_regs_range_array_size, 0, pb_blocks, glbl_sec, 38962306a36Sopenharmony_ci blocks_array_size); 39062306a36Sopenharmony_ci if (rc) 39162306a36Sopenharmony_ci goto free_glbl_sec; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Fill all blocks with the same configuration */ 39462306a36Sopenharmony_ci for (i = 0 ; i < num_dcores ; i++) { 39562306a36Sopenharmony_ci for (j = 0 ; j < num_instances ; j++) { 39662306a36Sopenharmony_ci int seq = i * num_instances + j; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (!(mask & BIT_ULL(seq))) 39962306a36Sopenharmony_ci continue; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 40262306a36Sopenharmony_ci i * dcore_offset + j * instance_offset, 40362306a36Sopenharmony_ci blocks_array_size); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cifree_glbl_sec: 40862306a36Sopenharmony_ci kfree(glbl_sec); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return rc; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/** 41462306a36Sopenharmony_ci * hl_init_pb_ranges - set pb in HW according to given configuration unsecurring 41562306a36Sopenharmony_ci * registers ranges instead of specific registers 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 41862306a36Sopenharmony_ci * @num_dcores: number of decores to apply configuration to 41962306a36Sopenharmony_ci * set to HL_PB_SHARED if need to apply only once 42062306a36Sopenharmony_ci * @dcore_offset: offset between dcores 42162306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 42262306a36Sopenharmony_ci * @instance_offset: offset between instances 42362306a36Sopenharmony_ci * @pb_blocks: blocks array 42462306a36Sopenharmony_ci * @blocks_array_size: blocks array size 42562306a36Sopenharmony_ci * @user_regs_range_array: unsecured register range array 42662306a36Sopenharmony_ci * @user_regs_range_array_size: unsecured register range array size 42762306a36Sopenharmony_ci * 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ciint hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores, 43062306a36Sopenharmony_ci u32 dcore_offset, u32 num_instances, u32 instance_offset, 43162306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, 43262306a36Sopenharmony_ci const struct range *user_regs_range_array, 43362306a36Sopenharmony_ci u32 user_regs_range_array_size) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset, 43662306a36Sopenharmony_ci num_instances, instance_offset, pb_blocks, 43762306a36Sopenharmony_ci blocks_array_size, user_regs_range_array, 43862306a36Sopenharmony_ci user_regs_range_array_size, ULLONG_MAX); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/** 44262306a36Sopenharmony_ci * hl_init_pb_single_dcore - set pb for a single docre in HW 44362306a36Sopenharmony_ci * according to given configuration 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 44662306a36Sopenharmony_ci * @dcore_offset: offset from the dcore0 44762306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 44862306a36Sopenharmony_ci * @instance_offset: offset between instances 44962306a36Sopenharmony_ci * @pb_blocks: blocks array 45062306a36Sopenharmony_ci * @blocks_array_size: blocks array size 45162306a36Sopenharmony_ci * @user_regs_array: unsecured register array 45262306a36Sopenharmony_ci * @user_regs_array_size: unsecured register array size 45362306a36Sopenharmony_ci * 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ciint hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, 45662306a36Sopenharmony_ci u32 num_instances, u32 instance_offset, 45762306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, 45862306a36Sopenharmony_ci const u32 *user_regs_array, u32 user_regs_array_size) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci int i, rc = 0; 46162306a36Sopenharmony_ci struct hl_block_glbl_sec *glbl_sec; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci glbl_sec = kcalloc(blocks_array_size, 46462306a36Sopenharmony_ci sizeof(struct hl_block_glbl_sec), 46562306a36Sopenharmony_ci GFP_KERNEL); 46662306a36Sopenharmony_ci if (!glbl_sec) 46762306a36Sopenharmony_ci return -ENOMEM; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci hl_secure_block(hdev, glbl_sec, blocks_array_size); 47062306a36Sopenharmony_ci rc = hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 47162306a36Sopenharmony_ci 0, pb_blocks, glbl_sec, blocks_array_size); 47262306a36Sopenharmony_ci if (rc) 47362306a36Sopenharmony_ci goto free_glbl_sec; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Fill all blocks with the same configuration */ 47662306a36Sopenharmony_ci for (i = 0 ; i < num_instances ; i++) 47762306a36Sopenharmony_ci hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 47862306a36Sopenharmony_ci dcore_offset + i * instance_offset, 47962306a36Sopenharmony_ci blocks_array_size); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cifree_glbl_sec: 48262306a36Sopenharmony_ci kfree(glbl_sec); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return rc; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/** 48862306a36Sopenharmony_ci * hl_init_pb_ranges_single_dcore - set pb for a single docre in HW according 48962306a36Sopenharmony_ci * to given configuration unsecurring 49062306a36Sopenharmony_ci * registers ranges instead of specific 49162306a36Sopenharmony_ci * registers 49262306a36Sopenharmony_ci * 49362306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 49462306a36Sopenharmony_ci * @dcore_offset: offset from the dcore0 49562306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 49662306a36Sopenharmony_ci * @instance_offset: offset between instances 49762306a36Sopenharmony_ci * @pb_blocks: blocks array 49862306a36Sopenharmony_ci * @blocks_array_size: blocks array size 49962306a36Sopenharmony_ci * @user_regs_range_array: unsecured register range array 50062306a36Sopenharmony_ci * @user_regs_range_array_size: unsecured register range array size 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ciint hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset, 50462306a36Sopenharmony_ci u32 num_instances, u32 instance_offset, 50562306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, 50662306a36Sopenharmony_ci const struct range *user_regs_range_array, u32 user_regs_range_array_size) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci int i; 50962306a36Sopenharmony_ci struct hl_block_glbl_sec *glbl_sec; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci glbl_sec = kcalloc(blocks_array_size, 51262306a36Sopenharmony_ci sizeof(struct hl_block_glbl_sec), 51362306a36Sopenharmony_ci GFP_KERNEL); 51462306a36Sopenharmony_ci if (!glbl_sec) 51562306a36Sopenharmony_ci return -ENOMEM; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci hl_secure_block(hdev, glbl_sec, blocks_array_size); 51862306a36Sopenharmony_ci hl_unsecure_registers_range(hdev, user_regs_range_array, 51962306a36Sopenharmony_ci user_regs_range_array_size, 0, pb_blocks, glbl_sec, 52062306a36Sopenharmony_ci blocks_array_size); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Fill all blocks with the same configuration */ 52362306a36Sopenharmony_ci for (i = 0 ; i < num_instances ; i++) 52462306a36Sopenharmony_ci hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 52562306a36Sopenharmony_ci dcore_offset + i * instance_offset, 52662306a36Sopenharmony_ci blocks_array_size); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci kfree(glbl_sec); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/** 53462306a36Sopenharmony_ci * hl_ack_pb_with_mask - ack pb with mask in HW according to given configuration 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 53762306a36Sopenharmony_ci * @num_dcores: number of decores to apply configuration to 53862306a36Sopenharmony_ci * set to HL_PB_SHARED if need to apply only once 53962306a36Sopenharmony_ci * @dcore_offset: offset between dcores 54062306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 54162306a36Sopenharmony_ci * @instance_offset: offset between instances 54262306a36Sopenharmony_ci * @pb_blocks: blocks array 54362306a36Sopenharmony_ci * @blocks_array_size: blocks array size 54462306a36Sopenharmony_ci * @mask: enabled instances mask: 1- enabled, 0- disabled 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_civoid hl_ack_pb_with_mask(struct hl_device *hdev, u32 num_dcores, 54862306a36Sopenharmony_ci u32 dcore_offset, u32 num_instances, u32 instance_offset, 54962306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size, u64 mask) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci int i, j; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* ack all blocks */ 55462306a36Sopenharmony_ci for (i = 0 ; i < num_dcores ; i++) { 55562306a36Sopenharmony_ci for (j = 0 ; j < num_instances ; j++) { 55662306a36Sopenharmony_ci int seq = i * num_instances + j; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (!(mask & BIT_ULL(seq))) 55962306a36Sopenharmony_ci continue; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci hl_ack_pb_security_violations(hdev, pb_blocks, 56262306a36Sopenharmony_ci i * dcore_offset + j * instance_offset, 56362306a36Sopenharmony_ci blocks_array_size); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/** 56962306a36Sopenharmony_ci * hl_ack_pb - ack pb in HW according to given configuration 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 57262306a36Sopenharmony_ci * @num_dcores: number of decores to apply configuration to 57362306a36Sopenharmony_ci * set to HL_PB_SHARED if need to apply only once 57462306a36Sopenharmony_ci * @dcore_offset: offset between dcores 57562306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 57662306a36Sopenharmony_ci * @instance_offset: offset between instances 57762306a36Sopenharmony_ci * @pb_blocks: blocks array 57862306a36Sopenharmony_ci * @blocks_array_size: blocks array size 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_civoid hl_ack_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, 58262306a36Sopenharmony_ci u32 num_instances, u32 instance_offset, 58362306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci hl_ack_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances, 58662306a36Sopenharmony_ci instance_offset, pb_blocks, blocks_array_size, 58762306a36Sopenharmony_ci ULLONG_MAX); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci/** 59162306a36Sopenharmony_ci * hl_ack_pb_single_dcore - ack pb for single docre in HW 59262306a36Sopenharmony_ci * according to given configuration 59362306a36Sopenharmony_ci * 59462306a36Sopenharmony_ci * @hdev: pointer to hl_device structure 59562306a36Sopenharmony_ci * @dcore_offset: offset from dcore0 59662306a36Sopenharmony_ci * @num_instances: number of instances to apply configuration to 59762306a36Sopenharmony_ci * @instance_offset: offset between instances 59862306a36Sopenharmony_ci * @pb_blocks: blocks array 59962306a36Sopenharmony_ci * @blocks_array_size: blocks array size 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_civoid hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, 60362306a36Sopenharmony_ci u32 num_instances, u32 instance_offset, 60462306a36Sopenharmony_ci const u32 pb_blocks[], u32 blocks_array_size) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci int i; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* ack all blocks */ 60962306a36Sopenharmony_ci for (i = 0 ; i < num_instances ; i++) 61062306a36Sopenharmony_ci hl_ack_pb_security_violations(hdev, pb_blocks, 61162306a36Sopenharmony_ci dcore_offset + i * instance_offset, 61262306a36Sopenharmony_ci blocks_array_size); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic u32 hl_automated_get_block_base_addr(struct hl_device *hdev, 61762306a36Sopenharmony_ci struct hl_special_block_info *block_info, 61862306a36Sopenharmony_ci u32 major, u32 minor, u32 sub_minor) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci u32 fw_block_base_address = block_info->base_addr + 62162306a36Sopenharmony_ci major * block_info->major_offset + 62262306a36Sopenharmony_ci minor * block_info->minor_offset + 62362306a36Sopenharmony_ci sub_minor * block_info->sub_minor_offset; 62462306a36Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* Calculation above returns an address for FW use, and therefore should 62762306a36Sopenharmony_ci * be casted for driver use. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci return (fw_block_base_address - lower_32_bits(prop->cfg_base_address)); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic bool hl_check_block_type_exclusion(struct hl_skip_blocks_cfg *skip_blocks_cfg, 63362306a36Sopenharmony_ci int block_type) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci int i; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Check if block type is listed in the exclusion list of block types */ 63862306a36Sopenharmony_ci for (i = 0 ; i < skip_blocks_cfg->block_types_len ; i++) 63962306a36Sopenharmony_ci if (block_type == skip_blocks_cfg->block_types[i]) 64062306a36Sopenharmony_ci return true; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci return false; 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic bool hl_check_block_range_exclusion(struct hl_device *hdev, 64662306a36Sopenharmony_ci struct hl_skip_blocks_cfg *skip_blocks_cfg, 64762306a36Sopenharmony_ci struct hl_special_block_info *block_info, 64862306a36Sopenharmony_ci u32 major, u32 minor, u32 sub_minor) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci u32 blocks_in_range, block_base_addr_in_range, block_base_addr; 65162306a36Sopenharmony_ci int i, j; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci block_base_addr = hl_automated_get_block_base_addr(hdev, block_info, 65462306a36Sopenharmony_ci major, minor, sub_minor); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci for (i = 0 ; i < skip_blocks_cfg->block_ranges_len ; i++) { 65762306a36Sopenharmony_ci blocks_in_range = (skip_blocks_cfg->block_ranges[i].end - 65862306a36Sopenharmony_ci skip_blocks_cfg->block_ranges[i].start) / 65962306a36Sopenharmony_ci HL_BLOCK_SIZE + 1; 66062306a36Sopenharmony_ci for (j = 0 ; j < blocks_in_range ; j++) { 66162306a36Sopenharmony_ci block_base_addr_in_range = skip_blocks_cfg->block_ranges[i].start + 66262306a36Sopenharmony_ci j * HL_BLOCK_SIZE; 66362306a36Sopenharmony_ci if (block_base_addr == block_base_addr_in_range) 66462306a36Sopenharmony_ci return true; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return false; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int hl_read_glbl_errors(struct hl_device *hdev, 67262306a36Sopenharmony_ci u32 blk_idx, u32 major, u32 minor, u32 sub_minor, void *data) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct hl_special_block_info *special_blocks = hdev->asic_prop.special_blocks; 67562306a36Sopenharmony_ci struct hl_special_block_info *current_block = &special_blocks[blk_idx]; 67662306a36Sopenharmony_ci u32 glbl_err_addr, glbl_err_cause, addr_val, cause_val, block_base, 67762306a36Sopenharmony_ci base = current_block->base_addr - lower_32_bits(hdev->asic_prop.cfg_base_address); 67862306a36Sopenharmony_ci int i; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci block_base = base + major * current_block->major_offset + 68162306a36Sopenharmony_ci minor * current_block->minor_offset + 68262306a36Sopenharmony_ci sub_minor * current_block->sub_minor_offset; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci glbl_err_cause = block_base + HL_GLBL_ERR_CAUSE_OFFSET; 68562306a36Sopenharmony_ci cause_val = RREG32(glbl_err_cause); 68662306a36Sopenharmony_ci if (!cause_val) 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci glbl_err_addr = block_base + HL_GLBL_ERR_ADDR_OFFSET; 69062306a36Sopenharmony_ci addr_val = RREG32(glbl_err_addr); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci for (i = 0 ; i < hdev->asic_prop.glbl_err_cause_num ; i++) { 69362306a36Sopenharmony_ci if (cause_val & BIT(i)) 69462306a36Sopenharmony_ci dev_err_ratelimited(hdev->dev, 69562306a36Sopenharmony_ci "%s, addr %#llx\n", 69662306a36Sopenharmony_ci hl_glbl_error_cause[i], 69762306a36Sopenharmony_ci hdev->asic_prop.cfg_base_address + block_base + 69862306a36Sopenharmony_ci FIELD_GET(HL_GLBL_ERR_ADDRESS_MASK, addr_val)); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci WREG32(glbl_err_cause, cause_val); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_civoid hl_check_for_glbl_errors(struct hl_device *hdev) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 70962306a36Sopenharmony_ci struct hl_special_blocks_cfg special_blocks_cfg; 71062306a36Sopenharmony_ci struct iterate_special_ctx glbl_err_iter; 71162306a36Sopenharmony_ci int rc; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci memset(&special_blocks_cfg, 0, sizeof(special_blocks_cfg)); 71462306a36Sopenharmony_ci special_blocks_cfg.skip_blocks_cfg = &prop->skip_special_blocks_cfg; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci glbl_err_iter.fn = &hl_read_glbl_errors; 71762306a36Sopenharmony_ci glbl_err_iter.data = &special_blocks_cfg; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci rc = hl_iterate_special_blocks(hdev, &glbl_err_iter); 72062306a36Sopenharmony_ci if (rc) 72162306a36Sopenharmony_ci dev_err_ratelimited(hdev->dev, 72262306a36Sopenharmony_ci "Could not iterate special blocks, glbl error check failed\n"); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ciint hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct hl_special_blocks_cfg *special_blocks_cfg = 72862306a36Sopenharmony_ci (struct hl_special_blocks_cfg *)ctx->data; 72962306a36Sopenharmony_ci struct hl_skip_blocks_cfg *skip_blocks_cfg = 73062306a36Sopenharmony_ci special_blocks_cfg->skip_blocks_cfg; 73162306a36Sopenharmony_ci u32 major, minor, sub_minor, blk_idx, num_blocks; 73262306a36Sopenharmony_ci struct hl_special_block_info *block_info_arr; 73362306a36Sopenharmony_ci int rc; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci block_info_arr = hdev->asic_prop.special_blocks; 73662306a36Sopenharmony_ci if (!block_info_arr) 73762306a36Sopenharmony_ci return -EINVAL; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci num_blocks = hdev->asic_prop.num_of_special_blocks; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci for (blk_idx = 0 ; blk_idx < num_blocks ; blk_idx++, block_info_arr++) { 74262306a36Sopenharmony_ci if (hl_check_block_type_exclusion(skip_blocks_cfg, block_info_arr->block_type)) 74362306a36Sopenharmony_ci continue; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci for (major = 0 ; major < block_info_arr->major ; major++) { 74662306a36Sopenharmony_ci minor = 0; 74762306a36Sopenharmony_ci do { 74862306a36Sopenharmony_ci sub_minor = 0; 74962306a36Sopenharmony_ci do { 75062306a36Sopenharmony_ci if ((hl_check_block_range_exclusion(hdev, 75162306a36Sopenharmony_ci skip_blocks_cfg, block_info_arr, 75262306a36Sopenharmony_ci major, minor, sub_minor)) || 75362306a36Sopenharmony_ci (skip_blocks_cfg->skip_block_hook && 75462306a36Sopenharmony_ci skip_blocks_cfg->skip_block_hook(hdev, 75562306a36Sopenharmony_ci special_blocks_cfg, 75662306a36Sopenharmony_ci blk_idx, major, minor, sub_minor))) { 75762306a36Sopenharmony_ci sub_minor++; 75862306a36Sopenharmony_ci continue; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci rc = ctx->fn(hdev, blk_idx, major, minor, 76262306a36Sopenharmony_ci sub_minor, ctx->data); 76362306a36Sopenharmony_ci if (rc) 76462306a36Sopenharmony_ci return rc; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci sub_minor++; 76762306a36Sopenharmony_ci } while (sub_minor < block_info_arr->sub_minor); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci minor++; 77062306a36Sopenharmony_ci } while (minor < block_info_arr->minor); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci} 776