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 = 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 configuration
346 *
347 * @hdev: pointer to hl_device structure
348 * @num_dcores: number of decores to apply configuration to
349 * set to HL_PB_SHARED if need to apply only once
350 * @dcore_offset: offset between dcores
351 * @num_instances: number of instances to apply configuration to
352 * @instance_offset: offset between instances
353 * @pb_blocks: blocks array
354 * @blocks_array_size: blocks array size
355 * @user_regs_array: unsecured register array
356 * @user_regs_array_size: unsecured register array size
357 *
358 */
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)359 int 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 to
372 * given configuration unsecurring registers
373 * ranges instead of specific registers
374 *
375 * @hdev: pointer to hl_device structure
376 * @num_dcores: number of decores to apply configuration to
377 * set to HL_PB_SHARED if need to apply only once
378 * @dcore_offset: offset between dcores
379 * @num_instances: number of instances to apply configuration to
380 * @instance_offset: offset between instances
381 * @pb_blocks: blocks array
382 * @blocks_array_size: blocks array size
383 * @user_regs_range_array: unsecured register range array
384 * @user_regs_range_array_size: unsecured register range array size
385 * @mask: enabled instances mask: 1- enabled, 0- disabled
386 */
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)387 int 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
423 free_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 unsecurring
431 * registers ranges instead of specific registers
432 *
433 * @hdev: pointer to hl_device structure
434 * @num_dcores: number of decores to apply configuration to
435 * set to HL_PB_SHARED if need to apply only once
436 * @dcore_offset: offset between dcores
437 * @num_instances: number of instances to apply configuration to
438 * @instance_offset: offset between instances
439 * @pb_blocks: blocks array
440 * @blocks_array_size: blocks array size
441 * @user_regs_range_array: unsecured register range array
442 * @user_regs_range_array_size: unsecured register range array size
443 *
444 */
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)445 int 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 HW
459 * according to given configuration
460 *
461 * @hdev: pointer to hl_device structure
462 * @dcore_offset: offset from the dcore0
463 * @num_instances: number of instances to apply configuration to
464 * @instance_offset: offset between instances
465 * @pb_blocks: blocks array
466 * @blocks_array_size: blocks array size
467 * @user_regs_array: unsecured register array
468 * @user_regs_array_size: unsecured register array size
469 *
470 */
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)471 int 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
497 free_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 according
505 * to given configuration unsecurring
506 * registers ranges instead of specific
507 * registers
508 *
509 * @hdev: pointer to hl_device structure
510 * @dcore_offset: offset from the dcore0
511 * @num_instances: number of instances to apply configuration to
512 * @instance_offset: offset between instances
513 * @pb_blocks: blocks array
514 * @blocks_array_size: blocks array size
515 * @user_regs_range_array: unsecured register range array
516 * @user_regs_range_array_size: unsecured register range array size
517 *
518 */
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)519 int 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 configuration
551 *
552 * @hdev: pointer to hl_device structure
553 * @num_dcores: number of decores to apply configuration to
554 * set to HL_PB_SHARED if need to apply only once
555 * @dcore_offset: offset between dcores
556 * @num_instances: number of instances to apply configuration to
557 * @instance_offset: offset between instances
558 * @pb_blocks: blocks array
559 * @blocks_array_size: blocks array size
560 * @mask: enabled instances mask: 1- enabled, 0- disabled
561 *
562 */
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)563 void 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 configuration
586 *
587 * @hdev: pointer to hl_device structure
588 * @num_dcores: number of decores to apply configuration to
589 * set to HL_PB_SHARED if need to apply only once
590 * @dcore_offset: offset between dcores
591 * @num_instances: number of instances to apply configuration to
592 * @instance_offset: offset between instances
593 * @pb_blocks: blocks array
594 * @blocks_array_size: blocks array size
595 *
596 */
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)597 void 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 HW
608 * according to given configuration
609 *
610 * @hdev: pointer to hl_device structure
611 * @dcore_offset: offset from dcore0
612 * @num_instances: number of instances to apply configuration to
613 * @instance_offset: offset between instances
614 * @pb_blocks: blocks array
615 * @blocks_array_size: blocks array size
616 *
617 */
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)618 void 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
hl_automated_get_block_base_addr(struct hl_device * hdev,struct hl_special_block_info * block_info,u32 major,u32 minor,u32 sub_minor)632 static 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 should
643 * be casted for driver use.
644 */
645 return (fw_block_base_address - lower_32_bits(prop->cfg_base_address));
646 }
647
hl_check_block_type_exclusion(struct hl_skip_blocks_cfg * skip_blocks_cfg,int block_type)648 static 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
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)661 static 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
hl_read_glbl_errors(struct hl_device * hdev,u32 blk_idx,u32 major,u32 minor,u32 sub_minor,void * data)687 static 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
hl_check_for_glbl_errors(struct hl_device * hdev)723 void 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
hl_iterate_special_blocks(struct hl_device * hdev,struct iterate_special_ctx * ctx)742 int 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