brintos

brintos / linux-shallow public Read only

0
0
Text · 22.7 KiB · 5402a3c Raw
793 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Copyright 2020 HabanaLabs, Ltd.5 * All Rights Reserved.6 */7 8#include "habanalabs.h"9 10static const char * const hl_glbl_error_cause[] = {11	"Error due to un-priv read",12	"Error due to un-secure read",13	"Error due to read from unmapped reg",14	"Error due to un-priv write",15	"Error due to un-secure write",16	"Error due to write to unmapped reg",17	"N/A",18	"N/A",19	"N/A",20	"N/A",21	"N/A",22	"N/A",23	"N/A",24	"N/A",25	"N/A",26	"N/A",27	"External I/F write sec violation",28	"External I/F write to un-mapped reg",29	"N/A",30	"N/A",31	"N/A",32	"N/A",33	"N/A",34	"N/A",35	"Read to write only",36	"Write to read only"37};38 39/**40 * hl_get_pb_block - return the relevant block within the block array41 *42 * @hdev: pointer to hl_device structure43 * @mm_reg_addr: register address in the desired block44 * @pb_blocks: blocks array45 * @array_size: blocks array size46 *47 */48static int hl_get_pb_block(struct hl_device *hdev, u32 mm_reg_addr,49		const u32 pb_blocks[], int array_size)50{51	int i;52	u32 start_addr, end_addr;53 54	for (i = 0 ; i < array_size ; i++) {55		start_addr = pb_blocks[i];56		end_addr = start_addr + HL_BLOCK_SIZE;57 58		if ((mm_reg_addr >= start_addr) && (mm_reg_addr < end_addr))59			return i;60	}61 62	dev_err(hdev->dev, "No protection domain was found for 0x%x\n",63			mm_reg_addr);64	return -EDOM;65}66 67/**68 * hl_unset_pb_in_block - clear a specific protection bit in a block69 *70 * @hdev: pointer to hl_device structure71 * @reg_offset: register offset will be converted to bit offset in pb block72 * @sgs_entry: pb array73 *74 */75static int hl_unset_pb_in_block(struct hl_device *hdev, u32 reg_offset,76				struct hl_block_glbl_sec *sgs_entry)77{78	if ((reg_offset >= HL_BLOCK_SIZE) || (reg_offset & 0x3)) {79		dev_err(hdev->dev,80			"Register offset(%d) is out of range(%d) or invalid\n",81			reg_offset, HL_BLOCK_SIZE);82		return -EINVAL;83	}84 85	UNSET_GLBL_SEC_BIT(sgs_entry->sec_array,86			 (reg_offset & (HL_BLOCK_SIZE - 1)) >> 2);87 88	return 0;89}90 91/**92 * hl_unsecure_register - locate the relevant block for this register and93 *                        remove corresponding protection bit94 *95 * @hdev: pointer to hl_device structure96 * @mm_reg_addr: register address to unsecure97 * @offset: additional offset to the register address98 * @pb_blocks: blocks array99 * @sgs_array: pb array100 * @array_size: blocks array size101 *102 */103int hl_unsecure_register(struct hl_device *hdev, u32 mm_reg_addr, int offset,104		const u32 pb_blocks[], struct hl_block_glbl_sec sgs_array[],105		int array_size)106{107	u32 reg_offset;108	int block_num;109 110	block_num = hl_get_pb_block(hdev, mm_reg_addr + offset, pb_blocks,111			array_size);112	if (block_num < 0)113		return block_num;114 115	reg_offset = (mm_reg_addr + offset) - pb_blocks[block_num];116 117	return hl_unset_pb_in_block(hdev, reg_offset, &sgs_array[block_num]);118}119 120/**121 * hl_unsecure_register_range - locate the relevant block for this register122 *                              range and remove corresponding protection bit123 *124 * @hdev: pointer to hl_device structure125 * @mm_reg_range: register address range to unsecure126 * @offset: additional offset to the register address127 * @pb_blocks: blocks array128 * @sgs_array: pb array129 * @array_size: blocks array size130 *131 */132static int hl_unsecure_register_range(struct hl_device *hdev,133		struct range mm_reg_range, int offset, const u32 pb_blocks[],134		struct hl_block_glbl_sec sgs_array[],135		int array_size)136{137	u32 reg_offset;138	int i, block_num, rc = 0;139 140	block_num = hl_get_pb_block(hdev,141			mm_reg_range.start + offset, pb_blocks,142			array_size);143	if (block_num < 0)144		return block_num;145 146	for (i = mm_reg_range.start ; i <= mm_reg_range.end ; i += 4) {147		reg_offset = (i + offset) - pb_blocks[block_num];148		rc |= hl_unset_pb_in_block(hdev, reg_offset,149					&sgs_array[block_num]);150	}151 152	return rc;153}154 155/**156 * hl_unsecure_registers - locate the relevant block for all registers and157 *                        remove corresponding protection bit158 *159 * @hdev: pointer to hl_device structure160 * @mm_reg_array: register address array to unsecure161 * @mm_array_size: register array size162 * @offset: additional offset to the register address163 * @pb_blocks: blocks array164 * @sgs_array: pb array165 * @blocks_array_size: blocks array size166 *167 */168int hl_unsecure_registers(struct hl_device *hdev, const u32 mm_reg_array[],169		int mm_array_size, int offset, const u32 pb_blocks[],170		struct hl_block_glbl_sec sgs_array[], int blocks_array_size)171{172	int i, rc = 0;173 174	for (i = 0 ; i < mm_array_size ; i++) {175		rc = hl_unsecure_register(hdev, mm_reg_array[i], offset,176				pb_blocks, sgs_array, blocks_array_size);177 178		if (rc)179			return rc;180	}181 182	return rc;183}184 185/**186 * hl_unsecure_registers_range - locate the relevant block for all register187 *                        ranges and remove corresponding protection bit188 *189 * @hdev: pointer to hl_device structure190 * @mm_reg_range_array: register address range array to unsecure191 * @mm_array_size: register array size192 * @offset: additional offset to the register address193 * @pb_blocks: blocks array194 * @sgs_array: pb array195 * @blocks_array_size: blocks array size196 *197 */198static int hl_unsecure_registers_range(struct hl_device *hdev,199		const struct range mm_reg_range_array[], int mm_array_size,200		int offset, const u32 pb_blocks[],201		struct hl_block_glbl_sec sgs_array[], int blocks_array_size)202{203	int i, rc = 0;204 205	for (i = 0 ; i < mm_array_size ; i++) {206		rc = hl_unsecure_register_range(hdev, mm_reg_range_array[i],207			offset, pb_blocks, sgs_array, blocks_array_size);208 209		if (rc)210			return rc;211	}212 213	return rc;214}215 216/**217 * hl_ack_pb_security_violations - Ack security violation218 *219 * @hdev: pointer to hl_device structure220 * @pb_blocks: blocks array221 * @block_offset: additional offset to the block222 * @array_size: blocks array size223 *224 */225static void hl_ack_pb_security_violations(struct hl_device *hdev,226		const u32 pb_blocks[], u32 block_offset, int array_size)227{228	int i;229	u32 cause, addr, block_base;230 231	for (i = 0 ; i < array_size ; i++) {232		block_base = pb_blocks[i] + block_offset;233		cause = RREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE);234		if (cause) {235			addr = RREG32(block_base + HL_BLOCK_GLBL_ERR_ADDR);236			hdev->asic_funcs->pb_print_security_errors(hdev,237					block_base, cause, addr);238			WREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE, cause);239		}240	}241}242 243/**244 * hl_config_glbl_sec - set pb in HW according to given pb array245 *246 * @hdev: pointer to hl_device structure247 * @pb_blocks: blocks array248 * @sgs_array: pb array249 * @block_offset: additional offset to the block250 * @array_size: blocks array size251 *252 */253void hl_config_glbl_sec(struct hl_device *hdev, const u32 pb_blocks[],254		struct hl_block_glbl_sec sgs_array[], u32 block_offset,255		int array_size)256{257	int i, j;258	u32 sgs_base;259 260	if (hdev->pldm)261		usleep_range(100, 1000);262 263	for (i = 0 ; i < array_size ; i++) {264		sgs_base = block_offset + pb_blocks[i] +265				HL_BLOCK_GLBL_SEC_OFFS;266 267		for (j = 0 ; j < HL_BLOCK_GLBL_SEC_LEN ; j++)268			WREG32(sgs_base + j * sizeof(u32),269				sgs_array[i].sec_array[j]);270	}271}272 273/**274 * hl_secure_block - locally memsets a block to 0275 *276 * @hdev: pointer to hl_device structure277 * @sgs_array: pb array to clear278 * @array_size: blocks array size279 *280 */281void hl_secure_block(struct hl_device *hdev,282		struct hl_block_glbl_sec sgs_array[], int array_size)283{284	int i;285 286	for (i = 0 ; i < array_size ; i++)287		memset((char *)(sgs_array[i].sec_array), 0,288			HL_BLOCK_GLBL_SEC_SIZE);289}290 291/**292 * hl_init_pb_with_mask - set selected pb instances with mask in HW according293 *                        to given configuration294 *295 * @hdev: pointer to hl_device structure296 * @num_dcores: number of decores to apply configuration to297 *              set to HL_PB_SHARED if need to apply only once298 * @dcore_offset: offset between dcores299 * @num_instances: number of instances to apply configuration to300 * @instance_offset: offset between instances301 * @pb_blocks: blocks array302 * @blocks_array_size: blocks array size303 * @user_regs_array: unsecured register array304 * @user_regs_array_size: unsecured register array size305 * @mask: enabled instances mask: 1- enabled, 0- disabled306 */307int hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores,308		u32 dcore_offset, u32 num_instances, u32 instance_offset,309		const u32 pb_blocks[], u32 blocks_array_size,310		const u32 *user_regs_array, u32 user_regs_array_size, u64 mask)311{312	int i, j;313	struct hl_block_glbl_sec *glbl_sec;314 315	glbl_sec = kcalloc(blocks_array_size,316			sizeof(struct hl_block_glbl_sec),317			GFP_KERNEL);318	if (!glbl_sec)319		return -ENOMEM;320 321	hl_secure_block(hdev, glbl_sec, blocks_array_size);322	hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 0,323			pb_blocks, glbl_sec, blocks_array_size);324 325	/* Fill all blocks with the same configuration */326	for (i = 0 ; i < num_dcores ; i++) {327		for (j = 0 ; j < num_instances ; j++) {328			int seq = i * num_instances + j;329 330			if (!(mask & BIT_ULL(seq)))331				continue;332 333			hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,334					i * dcore_offset + j * instance_offset,335					blocks_array_size);336		}337	}338 339	kfree(glbl_sec);340 341	return 0;342}343 344/**345 * hl_init_pb - set pb in HW according to given configuration346 *347 * @hdev: pointer to hl_device structure348 * @num_dcores: number of decores to apply configuration to349 *              set to HL_PB_SHARED if need to apply only once350 * @dcore_offset: offset between dcores351 * @num_instances: number of instances to apply configuration to352 * @instance_offset: offset between instances353 * @pb_blocks: blocks array354 * @blocks_array_size: blocks array size355 * @user_regs_array: unsecured register array356 * @user_regs_array_size: unsecured register array size357 *358 */359int hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset,360		u32 num_instances, u32 instance_offset,361		const u32 pb_blocks[], u32 blocks_array_size,362		const u32 *user_regs_array, u32 user_regs_array_size)363{364	return hl_init_pb_with_mask(hdev, num_dcores, dcore_offset,365			num_instances, instance_offset, pb_blocks,366			blocks_array_size, user_regs_array,367			user_regs_array_size, ULLONG_MAX);368}369 370/**371 * hl_init_pb_ranges_with_mask - set pb instances using mask in HW according to372 *                               given configuration unsecurring registers373 *                               ranges instead of specific registers374 *375 * @hdev: pointer to hl_device structure376 * @num_dcores: number of decores to apply configuration to377 *              set to HL_PB_SHARED if need to apply only once378 * @dcore_offset: offset between dcores379 * @num_instances: number of instances to apply configuration to380 * @instance_offset: offset between instances381 * @pb_blocks: blocks array382 * @blocks_array_size: blocks array size383 * @user_regs_range_array: unsecured register range array384 * @user_regs_range_array_size: unsecured register range array size385 * @mask: enabled instances mask: 1- enabled, 0- disabled386 */387int hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores,388		u32 dcore_offset, u32 num_instances, u32 instance_offset,389		const u32 pb_blocks[], u32 blocks_array_size,390		const struct range *user_regs_range_array,391		u32 user_regs_range_array_size, u64 mask)392{393	int i, j, rc = 0;394	struct hl_block_glbl_sec *glbl_sec;395 396	glbl_sec = kcalloc(blocks_array_size,397			sizeof(struct hl_block_glbl_sec),398			GFP_KERNEL);399	if (!glbl_sec)400		return -ENOMEM;401 402	hl_secure_block(hdev, glbl_sec, blocks_array_size);403	rc = hl_unsecure_registers_range(hdev, user_regs_range_array,404			user_regs_range_array_size, 0, pb_blocks, glbl_sec,405			blocks_array_size);406	if (rc)407		goto free_glbl_sec;408 409	/* Fill all blocks with the same configuration */410	for (i = 0 ; i < num_dcores ; i++) {411		for (j = 0 ; j < num_instances ; j++) {412			int seq = i * num_instances + j;413 414			if (!(mask & BIT_ULL(seq)))415				continue;416 417			hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,418					i * dcore_offset + j * instance_offset,419					blocks_array_size);420		}421	}422 423free_glbl_sec:424	kfree(glbl_sec);425 426	return rc;427}428 429/**430 * hl_init_pb_ranges - set pb in HW according to given configuration unsecurring431 *                     registers ranges instead of specific registers432 *433 * @hdev: pointer to hl_device structure434 * @num_dcores: number of decores to apply configuration to435 *              set to HL_PB_SHARED if need to apply only once436 * @dcore_offset: offset between dcores437 * @num_instances: number of instances to apply configuration to438 * @instance_offset: offset between instances439 * @pb_blocks: blocks array440 * @blocks_array_size: blocks array size441 * @user_regs_range_array: unsecured register range array442 * @user_regs_range_array_size: unsecured register range array size443 *444 */445int hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores,446		u32 dcore_offset, u32 num_instances, u32 instance_offset,447		const u32 pb_blocks[], u32 blocks_array_size,448		const struct range *user_regs_range_array,449		u32 user_regs_range_array_size)450{451	return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset,452			num_instances, instance_offset, pb_blocks,453			blocks_array_size, user_regs_range_array,454			user_regs_range_array_size, ULLONG_MAX);455}456 457/**458 * hl_init_pb_single_dcore - set pb for a single docre in HW459 * according to given configuration460 *461 * @hdev: pointer to hl_device structure462 * @dcore_offset: offset from the dcore0463 * @num_instances: number of instances to apply configuration to464 * @instance_offset: offset between instances465 * @pb_blocks: blocks array466 * @blocks_array_size: blocks array size467 * @user_regs_array: unsecured register array468 * @user_regs_array_size: unsecured register array size469 *470 */471int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,472		u32 num_instances, u32 instance_offset,473		const u32 pb_blocks[], u32 blocks_array_size,474		const u32 *user_regs_array, u32 user_regs_array_size)475{476	int i, rc = 0;477	struct hl_block_glbl_sec *glbl_sec;478 479	glbl_sec = kcalloc(blocks_array_size,480			sizeof(struct hl_block_glbl_sec),481			GFP_KERNEL);482	if (!glbl_sec)483		return -ENOMEM;484 485	hl_secure_block(hdev, glbl_sec, blocks_array_size);486	rc = hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size,487			0, pb_blocks, glbl_sec, blocks_array_size);488	if (rc)489		goto free_glbl_sec;490 491	/* Fill all blocks with the same configuration */492	for (i = 0 ; i < num_instances ; i++)493		hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,494				dcore_offset + i * instance_offset,495				blocks_array_size);496 497free_glbl_sec:498	kfree(glbl_sec);499 500	return rc;501}502 503/**504 * hl_init_pb_ranges_single_dcore - set pb for a single docre in HW according505 *                                  to given configuration unsecurring506 *                                  registers ranges instead of specific507 *                                  registers508 *509 * @hdev: pointer to hl_device structure510 * @dcore_offset: offset from the dcore0511 * @num_instances: number of instances to apply configuration to512 * @instance_offset: offset between instances513 * @pb_blocks: blocks array514 * @blocks_array_size: blocks array size515 * @user_regs_range_array: unsecured register range array516 * @user_regs_range_array_size: unsecured register range array size517 *518 */519int hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset,520		u32 num_instances, u32 instance_offset,521		const u32 pb_blocks[], u32 blocks_array_size,522		const struct range *user_regs_range_array, u32 user_regs_range_array_size)523{524	int i;525	struct hl_block_glbl_sec *glbl_sec;526 527	glbl_sec = kcalloc(blocks_array_size,528			sizeof(struct hl_block_glbl_sec),529			GFP_KERNEL);530	if (!glbl_sec)531		return -ENOMEM;532 533	hl_secure_block(hdev, glbl_sec, blocks_array_size);534	hl_unsecure_registers_range(hdev, user_regs_range_array,535			user_regs_range_array_size, 0, pb_blocks, glbl_sec,536			blocks_array_size);537 538	/* Fill all blocks with the same configuration */539	for (i = 0 ; i < num_instances ; i++)540		hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,541				dcore_offset + i * instance_offset,542				blocks_array_size);543 544	kfree(glbl_sec);545 546	return 0;547}548 549/**550 * hl_ack_pb_with_mask - ack pb with mask in HW according to given configuration551 *552 * @hdev: pointer to hl_device structure553 * @num_dcores: number of decores to apply configuration to554 *              set to HL_PB_SHARED if need to apply only once555 * @dcore_offset: offset between dcores556 * @num_instances: number of instances to apply configuration to557 * @instance_offset: offset between instances558 * @pb_blocks: blocks array559 * @blocks_array_size: blocks array size560 * @mask: enabled instances mask: 1- enabled, 0- disabled561 *562 */563void hl_ack_pb_with_mask(struct hl_device *hdev, u32 num_dcores,564		u32 dcore_offset, u32 num_instances, u32 instance_offset,565		const u32 pb_blocks[], u32 blocks_array_size, u64 mask)566{567	int i, j;568 569	/* ack all blocks */570	for (i = 0 ; i < num_dcores ; i++) {571		for (j = 0 ; j < num_instances ; j++) {572			int seq = i * num_instances + j;573 574			if (!(mask & BIT_ULL(seq)))575				continue;576 577			hl_ack_pb_security_violations(hdev, pb_blocks,578					i * dcore_offset + j * instance_offset,579					blocks_array_size);580		}581	}582}583 584/**585 * hl_ack_pb - ack pb in HW according to given configuration586 *587 * @hdev: pointer to hl_device structure588 * @num_dcores: number of decores to apply configuration to589 *              set to HL_PB_SHARED if need to apply only once590 * @dcore_offset: offset between dcores591 * @num_instances: number of instances to apply configuration to592 * @instance_offset: offset between instances593 * @pb_blocks: blocks array594 * @blocks_array_size: blocks array size595 *596 */597void hl_ack_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset,598		u32 num_instances, u32 instance_offset,599		const u32 pb_blocks[], u32 blocks_array_size)600{601	hl_ack_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances,602			instance_offset, pb_blocks, blocks_array_size,603			ULLONG_MAX);604}605 606/**607 * hl_ack_pb_single_dcore - ack pb for single docre in HW608 * according to given configuration609 *610 * @hdev: pointer to hl_device structure611 * @dcore_offset: offset from dcore0612 * @num_instances: number of instances to apply configuration to613 * @instance_offset: offset between instances614 * @pb_blocks: blocks array615 * @blocks_array_size: blocks array size616 *617 */618void hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,619		u32 num_instances, u32 instance_offset,620		const u32 pb_blocks[], u32 blocks_array_size)621{622	int i;623 624	/* ack all blocks */625	for (i = 0 ; i < num_instances ; i++)626		hl_ack_pb_security_violations(hdev, pb_blocks,627				dcore_offset + i * instance_offset,628				blocks_array_size);629 630}631 632static u32 hl_automated_get_block_base_addr(struct hl_device *hdev,633		struct hl_special_block_info *block_info,634		u32 major, u32 minor, u32 sub_minor)635{636	u32 fw_block_base_address = block_info->base_addr +637			major * block_info->major_offset +638			minor * block_info->minor_offset +639			sub_minor * block_info->sub_minor_offset;640	struct asic_fixed_properties *prop = &hdev->asic_prop;641 642	/* Calculation above returns an address for FW use, and therefore should643	 * be casted for driver use.644	 */645	return (fw_block_base_address - lower_32_bits(prop->cfg_base_address));646}647 648static bool hl_check_block_type_exclusion(struct hl_skip_blocks_cfg *skip_blocks_cfg,649		int block_type)650{651	int i;652 653	/* Check if block type is listed in the exclusion list of block types */654	for (i = 0 ; i < skip_blocks_cfg->block_types_len ; i++)655		if (block_type == skip_blocks_cfg->block_types[i])656			return true;657 658	return false;659}660 661static bool hl_check_block_range_exclusion(struct hl_device *hdev,662		struct hl_skip_blocks_cfg *skip_blocks_cfg,663		struct hl_special_block_info *block_info,664		u32 major, u32 minor, u32 sub_minor)665{666	u32 blocks_in_range, block_base_addr_in_range, block_base_addr;667	int i, j;668 669	block_base_addr = hl_automated_get_block_base_addr(hdev, block_info,670			major, minor, sub_minor);671 672	for (i = 0 ; i < skip_blocks_cfg->block_ranges_len ; i++) {673		blocks_in_range = (skip_blocks_cfg->block_ranges[i].end -674				skip_blocks_cfg->block_ranges[i].start) /675				HL_BLOCK_SIZE + 1;676		for (j = 0 ; j < blocks_in_range ; j++) {677			block_base_addr_in_range = skip_blocks_cfg->block_ranges[i].start +678					j * HL_BLOCK_SIZE;679			if (block_base_addr == block_base_addr_in_range)680				return true;681		}682	}683 684	return false;685}686 687static int hl_read_glbl_errors(struct hl_device *hdev,688		u32 blk_idx, u32 major, u32 minor, u32 sub_minor, void *data)689{690	struct asic_fixed_properties *prop = &hdev->asic_prop;691	struct hl_special_block_info *special_blocks = prop->special_blocks;692	struct hl_special_block_info *current_block = &special_blocks[blk_idx];693	u32 glbl_err_addr, glbl_err_cause, addr_val, cause_val, block_base,694		base = current_block->base_addr - lower_32_bits(prop->cfg_base_address);695	int i;696 697	block_base = base + major * current_block->major_offset +698			minor * current_block->minor_offset +699			sub_minor * current_block->sub_minor_offset;700 701	glbl_err_cause = block_base + HL_GLBL_ERR_CAUSE_OFFSET;702	cause_val = RREG32(glbl_err_cause);703	if (!cause_val)704		return 0;705 706	glbl_err_addr = block_base + HL_GLBL_ERR_ADDR_OFFSET;707	addr_val = RREG32(glbl_err_addr);708 709	for (i = 0 ; i <= prop->glbl_err_max_cause_num ; i++) {710		if (cause_val & BIT(i))711			dev_err_ratelimited(hdev->dev,712					"%s, addr %#llx\n",713					hl_glbl_error_cause[i],714					prop->cfg_base_address + block_base +715						FIELD_GET(HL_GLBL_ERR_ADDRESS_MASK, addr_val));716	}717 718	WREG32(glbl_err_cause, cause_val);719 720	return 0;721}722 723void hl_check_for_glbl_errors(struct hl_device *hdev)724{725	struct asic_fixed_properties *prop = &hdev->asic_prop;726	struct hl_special_blocks_cfg special_blocks_cfg;727	struct iterate_special_ctx glbl_err_iter;728	int rc;729 730	memset(&special_blocks_cfg, 0, sizeof(special_blocks_cfg));731	special_blocks_cfg.skip_blocks_cfg = &prop->skip_special_blocks_cfg;732 733	glbl_err_iter.fn = &hl_read_glbl_errors;734	glbl_err_iter.data = &special_blocks_cfg;735 736	rc = hl_iterate_special_blocks(hdev, &glbl_err_iter);737	if (rc)738		dev_err_ratelimited(hdev->dev,739			"Could not iterate special blocks, glbl error check failed\n");740}741 742int hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx)743{744	struct hl_special_blocks_cfg *special_blocks_cfg =745			(struct hl_special_blocks_cfg *)ctx->data;746	struct hl_skip_blocks_cfg *skip_blocks_cfg =747			special_blocks_cfg->skip_blocks_cfg;748	u32 major, minor, sub_minor, blk_idx, num_blocks;749	struct hl_special_block_info *block_info_arr;750	int rc;751 752	block_info_arr = hdev->asic_prop.special_blocks;753	if (!block_info_arr)754		return -EINVAL;755 756	num_blocks = hdev->asic_prop.num_of_special_blocks;757 758	for (blk_idx = 0 ; blk_idx < num_blocks ; blk_idx++, block_info_arr++) {759		if (hl_check_block_type_exclusion(skip_blocks_cfg, block_info_arr->block_type))760			continue;761 762		for (major = 0 ; major < block_info_arr->major ; major++) {763			minor = 0;764			do {765				sub_minor = 0;766				do {767					if ((hl_check_block_range_exclusion(hdev,768							skip_blocks_cfg, block_info_arr,769							major, minor, sub_minor)) ||770						(skip_blocks_cfg->skip_block_hook &&771						skip_blocks_cfg->skip_block_hook(hdev,772							special_blocks_cfg,773							blk_idx, major, minor, sub_minor))) {774						sub_minor++;775						continue;776					}777 778					rc = ctx->fn(hdev, blk_idx, major, minor,779								sub_minor, ctx->data);780					if (rc)781						return rc;782 783					sub_minor++;784				} while (sub_minor < block_info_arr->sub_minor);785 786				minor++;787			} while (minor < block_info_arr->minor);788		}789	}790 791	return 0;792}793