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 * @regs_array: register array 288 * @regs_array_size: 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 *regs_array, u32 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, regs_array, regs_array_size, 0, pb_blocks, 307 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 * @regs_array: register array 340 * @regs_array_size: 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 *regs_array, u32 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, regs_array, regs_array_size, 351 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 * @regs_range_array: register range array 368 * @regs_range_array_size: 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 *regs_range_array, u32 regs_range_array_size, 375 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, regs_range_array, 388 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 * @regs_range_array: register range array 426 * @regs_range_array_size: 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 *regs_range_array, u32 regs_range_array_size) 433 { 434 return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset, 435 num_instances, instance_offset, pb_blocks, 436 blocks_array_size, regs_range_array, 437 regs_range_array_size, ULLONG_MAX); 438 } 439 440 /** 441 * hl_init_pb_single_dcore - set pb for a single docre in HW 442 * according to given configuration 443 * 444 * @hdev: pointer to hl_device structure 445 * @dcore_offset: offset from the dcore0 446 * @num_instances: number of instances to apply configuration to 447 * @instance_offset: offset between instances 448 * @pb_blocks: blocks array 449 * @blocks_array_size: blocks array size 450 * @regs_array: register array 451 * @regs_array_size: register array size 452 * 453 */ 454 int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, 455 u32 num_instances, u32 instance_offset, 456 const u32 pb_blocks[], u32 blocks_array_size, 457 const u32 *regs_array, u32 regs_array_size) 458 { 459 int i, rc = 0; 460 struct hl_block_glbl_sec *glbl_sec; 461 462 glbl_sec = kcalloc(blocks_array_size, 463 sizeof(struct hl_block_glbl_sec), 464 GFP_KERNEL); 465 if (!glbl_sec) 466 return -ENOMEM; 467 468 hl_secure_block(hdev, glbl_sec, blocks_array_size); 469 rc = hl_unsecure_registers(hdev, regs_array, regs_array_size, 0, 470 pb_blocks, glbl_sec, blocks_array_size); 471 if (rc) 472 goto free_glbl_sec; 473 474 /* Fill all blocks with the same configuration */ 475 for (i = 0 ; i < num_instances ; i++) 476 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 477 dcore_offset + i * instance_offset, 478 blocks_array_size); 479 480 free_glbl_sec: 481 kfree(glbl_sec); 482 483 return rc; 484 } 485 486 /** 487 * hl_init_pb_ranges_single_dcore - set pb for a single docre in HW according 488 * to given configuration unsecurring 489 * registers ranges instead of specific 490 * registers 491 * 492 * @hdev: pointer to hl_device structure 493 * @dcore_offset: offset from the dcore0 494 * @num_instances: number of instances to apply configuration to 495 * @instance_offset: offset between instances 496 * @pb_blocks: blocks array 497 * @blocks_array_size: blocks array size 498 * @regs_range_array: register range array 499 * @regs_range_array_size: register range array size 500 * 501 */ 502 int hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset, 503 u32 num_instances, u32 instance_offset, 504 const u32 pb_blocks[], u32 blocks_array_size, 505 const struct range *user_regs_range_array, u32 user_regs_range_array_size) 506 { 507 int i; 508 struct hl_block_glbl_sec *glbl_sec; 509 510 glbl_sec = kcalloc(blocks_array_size, 511 sizeof(struct hl_block_glbl_sec), 512 GFP_KERNEL); 513 if (!glbl_sec) 514 return -ENOMEM; 515 516 hl_secure_block(hdev, glbl_sec, blocks_array_size); 517 hl_unsecure_registers_range(hdev, user_regs_range_array, 518 user_regs_range_array_size, 0, pb_blocks, glbl_sec, 519 blocks_array_size); 520 521 /* Fill all blocks with the same configuration */ 522 for (i = 0 ; i < num_instances ; i++) 523 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec, 524 dcore_offset + i * instance_offset, 525 blocks_array_size); 526 527 kfree(glbl_sec); 528 529 return 0; 530 } 531 532 /** 533 * hl_ack_pb_with_mask - ack pb with mask in HW according to given configuration 534 * 535 * @hdev: pointer to hl_device structure 536 * @num_dcores: number of decores to apply configuration to 537 * set to HL_PB_SHARED if need to apply only once 538 * @dcore_offset: offset between dcores 539 * @num_instances: number of instances to apply configuration to 540 * @instance_offset: offset between instances 541 * @pb_blocks: blocks array 542 * @blocks_array_size: blocks array size 543 * @mask: enabled instances mask: 1- enabled, 0- disabled 544 * 545 */ 546 void hl_ack_pb_with_mask(struct hl_device *hdev, u32 num_dcores, 547 u32 dcore_offset, u32 num_instances, u32 instance_offset, 548 const u32 pb_blocks[], u32 blocks_array_size, u64 mask) 549 { 550 int i, j; 551 552 /* ack all blocks */ 553 for (i = 0 ; i < num_dcores ; i++) { 554 for (j = 0 ; j < num_instances ; j++) { 555 int seq = i * num_instances + j; 556 557 if (!(mask & BIT_ULL(seq))) 558 continue; 559 560 hl_ack_pb_security_violations(hdev, pb_blocks, 561 i * dcore_offset + j * instance_offset, 562 blocks_array_size); 563 } 564 } 565 } 566 567 /** 568 * hl_ack_pb - ack pb in HW according to given configuration 569 * 570 * @hdev: pointer to hl_device structure 571 * @num_dcores: number of decores to apply configuration to 572 * set to HL_PB_SHARED if need to apply only once 573 * @dcore_offset: offset between dcores 574 * @num_instances: number of instances to apply configuration to 575 * @instance_offset: offset between instances 576 * @pb_blocks: blocks array 577 * @blocks_array_size: blocks array size 578 * 579 */ 580 void hl_ack_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, 581 u32 num_instances, u32 instance_offset, 582 const u32 pb_blocks[], u32 blocks_array_size) 583 { 584 hl_ack_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances, 585 instance_offset, pb_blocks, blocks_array_size, 586 ULLONG_MAX); 587 } 588 589 /** 590 * hl_ack_pb_single_dcore - ack pb for single docre in HW 591 * according to given configuration 592 * 593 * @hdev: pointer to hl_device structure 594 * @dcore_offset: offset from dcore0 595 * @num_instances: number of instances to apply configuration to 596 * @instance_offset: offset between instances 597 * @pb_blocks: blocks array 598 * @blocks_array_size: blocks array size 599 * 600 */ 601 void hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, 602 u32 num_instances, u32 instance_offset, 603 const u32 pb_blocks[], u32 blocks_array_size) 604 { 605 int i; 606 607 /* ack all blocks */ 608 for (i = 0 ; i < num_instances ; i++) 609 hl_ack_pb_security_violations(hdev, pb_blocks, 610 dcore_offset + i * instance_offset, 611 blocks_array_size); 612 613 } 614 615 static u32 hl_automated_get_block_base_addr(struct hl_device *hdev, 616 struct hl_special_block_info *block_info, 617 u32 major, u32 minor, u32 sub_minor) 618 { 619 u32 fw_block_base_address = block_info->base_addr + 620 major * block_info->major_offset + 621 minor * block_info->minor_offset + 622 sub_minor * block_info->sub_minor_offset; 623 struct asic_fixed_properties *prop = &hdev->asic_prop; 624 625 /* Calculation above returns an address for FW use, and therefore should 626 * be casted for driver use. 627 */ 628 return (fw_block_base_address - lower_32_bits(prop->cfg_base_address)); 629 } 630 631 static bool hl_check_block_type_exclusion(struct hl_skip_blocks_cfg *skip_blocks_cfg, 632 int block_type) 633 { 634 int i; 635 636 /* Check if block type is listed in the exclusion list of block types */ 637 for (i = 0 ; i < skip_blocks_cfg->block_types_len ; i++) 638 if (block_type == skip_blocks_cfg->block_types[i]) 639 return true; 640 641 return false; 642 } 643 644 static bool hl_check_block_range_exclusion(struct hl_device *hdev, 645 struct hl_skip_blocks_cfg *skip_blocks_cfg, 646 struct hl_special_block_info *block_info, 647 u32 major, u32 minor, u32 sub_minor) 648 { 649 u32 blocks_in_range, block_base_addr_in_range, block_base_addr; 650 int i, j; 651 652 block_base_addr = hl_automated_get_block_base_addr(hdev, block_info, 653 major, minor, sub_minor); 654 655 for (i = 0 ; i < skip_blocks_cfg->block_ranges_len ; i++) { 656 blocks_in_range = (skip_blocks_cfg->block_ranges[i].end - 657 skip_blocks_cfg->block_ranges[i].start) / 658 HL_BLOCK_SIZE + 1; 659 for (j = 0 ; j < blocks_in_range ; j++) { 660 block_base_addr_in_range = skip_blocks_cfg->block_ranges[i].start + 661 j * HL_BLOCK_SIZE; 662 if (block_base_addr == block_base_addr_in_range) 663 return true; 664 } 665 } 666 667 return false; 668 } 669 670 static int hl_read_glbl_errors(struct hl_device *hdev, 671 u32 blk_idx, u32 major, u32 minor, u32 sub_minor, void *data) 672 { 673 struct hl_special_block_info *special_blocks = hdev->asic_prop.special_blocks; 674 struct hl_special_block_info *current_block = &special_blocks[blk_idx]; 675 u32 glbl_err_addr, glbl_err_cause, addr_val, cause_val, block_base, 676 base = current_block->base_addr - lower_32_bits(hdev->asic_prop.cfg_base_address); 677 int i; 678 679 block_base = base + major * current_block->major_offset + 680 minor * current_block->minor_offset + 681 sub_minor * current_block->sub_minor_offset; 682 683 glbl_err_cause = block_base + HL_GLBL_ERR_CAUSE_OFFSET; 684 cause_val = RREG32(glbl_err_cause); 685 if (!cause_val) 686 return 0; 687 688 glbl_err_addr = block_base + HL_GLBL_ERR_ADDR_OFFSET; 689 addr_val = RREG32(glbl_err_addr); 690 691 for (i = 0 ; i < hdev->asic_prop.glbl_err_cause_num ; i++) { 692 if (cause_val & BIT(i)) 693 dev_err_ratelimited(hdev->dev, 694 "%s, addr %#llx\n", 695 hl_glbl_error_cause[i], 696 hdev->asic_prop.cfg_base_address + block_base + 697 FIELD_GET(HL_GLBL_ERR_ADDRESS_MASK, addr_val)); 698 } 699 700 WREG32(glbl_err_cause, cause_val); 701 702 return 0; 703 } 704 705 void hl_check_for_glbl_errors(struct hl_device *hdev) 706 { 707 struct asic_fixed_properties *prop = &hdev->asic_prop; 708 struct hl_special_blocks_cfg special_blocks_cfg; 709 struct iterate_special_ctx glbl_err_iter; 710 int rc; 711 712 memset(&special_blocks_cfg, 0, sizeof(special_blocks_cfg)); 713 special_blocks_cfg.skip_blocks_cfg = &prop->skip_special_blocks_cfg; 714 715 glbl_err_iter.fn = &hl_read_glbl_errors; 716 glbl_err_iter.data = &special_blocks_cfg; 717 718 rc = hl_iterate_special_blocks(hdev, &glbl_err_iter); 719 if (rc) 720 dev_err_ratelimited(hdev->dev, 721 "Could not iterate special blocks, glbl error check failed\n"); 722 } 723 724 int hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx) 725 { 726 struct hl_special_blocks_cfg *special_blocks_cfg = 727 (struct hl_special_blocks_cfg *)ctx->data; 728 struct hl_skip_blocks_cfg *skip_blocks_cfg = 729 special_blocks_cfg->skip_blocks_cfg; 730 u32 major, minor, sub_minor, blk_idx, num_blocks; 731 struct hl_special_block_info *block_info_arr; 732 int rc; 733 734 block_info_arr = hdev->asic_prop.special_blocks; 735 if (!block_info_arr) 736 return -EINVAL; 737 738 num_blocks = hdev->asic_prop.num_of_special_blocks; 739 740 for (blk_idx = 0 ; blk_idx < num_blocks ; blk_idx++, block_info_arr++) { 741 if (hl_check_block_type_exclusion(skip_blocks_cfg, block_info_arr->block_type)) 742 continue; 743 744 for (major = 0 ; major < block_info_arr->major ; major++) { 745 minor = 0; 746 do { 747 sub_minor = 0; 748 do { 749 if ((hl_check_block_range_exclusion(hdev, 750 skip_blocks_cfg, block_info_arr, 751 major, minor, sub_minor)) || 752 (skip_blocks_cfg->skip_block_hook && 753 skip_blocks_cfg->skip_block_hook(hdev, 754 special_blocks_cfg, 755 blk_idx, major, minor, sub_minor))) { 756 sub_minor++; 757 continue; 758 } 759 760 rc = ctx->fn(hdev, blk_idx, major, minor, 761 sub_minor, ctx->data); 762 if (rc) 763 return rc; 764 765 sub_minor++; 766 } while (sub_minor < block_info_arr->sub_minor); 767 768 minor++; 769 } while (minor < block_info_arr->minor); 770 } 771 } 772 773 return 0; 774 } 775