1 // SPDX-License-Identifier: GPL-2.0 2 3 /* 4 * Copyright 2020 HabanaLabs, Ltd. 5 * All Rights Reserved. 6 */ 7 8 #include "habanalabs.h" 9 10 static const char * const hl_glbl_error_cause[HL_MAX_NUM_OF_GLBL_ERR_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 "External I/F write sec violation", 18 "External I/F write to un-mapped reg", 19 "Read to write only", 20 "Write to read only" 21 }; 22 23 /** 24 * hl_get_pb_block - return the relevant block within the block array 25 * 26 * @hdev: pointer to hl_device structure 27 * @mm_reg_addr: register address in the desired block 28 * @pb_blocks: blocks array 29 * @array_size: blocks array size 30 * 31 */ 32 static int hl_get_pb_block(struct hl_device *hdev, u32 mm_reg_addr, 33 const u32 pb_blocks[], int array_size) 34 { 35 int i; 36 u32 start_addr, end_addr; 37 38 for (i = 0 ; i < array_size ; i++) { 39 start_addr = pb_blocks[i]; 40 end_addr = start_addr + HL_BLOCK_SIZE; 41 42 if ((mm_reg_addr >= start_addr) && (mm_reg_addr < end_addr)) 43 return i; 44 } 45 46 dev_err(hdev->dev, "No protection domain was found for 0x%x\n", 47 mm_reg_addr); 48 return -EDOM; 49 } 50 51 /** 52 * hl_unset_pb_in_block - clear a specific protection bit in a block 53 * 54 * @hdev: pointer to hl_device structure 55 * @reg_offset: register offset will be converted to bit offset in pb block 56 * @sgs_entry: pb array 57 * 58 */ 59 static int hl_unset_pb_in_block(struct hl_device *hdev, u32 reg_offset, 60 struct hl_block_glbl_sec *sgs_entry) 61 { 62 if ((reg_offset >= HL_BLOCK_SIZE) || (reg_offset & 0x3)) { 63 dev_err(hdev->dev, 64 "Register offset(%d) is out of range(%d) or invalid\n", 65 reg_offset, HL_BLOCK_SIZE); 66 return -EINVAL; 67 } 68 69 UNSET_GLBL_SEC_BIT(sgs_entry->sec_array, 70 (reg_offset & (HL_BLOCK_SIZE - 1)) >> 2); 71 72 return 0; 73 } 74 75 /** 76 * hl_unsecure_register - locate the relevant block for this register and 77 * remove corresponding protection bit 78 * 79 * @hdev: pointer to hl_device structure 80 * @mm_reg_addr: register address to unsecure 81 * @offset: additional offset to the register address 82 * @pb_blocks: blocks array 83 * @sgs_array: pb array 84 * @array_size: blocks array size 85 * 86 */ 87 int hl_unsecure_register(struct hl_device *hdev, u32 mm_reg_addr, int offset, 88 const u32 pb_blocks[], struct hl_block_glbl_sec sgs_array[], 89 int array_size) 90 { 91 u32 reg_offset; 92 int block_num; 93 94 block_num = hl_get_pb_block(hdev, mm_reg_addr + offset, pb_blocks, 95 array_size); 96 if (block_num < 0) 97 return block_num; 98 99 reg_offset = (mm_reg_addr + offset) - pb_blocks[block_num]; 100 101 return hl_unset_pb_in_block(hdev, reg_offset, &sgs_array[block_num]); 102 } 103 104 /** 105 * hl_unsecure_register_range - locate the relevant block for this register 106 * range and remove corresponding protection bit 107 * 108 * @hdev: pointer to hl_device structure 109 * @mm_reg_range: register address range to unsecure 110 * @offset: additional offset to the register address 111 * @pb_blocks: blocks array 112 * @sgs_array: pb array 113 * @array_size: blocks array size 114 * 115 */ 116 static int hl_unsecure_register_range(struct hl_device *hdev, 117 struct range mm_reg_range, int offset, const u32 pb_blocks[], 118 struct hl_block_glbl_sec sgs_array[], 119 int array_size) 120 { 121 u32 reg_offset; 122 int i, block_num, rc = 0; 123 124 block_num = hl_get_pb_block(hdev, 125 mm_reg_range.start + offset, pb_blocks, 126 array_size); 127 if (block_num < 0) 128 return block_num; 129 130 for (i = mm_reg_range.start ; i <= mm_reg_range.end ; i += 4) { 131 reg_offset = (i + offset) - pb_blocks[block_num]; 132 rc |= hl_unset_pb_in_block(hdev, reg_offset, 133 &sgs_array[block_num]); 134 } 135 136 return rc; 137 } 138 139 /** 140 * hl_unsecure_registers - locate the relevant block for all registers and 141 * remove corresponding protection bit 142 * 143 * @hdev: pointer to hl_device structure 144 * @mm_reg_array: register address array to unsecure 145 * @mm_array_size: register array size 146 * @offset: additional offset to the register address 147 * @pb_blocks: blocks array 148 * @sgs_array: pb array 149 * @blocks_array_size: blocks array size 150 * 151 */ 152 int hl_unsecure_registers(struct hl_device *hdev, const u32 mm_reg_array[], 153 int mm_array_size, int offset, const u32 pb_blocks[], 154 struct hl_block_glbl_sec sgs_array[], int blocks_array_size) 155 { 156 int i, rc = 0; 157 158 for (i = 0 ; i < mm_array_size ; i++) { 159 rc = hl_unsecure_register(hdev, mm_reg_array[i], offset, 160 pb_blocks, sgs_array, blocks_array_size); 161 162 if (rc) 163 return rc; 164 } 165 166 return rc; 167 } 168 169 /** 170 * hl_unsecure_registers_range - locate the relevant block for all register 171 * ranges and remove corresponding protection bit 172 * 173 * @hdev: pointer to hl_device structure 174 * @mm_reg_range_array: register address range array to unsecure 175 * @mm_array_size: register array size 176 * @offset: additional offset to the register address 177 * @pb_blocks: blocks array 178 * @sgs_array: pb array 179 * @blocks_array_size: blocks array size 180 * 181 */ 182 static int hl_unsecure_registers_range(struct hl_device *hdev, 183 const struct range mm_reg_range_array[], int mm_array_size, 184 int offset, const u32 pb_blocks[], 185 struct hl_block_glbl_sec sgs_array[], int blocks_array_size) 186 { 187 int i, rc = 0; 188 189 for (i = 0 ; i < mm_array_size ; i++) { 190 rc = hl_unsecure_register_range(hdev, mm_reg_range_array[i], 191 offset, pb_blocks, sgs_array, blocks_array_size); 192 193 if (rc) 194 return rc; 195 } 196 197 return rc; 198 } 199 200 /** 201 * hl_ack_pb_security_violations - Ack security violation 202 * 203 * @hdev: pointer to hl_device structure 204 * @pb_blocks: blocks array 205 * @block_offset: additional offset to the block 206 * @array_size: blocks array size 207 * 208 */ 209 static void hl_ack_pb_security_violations(struct hl_device *hdev, 210 const u32 pb_blocks[], u32 block_offset, int array_size) 211 { 212 int i; 213 u32 cause, addr, block_base; 214 215 for (i = 0 ; i < array_size ; i++) { 216 block_base = pb_blocks[i] + block_offset; 217 cause = RREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE); 218 if (cause) { 219 addr = RREG32(block_base + HL_BLOCK_GLBL_ERR_ADDR); 220 hdev->asic_funcs->pb_print_security_errors(hdev, 221 block_base, cause, addr); 222 WREG32(block_base + HL_BLOCK_GLBL_ERR_CAUSE, cause); 223 } 224 } 225 } 226 227 /** 228 * hl_config_glbl_sec - set pb in HW according to given pb array 229 * 230 * @hdev: pointer to hl_device structure 231 * @pb_blocks: blocks array 232 * @sgs_array: pb array 233 * @block_offset: additional offset to the block 234 * @array_size: blocks array size 235 * 236 */ 237 void hl_config_glbl_sec(struct hl_device *hdev, const u32 pb_blocks[], 238 struct hl_block_glbl_sec sgs_array[], u32 block_offset, 239 int array_size) 240 { 241 int i, j; 242 u32 sgs_base; 243 244 if (hdev->pldm) 245 usleep_range(100, 1000); 246 247 for (i = 0 ; i < array_size ; i++) { 248 sgs_base = block_offset + pb_blocks[i] + 249 HL_BLOCK_GLBL_SEC_OFFS; 250 251 for (j = 0 ; j < HL_BLOCK_GLBL_SEC_LEN ; j++) 252 WREG32(sgs_base + j * sizeof(u32), 253 sgs_array[i].sec_array[j]); 254 } 255 } 256 257 /** 258 * hl_secure_block - locally memsets a block to 0 259 * 260 * @hdev: pointer to hl_device structure 261 * @sgs_array: pb array to clear 262 * @array_size: blocks array size 263 * 264 */ 265 void hl_secure_block(struct hl_device *hdev, 266 struct hl_block_glbl_sec sgs_array[], int array_size) 267 { 268 int i; 269 270 for (i = 0 ; i < array_size ; i++) 271 memset((char *)(sgs_array[i].sec_array), 0, 272 HL_BLOCK_GLBL_SEC_SIZE); 273 } 274 275 /** 276 * hl_init_pb_with_mask - set selected pb instances with mask in HW according 277 * to given configuration 278 * 279 * @hdev: pointer to hl_device structure 280 * @num_dcores: number of decores to apply configuration to 281 * set to HL_PB_SHARED if need to apply only once 282 * @dcore_offset: offset between dcores 283 * @num_instances: number of instances to apply configuration to 284 * @instance_offset: offset between instances 285 * @pb_blocks: blocks array 286 * @blocks_array_size: blocks array size 287 * @user_regs_array: unsecured register array 288 * @user_regs_array_size: unsecured register array size 289 * @mask: enabled instances mask: 1- enabled, 0- disabled 290 */ 291 int hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores, 292 u32 dcore_offset, u32 num_instances, u32 instance_offset, 293 const u32 pb_blocks[], u32 blocks_array_size, 294 const u32 *user_regs_array, u32 user_regs_array_size, u64 mask) 295 { 296 int i, j; 297 struct hl_block_glbl_sec *glbl_sec; 298 299 glbl_sec = kcalloc(blocks_array_size, 300 sizeof(struct hl_block_glbl_sec), 301 GFP_KERNEL); 302 if (!glbl_sec) 303 return -ENOMEM; 304 305 hl_secure_block(hdev, glbl_sec, blocks_array_size); 306 hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 0, 307 pb_blocks, glbl_sec, blocks_array_size); 308 309 /* Fill all blocks with the same configuration */ 310 for (i = 0 ; i < num_dcores ; i++) { 311 for (j = 0 ; j < num_instances ; j++) { 312 int seq = i * num_instances + j; 313 314 if (!(mask & BIT_ULL(seq))) 315 continue; 316 317 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 318 i * dcore_offset + j * instance_offset, 319 blocks_array_size); 320 } 321 } 322 323 kfree(glbl_sec); 324 325 return 0; 326 } 327 328 /** 329 * hl_init_pb - set pb in HW according to given configuration 330 * 331 * @hdev: pointer to hl_device structure 332 * @num_dcores: number of decores to apply configuration to 333 * set to HL_PB_SHARED if need to apply only once 334 * @dcore_offset: offset between dcores 335 * @num_instances: number of instances to apply configuration to 336 * @instance_offset: offset between instances 337 * @pb_blocks: blocks array 338 * @blocks_array_size: blocks array size 339 * @user_regs_array: unsecured register array 340 * @user_regs_array_size: unsecured register array size 341 * 342 */ 343 int hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, 344 u32 num_instances, u32 instance_offset, 345 const u32 pb_blocks[], u32 blocks_array_size, 346 const u32 *user_regs_array, u32 user_regs_array_size) 347 { 348 return hl_init_pb_with_mask(hdev, num_dcores, dcore_offset, 349 num_instances, instance_offset, pb_blocks, 350 blocks_array_size, user_regs_array, 351 user_regs_array_size, ULLONG_MAX); 352 } 353 354 /** 355 * hl_init_pb_ranges_with_mask - set pb instances using mask in HW according to 356 * given configuration unsecurring registers 357 * ranges instead of specific registers 358 * 359 * @hdev: pointer to hl_device structure 360 * @num_dcores: number of decores to apply configuration to 361 * set to HL_PB_SHARED if need to apply only once 362 * @dcore_offset: offset between dcores 363 * @num_instances: number of instances to apply configuration to 364 * @instance_offset: offset between instances 365 * @pb_blocks: blocks array 366 * @blocks_array_size: blocks array size 367 * @user_regs_range_array: unsecured register range array 368 * @user_regs_range_array_size: unsecured register range array size 369 * @mask: enabled instances mask: 1- enabled, 0- disabled 370 */ 371 int hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores, 372 u32 dcore_offset, u32 num_instances, u32 instance_offset, 373 const u32 pb_blocks[], u32 blocks_array_size, 374 const struct range *user_regs_range_array, 375 u32 user_regs_range_array_size, u64 mask) 376 { 377 int i, j, rc = 0; 378 struct hl_block_glbl_sec *glbl_sec; 379 380 glbl_sec = kcalloc(blocks_array_size, 381 sizeof(struct hl_block_glbl_sec), 382 GFP_KERNEL); 383 if (!glbl_sec) 384 return -ENOMEM; 385 386 hl_secure_block(hdev, glbl_sec, blocks_array_size); 387 rc = hl_unsecure_registers_range(hdev, user_regs_range_array, 388 user_regs_range_array_size, 0, pb_blocks, glbl_sec, 389 blocks_array_size); 390 if (rc) 391 goto free_glbl_sec; 392 393 /* Fill all blocks with the same configuration */ 394 for (i = 0 ; i < num_dcores ; i++) { 395 for (j = 0 ; j < num_instances ; j++) { 396 int seq = i * num_instances + j; 397 398 if (!(mask & BIT_ULL(seq))) 399 continue; 400 401 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 402 i * dcore_offset + j * instance_offset, 403 blocks_array_size); 404 } 405 } 406 407 free_glbl_sec: 408 kfree(glbl_sec); 409 410 return rc; 411 } 412 413 /** 414 * hl_init_pb_ranges - set pb in HW according to given configuration unsecurring 415 * registers ranges instead of specific registers 416 * 417 * @hdev: pointer to hl_device structure 418 * @num_dcores: number of decores to apply configuration to 419 * set to HL_PB_SHARED if need to apply only once 420 * @dcore_offset: offset between dcores 421 * @num_instances: number of instances to apply configuration to 422 * @instance_offset: offset between instances 423 * @pb_blocks: blocks array 424 * @blocks_array_size: blocks array size 425 * @user_regs_range_array: unsecured register range array 426 * @user_regs_range_array_size: unsecured register range array size 427 * 428 */ 429 int hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores, 430 u32 dcore_offset, u32 num_instances, u32 instance_offset, 431 const u32 pb_blocks[], u32 blocks_array_size, 432 const struct range *user_regs_range_array, 433 u32 user_regs_range_array_size) 434 { 435 return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset, 436 num_instances, instance_offset, pb_blocks, 437 blocks_array_size, user_regs_range_array, 438 user_regs_range_array_size, ULLONG_MAX); 439 } 440 441 /** 442 * hl_init_pb_single_dcore - set pb for a single docre in HW 443 * according to given configuration 444 * 445 * @hdev: pointer to hl_device structure 446 * @dcore_offset: offset from the dcore0 447 * @num_instances: number of instances to apply configuration to 448 * @instance_offset: offset between instances 449 * @pb_blocks: blocks array 450 * @blocks_array_size: blocks array size 451 * @user_regs_array: unsecured register array 452 * @user_regs_array_size: unsecured register array size 453 * 454 */ 455 int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, 456 u32 num_instances, u32 instance_offset, 457 const u32 pb_blocks[], u32 blocks_array_size, 458 const u32 *user_regs_array, u32 user_regs_array_size) 459 { 460 int i, rc = 0; 461 struct hl_block_glbl_sec *glbl_sec; 462 463 glbl_sec = kcalloc(blocks_array_size, 464 sizeof(struct hl_block_glbl_sec), 465 GFP_KERNEL); 466 if (!glbl_sec) 467 return -ENOMEM; 468 469 hl_secure_block(hdev, glbl_sec, blocks_array_size); 470 rc = hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 471 0, pb_blocks, glbl_sec, blocks_array_size); 472 if (rc) 473 goto free_glbl_sec; 474 475 /* Fill all blocks with the same configuration */ 476 for (i = 0 ; i < num_instances ; i++) 477 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 478 dcore_offset + i * instance_offset, 479 blocks_array_size); 480 481 free_glbl_sec: 482 kfree(glbl_sec); 483 484 return rc; 485 } 486 487 /** 488 * hl_init_pb_ranges_single_dcore - set pb for a single docre in HW according 489 * to given configuration unsecurring 490 * registers ranges instead of specific 491 * registers 492 * 493 * @hdev: pointer to hl_device structure 494 * @dcore_offset: offset from the dcore0 495 * @num_instances: number of instances to apply configuration to 496 * @instance_offset: offset between instances 497 * @pb_blocks: blocks array 498 * @blocks_array_size: blocks array size 499 * @user_regs_range_array: unsecured register range array 500 * @user_regs_range_array_size: unsecured register range array size 501 * 502 */ 503 int hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset, 504 u32 num_instances, u32 instance_offset, 505 const u32 pb_blocks[], u32 blocks_array_size, 506 const struct range *user_regs_range_array, u32 user_regs_range_array_size) 507 { 508 int i; 509 struct hl_block_glbl_sec *glbl_sec; 510 511 glbl_sec = kcalloc(blocks_array_size, 512 sizeof(struct hl_block_glbl_sec), 513 GFP_KERNEL); 514 if (!glbl_sec) 515 return -ENOMEM; 516 517 hl_secure_block(hdev, glbl_sec, blocks_array_size); 518 hl_unsecure_registers_range(hdev, user_regs_range_array, 519 user_regs_range_array_size, 0, pb_blocks, glbl_sec, 520 blocks_array_size); 521 522 /* Fill all blocks with the same configuration */ 523 for (i = 0 ; i < num_instances ; i++) 524 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 525 dcore_offset + i * instance_offset, 526 blocks_array_size); 527 528 kfree(glbl_sec); 529 530 return 0; 531 } 532 533 /** 534 * hl_ack_pb_with_mask - ack pb with mask in HW according to given configuration 535 * 536 * @hdev: pointer to hl_device structure 537 * @num_dcores: number of decores to apply configuration to 538 * set to HL_PB_SHARED if need to apply only once 539 * @dcore_offset: offset between dcores 540 * @num_instances: number of instances to apply configuration to 541 * @instance_offset: offset between instances 542 * @pb_blocks: blocks array 543 * @blocks_array_size: blocks array size 544 * @mask: enabled instances mask: 1- enabled, 0- disabled 545 * 546 */ 547 void hl_ack_pb_with_mask(struct hl_device *hdev, u32 num_dcores, 548 u32 dcore_offset, u32 num_instances, u32 instance_offset, 549 const u32 pb_blocks[], u32 blocks_array_size, u64 mask) 550 { 551 int i, j; 552 553 /* ack all blocks */ 554 for (i = 0 ; i < num_dcores ; i++) { 555 for (j = 0 ; j < num_instances ; j++) { 556 int seq = i * num_instances + j; 557 558 if (!(mask & BIT_ULL(seq))) 559 continue; 560 561 hl_ack_pb_security_violations(hdev, pb_blocks, 562 i * dcore_offset + j * instance_offset, 563 blocks_array_size); 564 } 565 } 566 } 567 568 /** 569 * hl_ack_pb - ack pb in HW according to given configuration 570 * 571 * @hdev: pointer to hl_device structure 572 * @num_dcores: number of decores to apply configuration to 573 * set to HL_PB_SHARED if need to apply only once 574 * @dcore_offset: offset between dcores 575 * @num_instances: number of instances to apply configuration to 576 * @instance_offset: offset between instances 577 * @pb_blocks: blocks array 578 * @blocks_array_size: blocks array size 579 * 580 */ 581 void hl_ack_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, 582 u32 num_instances, u32 instance_offset, 583 const u32 pb_blocks[], u32 blocks_array_size) 584 { 585 hl_ack_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances, 586 instance_offset, pb_blocks, blocks_array_size, 587 ULLONG_MAX); 588 } 589 590 /** 591 * hl_ack_pb_single_dcore - ack pb for single docre in HW 592 * according to given configuration 593 * 594 * @hdev: pointer to hl_device structure 595 * @dcore_offset: offset from dcore0 596 * @num_instances: number of instances to apply configuration to 597 * @instance_offset: offset between instances 598 * @pb_blocks: blocks array 599 * @blocks_array_size: blocks array size 600 * 601 */ 602 void hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, 603 u32 num_instances, u32 instance_offset, 604 const u32 pb_blocks[], u32 blocks_array_size) 605 { 606 int i; 607 608 /* ack all blocks */ 609 for (i = 0 ; i < num_instances ; i++) 610 hl_ack_pb_security_violations(hdev, pb_blocks, 611 dcore_offset + i * instance_offset, 612 blocks_array_size); 613 614 } 615 616 static u32 hl_automated_get_block_base_addr(struct hl_device *hdev, 617 struct hl_special_block_info *block_info, 618 u32 major, u32 minor, u32 sub_minor) 619 { 620 u32 fw_block_base_address = block_info->base_addr + 621 major * block_info->major_offset + 622 minor * block_info->minor_offset + 623 sub_minor * block_info->sub_minor_offset; 624 struct asic_fixed_properties *prop = &hdev->asic_prop; 625 626 /* Calculation above returns an address for FW use, and therefore should 627 * be casted for driver use. 628 */ 629 return (fw_block_base_address - lower_32_bits(prop->cfg_base_address)); 630 } 631 632 static bool hl_check_block_type_exclusion(struct hl_skip_blocks_cfg *skip_blocks_cfg, 633 int block_type) 634 { 635 int i; 636 637 /* Check if block type is listed in the exclusion list of block types */ 638 for (i = 0 ; i < skip_blocks_cfg->block_types_len ; i++) 639 if (block_type == skip_blocks_cfg->block_types[i]) 640 return true; 641 642 return false; 643 } 644 645 static bool hl_check_block_range_exclusion(struct hl_device *hdev, 646 struct hl_skip_blocks_cfg *skip_blocks_cfg, 647 struct hl_special_block_info *block_info, 648 u32 major, u32 minor, u32 sub_minor) 649 { 650 u32 blocks_in_range, block_base_addr_in_range, block_base_addr; 651 int i, j; 652 653 block_base_addr = hl_automated_get_block_base_addr(hdev, block_info, 654 major, minor, sub_minor); 655 656 for (i = 0 ; i < skip_blocks_cfg->block_ranges_len ; i++) { 657 blocks_in_range = (skip_blocks_cfg->block_ranges[i].end - 658 skip_blocks_cfg->block_ranges[i].start) / 659 HL_BLOCK_SIZE + 1; 660 for (j = 0 ; j < blocks_in_range ; j++) { 661 block_base_addr_in_range = skip_blocks_cfg->block_ranges[i].start + 662 j * HL_BLOCK_SIZE; 663 if (block_base_addr == block_base_addr_in_range) 664 return true; 665 } 666 } 667 668 return false; 669 } 670 671 static int hl_read_glbl_errors(struct hl_device *hdev, 672 u32 blk_idx, u32 major, u32 minor, u32 sub_minor, void *data) 673 { 674 struct hl_special_block_info *special_blocks = hdev->asic_prop.special_blocks; 675 struct hl_special_block_info *current_block = &special_blocks[blk_idx]; 676 u32 glbl_err_addr, glbl_err_cause, addr_val, cause_val, block_base, 677 base = current_block->base_addr - lower_32_bits(hdev->asic_prop.cfg_base_address); 678 int i; 679 680 block_base = base + major * current_block->major_offset + 681 minor * current_block->minor_offset + 682 sub_minor * current_block->sub_minor_offset; 683 684 glbl_err_cause = block_base + HL_GLBL_ERR_CAUSE_OFFSET; 685 cause_val = RREG32(glbl_err_cause); 686 if (!cause_val) 687 return 0; 688 689 glbl_err_addr = block_base + HL_GLBL_ERR_ADDR_OFFSET; 690 addr_val = RREG32(glbl_err_addr); 691 692 for (i = 0 ; i < hdev->asic_prop.glbl_err_cause_num ; i++) { 693 if (cause_val & BIT(i)) 694 dev_err_ratelimited(hdev->dev, 695 "%s, addr %#llx\n", 696 hl_glbl_error_cause[i], 697 hdev->asic_prop.cfg_base_address + block_base + 698 FIELD_GET(HL_GLBL_ERR_ADDRESS_MASK, addr_val)); 699 } 700 701 WREG32(glbl_err_cause, cause_val); 702 703 return 0; 704 } 705 706 void hl_check_for_glbl_errors(struct hl_device *hdev) 707 { 708 struct asic_fixed_properties *prop = &hdev->asic_prop; 709 struct hl_special_blocks_cfg special_blocks_cfg; 710 struct iterate_special_ctx glbl_err_iter; 711 int rc; 712 713 memset(&special_blocks_cfg, 0, sizeof(special_blocks_cfg)); 714 special_blocks_cfg.skip_blocks_cfg = &prop->skip_special_blocks_cfg; 715 716 glbl_err_iter.fn = &hl_read_glbl_errors; 717 glbl_err_iter.data = &special_blocks_cfg; 718 719 rc = hl_iterate_special_blocks(hdev, &glbl_err_iter); 720 if (rc) 721 dev_err_ratelimited(hdev->dev, 722 "Could not iterate special blocks, glbl error check failed\n"); 723 } 724 725 int hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx) 726 { 727 struct hl_special_blocks_cfg *special_blocks_cfg = 728 (struct hl_special_blocks_cfg *)ctx->data; 729 struct hl_skip_blocks_cfg *skip_blocks_cfg = 730 special_blocks_cfg->skip_blocks_cfg; 731 u32 major, minor, sub_minor, blk_idx, num_blocks; 732 struct hl_special_block_info *block_info_arr; 733 int rc; 734 735 block_info_arr = hdev->asic_prop.special_blocks; 736 if (!block_info_arr) 737 return -EINVAL; 738 739 num_blocks = hdev->asic_prop.num_of_special_blocks; 740 741 for (blk_idx = 0 ; blk_idx < num_blocks ; blk_idx++, block_info_arr++) { 742 if (hl_check_block_type_exclusion(skip_blocks_cfg, block_info_arr->block_type)) 743 continue; 744 745 for (major = 0 ; major < block_info_arr->major ; major++) { 746 minor = 0; 747 do { 748 sub_minor = 0; 749 do { 750 if ((hl_check_block_range_exclusion(hdev, 751 skip_blocks_cfg, block_info_arr, 752 major, minor, sub_minor)) || 753 (skip_blocks_cfg->skip_block_hook && 754 skip_blocks_cfg->skip_block_hook(hdev, 755 special_blocks_cfg, 756 blk_idx, major, minor, sub_minor))) { 757 sub_minor++; 758 continue; 759 } 760 761 rc = ctx->fn(hdev, blk_idx, major, minor, 762 sub_minor, ctx->data); 763 if (rc) 764 return rc; 765 766 sub_minor++; 767 } while (sub_minor < block_info_arr->sub_minor); 768 769 minor++; 770 } while (minor < block_info_arr->minor); 771 } 772 } 773 774 return 0; 775 } 776