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[] = {
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 array
41 *
42 * @hdev: pointer to hl_device structure
43 * @mm_reg_addr: register address in the desired block
44 * @pb_blocks: blocks array
45 * @array_size: blocks array size
46 *
47 */
hl_get_pb_block(struct hl_device * hdev,u32 mm_reg_addr,const u32 pb_blocks[],int array_size)48 static 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 block
69 *
70 * @hdev: pointer to hl_device structure
71 * @reg_offset: register offset will be converted to bit offset in pb block
72 * @sgs_entry: pb array
73 *
74 */
hl_unset_pb_in_block(struct hl_device * hdev,u32 reg_offset,struct hl_block_glbl_sec * sgs_entry)75 static 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 and
93 * remove corresponding protection bit
94 *
95 * @hdev: pointer to hl_device structure
96 * @mm_reg_addr: register address to unsecure
97 * @offset: additional offset to the register address
98 * @pb_blocks: blocks array
99 * @sgs_array: pb array
100 * @array_size: blocks array size
101 *
102 */
hl_unsecure_register(struct hl_device * hdev,u32 mm_reg_addr,int offset,const u32 pb_blocks[],struct hl_block_glbl_sec sgs_array[],int array_size)103 int 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 register
122 * range and remove corresponding protection bit
123 *
124 * @hdev: pointer to hl_device structure
125 * @mm_reg_range: register address range to unsecure
126 * @offset: additional offset to the register address
127 * @pb_blocks: blocks array
128 * @sgs_array: pb array
129 * @array_size: blocks array size
130 *
131 */
hl_unsecure_register_range(struct hl_device * hdev,struct range mm_reg_range,int offset,const u32 pb_blocks[],struct hl_block_glbl_sec sgs_array[],int array_size)132 static 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 and
157 * remove corresponding protection bit
158 *
159 * @hdev: pointer to hl_device structure
160 * @mm_reg_array: register address array to unsecure
161 * @mm_array_size: register array size
162 * @offset: additional offset to the register address
163 * @pb_blocks: blocks array
164 * @sgs_array: pb array
165 * @blocks_array_size: blocks array size
166 *
167 */
hl_unsecure_registers(struct hl_device * hdev,const u32 mm_reg_array[],int mm_array_size,int offset,const u32 pb_blocks[],struct hl_block_glbl_sec sgs_array[],int blocks_array_size)168 int 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 register
187 * ranges and remove corresponding protection bit
188 *
189 * @hdev: pointer to hl_device structure
190 * @mm_reg_range_array: register address range array to unsecure
191 * @mm_array_size: register array size
192 * @offset: additional offset to the register address
193 * @pb_blocks: blocks array
194 * @sgs_array: pb array
195 * @blocks_array_size: blocks array size
196 *
197 */
hl_unsecure_registers_range(struct hl_device * hdev,const struct range mm_reg_range_array[],int mm_array_size,int offset,const u32 pb_blocks[],struct hl_block_glbl_sec sgs_array[],int blocks_array_size)198 static 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 violation
218 *
219 * @hdev: pointer to hl_device structure
220 * @pb_blocks: blocks array
221 * @block_offset: additional offset to the block
222 * @array_size: blocks array size
223 *
224 */
hl_ack_pb_security_violations(struct hl_device * hdev,const u32 pb_blocks[],u32 block_offset,int array_size)225 static 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 array
245 *
246 * @hdev: pointer to hl_device structure
247 * @pb_blocks: blocks array
248 * @sgs_array: pb array
249 * @block_offset: additional offset to the block
250 * @array_size: blocks array size
251 *
252 */
hl_config_glbl_sec(struct hl_device * hdev,const u32 pb_blocks[],struct hl_block_glbl_sec sgs_array[],u32 block_offset,int array_size)253 void 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 0
275 *
276 * @hdev: pointer to hl_device structure
277 * @sgs_array: pb array to clear
278 * @array_size: blocks array size
279 *
280 */
hl_secure_block(struct hl_device * hdev,struct hl_block_glbl_sec sgs_array[],int array_size)281 void 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 according
293 * to given configuration
294 *
295 * @hdev: pointer to hl_device structure
296 * @num_dcores: number of decores to apply configuration to
297 * set to HL_PB_SHARED if need to apply only once
298 * @dcore_offset: offset between dcores
299 * @num_instances: number of instances to apply configuration to
300 * @instance_offset: offset between instances
301 * @pb_blocks: blocks array
302 * @blocks_array_size: blocks array size
303 * @user_regs_array: unsecured register array
304 * @user_regs_array_size: unsecured register array size
305 * @mask: enabled instances mask: 1- enabled, 0- disabled
306 */
hl_init_pb_with_mask(struct hl_device * hdev,u32 num_dcores,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,const u32 * user_regs_array,u32 user_regs_array_size,u64 mask)307 int 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 = kzalloc_objs(struct hl_block_glbl_sec, blocks_array_size);
316 if (!glbl_sec)
317 return -ENOMEM;
318
319 hl_secure_block(hdev, glbl_sec, blocks_array_size);
320 hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 0,
321 pb_blocks, glbl_sec, blocks_array_size);
322
323 /* Fill all blocks with the same configuration */
324 for (i = 0 ; i < num_dcores ; i++) {
325 for (j = 0 ; j < num_instances ; j++) {
326 int seq = i * num_instances + j;
327
328 if (!(mask & BIT_ULL(seq)))
329 continue;
330
331 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
332 i * dcore_offset + j * instance_offset,
333 blocks_array_size);
334 }
335 }
336
337 kfree(glbl_sec);
338
339 return 0;
340 }
341
342 /**
343 * hl_init_pb - set pb in HW according to given configuration
344 *
345 * @hdev: pointer to hl_device structure
346 * @num_dcores: number of decores to apply configuration to
347 * set to HL_PB_SHARED if need to apply only once
348 * @dcore_offset: offset between dcores
349 * @num_instances: number of instances to apply configuration to
350 * @instance_offset: offset between instances
351 * @pb_blocks: blocks array
352 * @blocks_array_size: blocks array size
353 * @user_regs_array: unsecured register array
354 * @user_regs_array_size: unsecured register array size
355 *
356 */
hl_init_pb(struct hl_device * hdev,u32 num_dcores,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,const u32 * user_regs_array,u32 user_regs_array_size)357 int hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset,
358 u32 num_instances, u32 instance_offset,
359 const u32 pb_blocks[], u32 blocks_array_size,
360 const u32 *user_regs_array, u32 user_regs_array_size)
361 {
362 return hl_init_pb_with_mask(hdev, num_dcores, dcore_offset,
363 num_instances, instance_offset, pb_blocks,
364 blocks_array_size, user_regs_array,
365 user_regs_array_size, ULLONG_MAX);
366 }
367
368 /**
369 * hl_init_pb_ranges_with_mask - set pb instances using mask in HW according to
370 * given configuration unsecurring registers
371 * ranges instead of specific registers
372 *
373 * @hdev: pointer to hl_device structure
374 * @num_dcores: number of decores to apply configuration to
375 * set to HL_PB_SHARED if need to apply only once
376 * @dcore_offset: offset between dcores
377 * @num_instances: number of instances to apply configuration to
378 * @instance_offset: offset between instances
379 * @pb_blocks: blocks array
380 * @blocks_array_size: blocks array size
381 * @user_regs_range_array: unsecured register range array
382 * @user_regs_range_array_size: unsecured register range array size
383 * @mask: enabled instances mask: 1- enabled, 0- disabled
384 */
hl_init_pb_ranges_with_mask(struct hl_device * hdev,u32 num_dcores,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,const struct range * user_regs_range_array,u32 user_regs_range_array_size,u64 mask)385 int hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores,
386 u32 dcore_offset, u32 num_instances, u32 instance_offset,
387 const u32 pb_blocks[], u32 blocks_array_size,
388 const struct range *user_regs_range_array,
389 u32 user_regs_range_array_size, u64 mask)
390 {
391 int i, j, rc = 0;
392 struct hl_block_glbl_sec *glbl_sec;
393
394 glbl_sec = kzalloc_objs(struct hl_block_glbl_sec, blocks_array_size);
395 if (!glbl_sec)
396 return -ENOMEM;
397
398 hl_secure_block(hdev, glbl_sec, blocks_array_size);
399 rc = hl_unsecure_registers_range(hdev, user_regs_range_array,
400 user_regs_range_array_size, 0, pb_blocks, glbl_sec,
401 blocks_array_size);
402 if (rc)
403 goto free_glbl_sec;
404
405 /* Fill all blocks with the same configuration */
406 for (i = 0 ; i < num_dcores ; i++) {
407 for (j = 0 ; j < num_instances ; j++) {
408 int seq = i * num_instances + j;
409
410 if (!(mask & BIT_ULL(seq)))
411 continue;
412
413 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
414 i * dcore_offset + j * instance_offset,
415 blocks_array_size);
416 }
417 }
418
419 free_glbl_sec:
420 kfree(glbl_sec);
421
422 return rc;
423 }
424
425 /**
426 * hl_init_pb_ranges - set pb in HW according to given configuration unsecurring
427 * registers ranges instead of specific registers
428 *
429 * @hdev: pointer to hl_device structure
430 * @num_dcores: number of decores to apply configuration to
431 * set to HL_PB_SHARED if need to apply only once
432 * @dcore_offset: offset between dcores
433 * @num_instances: number of instances to apply configuration to
434 * @instance_offset: offset between instances
435 * @pb_blocks: blocks array
436 * @blocks_array_size: blocks array size
437 * @user_regs_range_array: unsecured register range array
438 * @user_regs_range_array_size: unsecured register range array size
439 *
440 */
hl_init_pb_ranges(struct hl_device * hdev,u32 num_dcores,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,const struct range * user_regs_range_array,u32 user_regs_range_array_size)441 int hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores,
442 u32 dcore_offset, u32 num_instances, u32 instance_offset,
443 const u32 pb_blocks[], u32 blocks_array_size,
444 const struct range *user_regs_range_array,
445 u32 user_regs_range_array_size)
446 {
447 return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset,
448 num_instances, instance_offset, pb_blocks,
449 blocks_array_size, user_regs_range_array,
450 user_regs_range_array_size, ULLONG_MAX);
451 }
452
453 /**
454 * hl_init_pb_single_dcore - set pb for a single docre in HW
455 * according to given configuration
456 *
457 * @hdev: pointer to hl_device structure
458 * @dcore_offset: offset from the dcore0
459 * @num_instances: number of instances to apply configuration to
460 * @instance_offset: offset between instances
461 * @pb_blocks: blocks array
462 * @blocks_array_size: blocks array size
463 * @user_regs_array: unsecured register array
464 * @user_regs_array_size: unsecured register array size
465 *
466 */
hl_init_pb_single_dcore(struct hl_device * hdev,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,const u32 * user_regs_array,u32 user_regs_array_size)467 int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,
468 u32 num_instances, u32 instance_offset,
469 const u32 pb_blocks[], u32 blocks_array_size,
470 const u32 *user_regs_array, u32 user_regs_array_size)
471 {
472 int i, rc = 0;
473 struct hl_block_glbl_sec *glbl_sec;
474
475 glbl_sec = kzalloc_objs(struct hl_block_glbl_sec, blocks_array_size);
476 if (!glbl_sec)
477 return -ENOMEM;
478
479 hl_secure_block(hdev, glbl_sec, blocks_array_size);
480 rc = hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size,
481 0, pb_blocks, glbl_sec, blocks_array_size);
482 if (rc)
483 goto free_glbl_sec;
484
485 /* Fill all blocks with the same configuration */
486 for (i = 0 ; i < num_instances ; i++)
487 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
488 dcore_offset + i * instance_offset,
489 blocks_array_size);
490
491 free_glbl_sec:
492 kfree(glbl_sec);
493
494 return rc;
495 }
496
497 /**
498 * hl_init_pb_ranges_single_dcore - set pb for a single docre in HW according
499 * to given configuration unsecurring
500 * registers ranges instead of specific
501 * registers
502 *
503 * @hdev: pointer to hl_device structure
504 * @dcore_offset: offset from the dcore0
505 * @num_instances: number of instances to apply configuration to
506 * @instance_offset: offset between instances
507 * @pb_blocks: blocks array
508 * @blocks_array_size: blocks array size
509 * @user_regs_range_array: unsecured register range array
510 * @user_regs_range_array_size: unsecured register range array size
511 *
512 */
hl_init_pb_ranges_single_dcore(struct hl_device * hdev,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,const struct range * user_regs_range_array,u32 user_regs_range_array_size)513 int hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset,
514 u32 num_instances, u32 instance_offset,
515 const u32 pb_blocks[], u32 blocks_array_size,
516 const struct range *user_regs_range_array, u32 user_regs_range_array_size)
517 {
518 int i;
519 struct hl_block_glbl_sec *glbl_sec;
520
521 glbl_sec = kzalloc_objs(struct hl_block_glbl_sec, blocks_array_size);
522 if (!glbl_sec)
523 return -ENOMEM;
524
525 hl_secure_block(hdev, glbl_sec, blocks_array_size);
526 hl_unsecure_registers_range(hdev, user_regs_range_array,
527 user_regs_range_array_size, 0, pb_blocks, glbl_sec,
528 blocks_array_size);
529
530 /* Fill all blocks with the same configuration */
531 for (i = 0 ; i < num_instances ; i++)
532 hl_config_glbl_sec(hdev, pb_blocks, glbl_sec,
533 dcore_offset + i * instance_offset,
534 blocks_array_size);
535
536 kfree(glbl_sec);
537
538 return 0;
539 }
540
541 /**
542 * hl_ack_pb_with_mask - ack pb with mask in HW according to given configuration
543 *
544 * @hdev: pointer to hl_device structure
545 * @num_dcores: number of decores to apply configuration to
546 * set to HL_PB_SHARED if need to apply only once
547 * @dcore_offset: offset between dcores
548 * @num_instances: number of instances to apply configuration to
549 * @instance_offset: offset between instances
550 * @pb_blocks: blocks array
551 * @blocks_array_size: blocks array size
552 * @mask: enabled instances mask: 1- enabled, 0- disabled
553 *
554 */
hl_ack_pb_with_mask(struct hl_device * hdev,u32 num_dcores,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size,u64 mask)555 void hl_ack_pb_with_mask(struct hl_device *hdev, u32 num_dcores,
556 u32 dcore_offset, u32 num_instances, u32 instance_offset,
557 const u32 pb_blocks[], u32 blocks_array_size, u64 mask)
558 {
559 int i, j;
560
561 /* ack all blocks */
562 for (i = 0 ; i < num_dcores ; i++) {
563 for (j = 0 ; j < num_instances ; j++) {
564 int seq = i * num_instances + j;
565
566 if (!(mask & BIT_ULL(seq)))
567 continue;
568
569 hl_ack_pb_security_violations(hdev, pb_blocks,
570 i * dcore_offset + j * instance_offset,
571 blocks_array_size);
572 }
573 }
574 }
575
576 /**
577 * hl_ack_pb - ack pb in HW according to given configuration
578 *
579 * @hdev: pointer to hl_device structure
580 * @num_dcores: number of decores to apply configuration to
581 * set to HL_PB_SHARED if need to apply only once
582 * @dcore_offset: offset between dcores
583 * @num_instances: number of instances to apply configuration to
584 * @instance_offset: offset between instances
585 * @pb_blocks: blocks array
586 * @blocks_array_size: blocks array size
587 *
588 */
hl_ack_pb(struct hl_device * hdev,u32 num_dcores,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size)589 void hl_ack_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset,
590 u32 num_instances, u32 instance_offset,
591 const u32 pb_blocks[], u32 blocks_array_size)
592 {
593 hl_ack_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances,
594 instance_offset, pb_blocks, blocks_array_size,
595 ULLONG_MAX);
596 }
597
598 /**
599 * hl_ack_pb_single_dcore - ack pb for single docre in HW
600 * according to given configuration
601 *
602 * @hdev: pointer to hl_device structure
603 * @dcore_offset: offset from dcore0
604 * @num_instances: number of instances to apply configuration to
605 * @instance_offset: offset between instances
606 * @pb_blocks: blocks array
607 * @blocks_array_size: blocks array size
608 *
609 */
hl_ack_pb_single_dcore(struct hl_device * hdev,u32 dcore_offset,u32 num_instances,u32 instance_offset,const u32 pb_blocks[],u32 blocks_array_size)610 void hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,
611 u32 num_instances, u32 instance_offset,
612 const u32 pb_blocks[], u32 blocks_array_size)
613 {
614 int i;
615
616 /* ack all blocks */
617 for (i = 0 ; i < num_instances ; i++)
618 hl_ack_pb_security_violations(hdev, pb_blocks,
619 dcore_offset + i * instance_offset,
620 blocks_array_size);
621
622 }
623
hl_automated_get_block_base_addr(struct hl_device * hdev,struct hl_special_block_info * block_info,u32 major,u32 minor,u32 sub_minor)624 static u32 hl_automated_get_block_base_addr(struct hl_device *hdev,
625 struct hl_special_block_info *block_info,
626 u32 major, u32 minor, u32 sub_minor)
627 {
628 u32 fw_block_base_address = block_info->base_addr +
629 major * block_info->major_offset +
630 minor * block_info->minor_offset +
631 sub_minor * block_info->sub_minor_offset;
632 struct asic_fixed_properties *prop = &hdev->asic_prop;
633
634 /* Calculation above returns an address for FW use, and therefore should
635 * be casted for driver use.
636 */
637 return (fw_block_base_address - lower_32_bits(prop->cfg_base_address));
638 }
639
hl_check_block_type_exclusion(struct hl_skip_blocks_cfg * skip_blocks_cfg,int block_type)640 static bool hl_check_block_type_exclusion(struct hl_skip_blocks_cfg *skip_blocks_cfg,
641 int block_type)
642 {
643 int i;
644
645 /* Check if block type is listed in the exclusion list of block types */
646 for (i = 0 ; i < skip_blocks_cfg->block_types_len ; i++)
647 if (block_type == skip_blocks_cfg->block_types[i])
648 return true;
649
650 return false;
651 }
652
hl_check_block_range_exclusion(struct hl_device * hdev,struct hl_skip_blocks_cfg * skip_blocks_cfg,struct hl_special_block_info * block_info,u32 major,u32 minor,u32 sub_minor)653 static bool hl_check_block_range_exclusion(struct hl_device *hdev,
654 struct hl_skip_blocks_cfg *skip_blocks_cfg,
655 struct hl_special_block_info *block_info,
656 u32 major, u32 minor, u32 sub_minor)
657 {
658 u32 blocks_in_range, block_base_addr_in_range, block_base_addr;
659 int i, j;
660
661 block_base_addr = hl_automated_get_block_base_addr(hdev, block_info,
662 major, minor, sub_minor);
663
664 for (i = 0 ; i < skip_blocks_cfg->block_ranges_len ; i++) {
665 blocks_in_range = (skip_blocks_cfg->block_ranges[i].end -
666 skip_blocks_cfg->block_ranges[i].start) /
667 HL_BLOCK_SIZE + 1;
668 for (j = 0 ; j < blocks_in_range ; j++) {
669 block_base_addr_in_range = skip_blocks_cfg->block_ranges[i].start +
670 j * HL_BLOCK_SIZE;
671 if (block_base_addr == block_base_addr_in_range)
672 return true;
673 }
674 }
675
676 return false;
677 }
678
hl_read_glbl_errors(struct hl_device * hdev,u32 blk_idx,u32 major,u32 minor,u32 sub_minor,void * data)679 static int hl_read_glbl_errors(struct hl_device *hdev,
680 u32 blk_idx, u32 major, u32 minor, u32 sub_minor, void *data)
681 {
682 struct asic_fixed_properties *prop = &hdev->asic_prop;
683 struct hl_special_block_info *special_blocks = prop->special_blocks;
684 struct hl_special_block_info *current_block = &special_blocks[blk_idx];
685 u32 glbl_err_addr, glbl_err_cause, addr_val, cause_val, block_base,
686 base = current_block->base_addr - lower_32_bits(prop->cfg_base_address);
687 int i;
688
689 block_base = base + major * current_block->major_offset +
690 minor * current_block->minor_offset +
691 sub_minor * current_block->sub_minor_offset;
692
693 glbl_err_cause = block_base + HL_GLBL_ERR_CAUSE_OFFSET;
694 cause_val = RREG32(glbl_err_cause);
695 if (!cause_val)
696 return 0;
697
698 glbl_err_addr = block_base + HL_GLBL_ERR_ADDR_OFFSET;
699 addr_val = RREG32(glbl_err_addr);
700
701 for (i = 0 ; i <= prop->glbl_err_max_cause_num ; i++) {
702 if (cause_val & BIT(i))
703 dev_err_ratelimited(hdev->dev,
704 "%s, addr %#llx\n",
705 hl_glbl_error_cause[i],
706 prop->cfg_base_address + block_base +
707 FIELD_GET(HL_GLBL_ERR_ADDRESS_MASK, addr_val));
708 }
709
710 WREG32(glbl_err_cause, cause_val);
711
712 return 0;
713 }
714
hl_check_for_glbl_errors(struct hl_device * hdev)715 void hl_check_for_glbl_errors(struct hl_device *hdev)
716 {
717 struct asic_fixed_properties *prop = &hdev->asic_prop;
718 struct hl_special_blocks_cfg special_blocks_cfg;
719 struct iterate_special_ctx glbl_err_iter;
720 int rc;
721
722 memset(&special_blocks_cfg, 0, sizeof(special_blocks_cfg));
723 special_blocks_cfg.skip_blocks_cfg = &prop->skip_special_blocks_cfg;
724
725 glbl_err_iter.fn = &hl_read_glbl_errors;
726 glbl_err_iter.data = &special_blocks_cfg;
727
728 rc = hl_iterate_special_blocks(hdev, &glbl_err_iter);
729 if (rc)
730 dev_err_ratelimited(hdev->dev,
731 "Could not iterate special blocks, glbl error check failed\n");
732 }
733
hl_iterate_special_blocks(struct hl_device * hdev,struct iterate_special_ctx * ctx)734 int hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx)
735 {
736 struct hl_special_blocks_cfg *special_blocks_cfg =
737 (struct hl_special_blocks_cfg *)ctx->data;
738 struct hl_skip_blocks_cfg *skip_blocks_cfg =
739 special_blocks_cfg->skip_blocks_cfg;
740 u32 major, minor, sub_minor, blk_idx, num_blocks;
741 struct hl_special_block_info *block_info_arr;
742 int rc;
743
744 block_info_arr = hdev->asic_prop.special_blocks;
745 if (!block_info_arr)
746 return -EINVAL;
747
748 num_blocks = hdev->asic_prop.num_of_special_blocks;
749
750 for (blk_idx = 0 ; blk_idx < num_blocks ; blk_idx++, block_info_arr++) {
751 if (hl_check_block_type_exclusion(skip_blocks_cfg, block_info_arr->block_type))
752 continue;
753
754 for (major = 0 ; major < block_info_arr->major ; major++) {
755 minor = 0;
756 do {
757 sub_minor = 0;
758 do {
759 if ((hl_check_block_range_exclusion(hdev,
760 skip_blocks_cfg, block_info_arr,
761 major, minor, sub_minor)) ||
762 (skip_blocks_cfg->skip_block_hook &&
763 skip_blocks_cfg->skip_block_hook(hdev,
764 special_blocks_cfg,
765 blk_idx, major, minor, sub_minor))) {
766 sub_minor++;
767 continue;
768 }
769
770 rc = ctx->fn(hdev, blk_idx, major, minor,
771 sub_minor, ctx->data);
772 if (rc)
773 return rc;
774
775 sub_minor++;
776 } while (sub_minor < block_info_arr->sub_minor);
777
778 minor++;
779 } while (minor < block_info_arr->minor);
780 }
781 }
782
783 return 0;
784 }
785