1 /*******************************************************************************
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright 2014 QLogic Corporation
22 * The contents of this file are subject to the terms of the
23 * QLogic End User License (the "License").
24 * You may not use this file except in compliance with the License.
25 *
26 * You can obtain a copy of the License at
27 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
28 * QLogic_End_User_Software_License.txt
29 * See the License for the specific language governing permissions
30 * and limitations under the License.
31 *
32 *
33 * Module Description:
34 * This file encapsulates all the functions required to support error
35 * recovery in E2. It is an isolated module that can be compiled in/out
36 * according to error recovery support in upper layer
37 *
38 *
39 ******************************************************************************/
40
41 #include "lm5710.h"
42 #include "aeu_inputs.h"
43 #include "lm_defs.h"
44 #include "general_atten_bits.h"
45 /**
46 * @Description
47 * This function should be called to acquire the leader lock. the leader
48 * lock should not be released until recovery process id done.
49 * The leader lock is not waited for, its a non-blockinf function
50 *
51 * @param pdev
52 *
53 * @return lm_status_t SUCCESS or FAILURE
54 */
lm_er_acquire_leader_lock(lm_device_t * pdev)55 lm_status_t lm_er_acquire_leader_lock(lm_device_t * pdev)
56 {
57 return lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_LEADER_0, FALSE);
58 }
59
60 /**
61 * @Description
62 * release the lock acquired in the previous function
63 * @param pdev
64 *
65 * @return lm_status_t SUCCESS, INVALID_PARAM: if invalid input
66 * is provided, LM_STATUS_OBJECT_NOT_FOUND if the lock
67 * isn't taken.
68 */
lm_er_release_leader_lock(lm_device_t * pdev)69 lm_status_t lm_er_release_leader_lock(lm_device_t * pdev)
70 {
71 return lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_LEADER_0);
72 }
73
74
75 /**
76 * @Description
77 * This function disables close the gate functionality
78 * should be called from the last driver that unloads
79 * (unless recovery is in progress)
80 *
81 * @param pdev
82 */
lm_er_disable_close_the_gate(lm_device_t * pdev)83 void lm_er_disable_close_the_gate(lm_device_t *pdev)
84 {
85 u32_t val;
86
87 DbgMessage(pdev, INFORMer, "Disabling \"close the gates\"\n");
88
89 if (CHIP_IS_E2(pdev) || CHIP_IS_E3(pdev))
90 {
91 val = REG_RD(pdev, MISC_REG_AEU_GENERAL_MASK);
92 val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK |
93 MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK);
94 REG_WR(pdev, MISC_REG_AEU_GENERAL_MASK, val);
95 }
96 }
97
98 /* Close gates #2, #3 and #4: */
lm_er_set_234_gates(lm_device_t * pdev,u8_t close_g8)99 static void lm_er_set_234_gates(lm_device_t *pdev, u8_t close_g8)
100 {
101 u32_t val, enable_bit;
102
103 enable_bit = close_g8? 1 : 0;
104
105 /* close gate #4 */
106 REG_WR(pdev, PXP_REG_HST_DISCARD_DOORBELLS, enable_bit);
107
108 /* close gate #2 */
109 REG_WR(pdev, PXP_REG_HST_DISCARD_INTERNAL_WRITES, enable_bit);
110
111 /* close gate #3 (this will disable new interrupts */
112 val = REG_RD(pdev, IGU_REG_BLOCK_CONFIGURATION);
113 close_g8? RESET_FLAGS(val, IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE) :
114 SET_FLAGS(val, IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE);
115
116 REG_WR(pdev, IGU_REG_BLOCK_CONFIGURATION, val);
117
118
119 DbgMessage(pdev, FATAL, "%s gates #2, #3 and #4\n",
120 close_g8 ? "closing" : "opening");
121
122 }
123
124
lm_er_pxp_prep(lm_device_t * pdev)125 static void lm_er_pxp_prep(lm_device_t *pdev)
126 {
127 if (!CHIP_IS_E1(pdev))
128 {
129 REG_WR(pdev, PXP2_REG_RD_START_INIT, 0);
130 REG_WR(pdev, PXP2_REG_RQ_RBC_DONE, 0);
131 }
132 }
133
134 /*
135 * Reset the whole chip except for:
136 * - PCIE core
137 * - PCI Glue, PSWHST, PXP/PXP2 RF (all controlled by
138 * one reset bit)
139 * - IGU
140 * - MISC (including AEU)
141 * - GRC
142 * - RBCN, RBCP
143 * Reset MCP ONLY if reset_mcp is TRUE
144 */
lm_er_process_kill_chip_reset(lm_device_t * pdev,u8_t reset_mcp)145 static void lm_er_process_kill_chip_reset(lm_device_t *pdev, u8_t reset_mcp)
146 {
147 u32_t not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2;
148
149 not_reset_mask1 =
150 MISC_REGISTERS_RESET_REG_1_RST_HC |
151 MISC_REGISTERS_RESET_REG_1_RST_PXPV |
152 MISC_REGISTERS_RESET_REG_1_RST_PXP;
153
154 not_reset_mask2 =
155 MISC_REGISTERS_RESET_REG_2_RST_PCI_MDIO |
156 MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE |
157 MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE |
158 MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE |
159 MISC_REGISTERS_RESET_REG_2_RST_RBCN |
160 MISC_REGISTERS_RESET_REG_2_RST_GRC |
161 MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
162 MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B;
163
164
165 reset_mask1 = 0xffffffff;
166 reset_mask2 = 0x1ffff;
167
168 if (!reset_mcp)
169 {
170 RESET_FLAGS(reset_mask2, MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CPU);
171 RESET_FLAGS(reset_mask2, MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CORE);
172 }
173
174 if (CHIP_IS_E3(pdev)) /* Maybe some day... */
175 {
176 reset_mask2 |= MISC_REGISTERS_RESET_REG_2_MSTAT0;
177 reset_mask2 |= MISC_REGISTERS_RESET_REG_2_MSTAT1;
178 }
179
180 /* CQ54250, CQ54294, CQ54298, CQ54396
181 * Error Recovery: break at evbda!lm_dmae_command+960 during error recovery,
182 * REG_1 must be called after reg_2 so that QM is reset AFTER PXP, this is because
183 * resetting QM cancels close the gates, initiates request to PXP
184 * <Ofer Zipin>: theory when QM is reset before PXP: 'close the gates' is de-activated shortly before resetting PXP.
185 * PSWRQ sends a write request to PGLUE. Then PXP is reset (PGLUE is not reset).
186 * PGLUE tries to read the payload data from PSWWR, but PSWWR does not respond. The write queue in PGLUE will be stuck.
187 */
188
189 REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
190 reset_mask2 & (~not_reset_mask2));
191
192 REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
193 reset_mask1 & (~not_reset_mask1));
194 /* Take blocks out of reset */
195 REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, reset_mask2);
196
197 REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1);
198
199
200
201 }
202
203 /**
204 * @Description
205 * 13.2 Poll for Tetris buffer to empty. PSWWR FIFOs are
206 * not guaraneteed to empty. wait for all Glue tags to
207 * become unused (all read completions have returned).
208 *
209 * @param pdev
210 *
211 * @return lm_status_t
212 */
lm_er_empty_tetris_buffer(lm_device_t * pdev)213 static lm_status_t lm_er_empty_tetris_buffer(lm_device_t * pdev)
214 {
215 u32_t cnt = 1000;
216 u32_t sr_cnt = 0;
217 u32_t blk_cnt = 0;
218 u32_t port_is_idle_0 = 0;
219 u32_t port_is_idle_1 = 0;
220 u32_t pgl_exp_rom2 = 0;
221 u32_t pgl_b_reg_tags = 0;
222
223 do {
224 sr_cnt = REG_RD(pdev, PXP2_REG_RD_SR_CNT);
225 blk_cnt = REG_RD(pdev, PXP2_REG_RD_BLK_CNT);
226 port_is_idle_0 = REG_RD(pdev, PXP2_REG_RD_PORT_IS_IDLE_0);
227 port_is_idle_1 = REG_RD(pdev, PXP2_REG_RD_PORT_IS_IDLE_1);
228 pgl_exp_rom2 = REG_RD(pdev, PXP2_REG_PGL_EXP_ROM2);
229 pgl_b_reg_tags = REG_RD(pdev, PGLUE_B_REG_TAGS_63_32);
230
231 if (TRUE
232 && (sr_cnt >= 0x7e)
233 && (blk_cnt == 0xa0)
234 && ((port_is_idle_0 & 0x1) == 0x1)
235 && ((port_is_idle_1 & 0x1) == 0x1)
236 && (pgl_exp_rom2 == 0xffffffff)
237 && (!CHIP_IS_E3(pdev) || (pgl_b_reg_tags == 0xffffffff)))
238 {
239 break;
240 }
241 mm_wait(pdev, 1000);
242 } while (cnt-- > 0);
243
244 if (cnt == 0) {
245 DbgMessage(pdev, FATAL, "Tetris buffer didn't get empty or there are still outstanding read requests after 1s!\n");
246 DbgMessage(pdev, FATAL, "sr_cnt=0x%08x, blk_cnt=0x%08x, port_is_idle_0=0x%08x, port_is_idle_1=0x%08x, pgl_exp_rom2=0x%08x\n",
247 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2);
248 return LM_STATUS_BUSY;
249 }
250
251 return LM_STATUS_SUCCESS;
252 }
253
254
255 /**
256 * @Description
257 * 13.5. Poll for IGU VQ to become empty
258 *
259 * @param pdev
260 *
261 * @return lm_status_t
262 */
lm_er_poll_igu_vq(lm_device_t * pdev)263 static lm_status_t lm_er_poll_igu_vq(lm_device_t * pdev)
264 {
265 u32_t cnt = 1000;
266 u32_t pend_bits = 0;
267
268 do {
269 pend_bits = REG_RD(pdev, IGU_REG_PENDING_BITS_STATUS);
270
271 if (pend_bits == 0)
272 {
273 break;
274 }
275 mm_wait(pdev, 1000);
276 } while (cnt-- > 0);
277
278 if (cnt == 0) {
279 DbgMessage(pdev, FATAL, "Still pending IGU requests pend_bits=%x!\n", pend_bits);
280
281 return LM_STATUS_BUSY;
282 }
283
284 return LM_STATUS_SUCCESS;
285 }
286
287 /**
288 * @Description
289 * This section is based on E2 Recovery Flows Design
290 * document by Yuval Eliyahu. Section 12.2 (process kill)
291 * item #13. Number below refer to items inside item #13.
292 * Some modifications were made to accomidate to E2.
293 *
294 * @param pdev
295 *
296 * @return lm_status_t
297 */
lm_er_process_kill(lm_device_t * pdev,u8_t reset_mcp)298 static lm_status_t lm_er_process_kill(lm_device_t *pdev, u8_t reset_mcp)
299 {
300 lm_status_t lm_status = LM_STATUS_FAILURE;
301 u32_t magic_val = 0;
302
303 /* 13.2 Empty the Tetris buffer, wait for 1s TODO_ER: is this needed for E2? */
304 lm_status = lm_er_empty_tetris_buffer(pdev);
305 if (lm_status != LM_STATUS_SUCCESS)
306 {
307 return lm_status;
308 }
309
310 /* 13.3, 13.4 Close gates #2, #3 and #4 */
311 lm_er_set_234_gates(pdev, TRUE);
312
313 /* 13.5 Poll for IGU VQ to become empty */
314 lm_status = lm_er_poll_igu_vq(pdev);
315 if (lm_status != LM_STATUS_SUCCESS)
316 {
317 return lm_status;
318 }
319
320 /* 13.6 Indicate that "process kill" is in progress to MCP TODO_ER: how/why? */
321
322 /* 13.7 Clear "unprepared" bit */
323 REG_WR(pdev, MISC_REG_UNPREPARED, 0);
324
325 /* 13.8 Wait for 1ms to empty GLUE and PCI-E core queues,
326 * PSWHST, GRC and PSWRD Tetris buffer.
327 */
328 mm_wait(pdev, 1000);
329
330 /* Prepare to chip reset: */
331 /* MCP */
332 if (reset_mcp)
333 {
334 lm_reset_mcp_prep(pdev, &magic_val);
335 }
336
337 /* 13.11.1 PXP preparations TODO_ER: should this really be called before or only after
338 * spec says after, bnx2x implementation does this before as well. */
339 lm_er_pxp_prep(pdev);
340
341 /* 13.9 reset the chip */
342 /* 13.10 check that PSWRD, PSWRQ, PSWWR are reset : handled in function */
343 lm_er_process_kill_chip_reset(pdev, reset_mcp);
344
345
346 /* 13.11 Recover after reset: */
347 /* MCP */
348 if (reset_mcp)
349 {
350 lm_status = lm_reset_mcp_comp(pdev, magic_val);
351 if (lm_status != LM_STATUS_SUCCESS)
352 {
353 return lm_status;
354 }
355 }
356
357 /* Reset the loader for no-mcp mode, mcp has been reset!! */
358 lm_loader_reset(pdev);
359
360 /* 13.11.1.2 PXP */
361
362 // PXP2 initialization skipped here to address CQ61863:
363 // - PXP2 must not be re-initialized.
364 // - Starting MCP 7.0.45, PXP2 is initialized by MCP.
365
366 //lm_er_pxp_prep(pdev);
367
368 /* 13.11.2 Open the gates #2, #3 and #4 */
369 lm_er_set_234_gates(pdev, FALSE);
370
371 /* 13.11.3 TODO_ER: IGU/AEU preparation bring back the AEU/IGU to a
372 * reset state, re-enable attentions. This is done in "init" */
373
374 /* Clear the general attention used to notify second engine */
375 REG_WR(pdev, MISC_REG_AEU_GENERAL_ATTN_20 , 0);
376 /* Some Notes:
377 * 1. parity bits will be cleard for blocks that are being reset, so no need to take care of it...
378 * 2. MCP notification isn't handled yet, when it is leader will need to nofity mcp reset is done.
379 */
380 return 0;
381 }
382
383
384 /**
385 * @Description
386 * Perform the error recovery leader process kill flow.
387 *
388 * @param pdev
389 *
390 * @return lm_status_t SUCCESS or FAILURE
391 */
lm_er_leader_reset(lm_device_t * pdev)392 lm_status_t lm_er_leader_reset(lm_device_t *pdev)
393 {
394 lm_status_t lm_status = LM_STATUS_SUCCESS;
395 u32_t cnt = 1;
396 u8_t reset_mcp = FALSE;
397 u8_t function_of_opposite_path = 0;
398
399 /* Try to recover after the failure */
400 /* need to recover on both paths using pretend */
401 function_of_opposite_path = !PATH_ID(pdev);
402 do
403 {
404 lm_status = lm_er_process_kill(pdev, reset_mcp);
405 if (lm_status != LM_STATUS_SUCCESS)
406 {
407 break;
408 }
409
410 /* Pretend to the other path... */
411 if (!reset_mcp)
412 {
413 lm_pretend_func(pdev, function_of_opposite_path);
414 /* Only second go should reset MCP, so that the second engine doesn't get out of close-dg8 before the process is done */
415 reset_mcp = TRUE;
416 }
417 } while (cnt--);
418
419 /* in anycase pretend back... */
420 lm_pretend_func(pdev, ABS_FUNC_ID(pdev));
421
422 return lm_status;
423 }
424
425 /**
426 * @Description
427 * This function notifies the second engine that a
428 * attention occured and error recovery will initiate on
429 * second engine as well. Only the leader does this meaning
430 * that the second engine either hasn't seen that there was
431 * an error, or seen it and is waiting (won't initiate
432 * leader reset) which means it won't see it anyway...
433 * @param pdev
434 *
435 * @return lm_status_t
436 */
lm_er_notify_other_path(lm_device_t * pdev)437 lm_status_t lm_er_notify_other_path(lm_device_t *pdev)
438 {
439 u8_t function_of_opposite_path = 0;
440
441 DbgMessage(pdev, FATAL, "lm_er_notify_other_path\n");
442 /* Pretend to the other path... */
443 function_of_opposite_path = lm_er_get_first_func_of_opp_path(pdev);
444 if (function_of_opposite_path != 0xFF)
445 {
446 lm_pretend_func(pdev, function_of_opposite_path);
447
448 REG_WR(pdev, MISC_REG_AEU_GENERAL_ATTN_20 , 1);
449
450 /* in anycase pretend back... */
451 lm_pretend_func(pdev, ABS_FUNC_ID(pdev));
452 }
453 else
454 {
455 DbgMessage(pdev, FATAL, "No ebnabled functions on path%d, the pah is not notfied about ER\n",!PATH_ID(pdev));
456 }
457
458 return LM_STATUS_SUCCESS;
459 }
460
461 /**
462 * @Description
463 * This function attaches attentions to NIG / PXP
464 * close-the-g8, any attention that is added here should
465 * also be added to the lm_recoverable_error function.
466 * @param pdev
467 */
lm_er_config_close_the_g8(lm_device_t * pdev)468 void lm_er_config_close_the_g8(lm_device_t *pdev)
469 {
470 u32_t val;
471
472 if (!pdev->params.enable_error_recovery || CHIP_IS_E1x(pdev))
473 {
474 return;
475 }
476
477 /* HW Attentions (Except Parity which is configured by init-tool / reset-values ) */
478
479 /* QM Block */
480 val = REG_RD(pdev, MISC_REG_AEU_ENABLE2_NIG_0);
481 SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT); /* QM HW Interrupt */
482 REG_WR(pdev, MISC_REG_AEU_ENABLE2_NIG_0, val);
483
484 val = REG_RD(pdev, MISC_REG_AEU_ENABLE2_PXP_0);
485 SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT); /* QM HW Interrupt */
486 REG_WR(pdev, MISC_REG_AEU_ENABLE2_PXP_0, val);
487
488 /* General Attention 20 (error recovery attention) */
489 val = REG_RD(pdev, MISC_REG_AEU_ENABLE4_NIG_0);
490 SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_GRC_MAPPED_GENERAL_ATTN20); /* general attention 20 */
491 REG_WR(pdev, MISC_REG_AEU_ENABLE4_NIG_0, val);
492
493 val = REG_RD(pdev, MISC_REG_AEU_ENABLE4_PXP_0);
494 SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_GRC_MAPPED_GENERAL_ATTN20); /* general attention 20 */
495 REG_WR(pdev, MISC_REG_AEU_ENABLE4_PXP_0, val);
496
497 }
498
lm_er_get_func_bit(struct _lm_device_t * pdev)499 u32_t lm_er_get_func_bit(struct _lm_device_t *pdev)
500 {
501 u32_t func_bit = 1 << ABS_FUNC_ID(pdev);
502 return func_bit;
503 }
504
lm_er_get_number_of_functions(u32_t er_register)505 u32_t lm_er_get_number_of_functions(u32_t er_register)
506 {
507 u8_t i = 0;
508 u32_t func_num = 0;
509 for (i = 0; i < MAX_FUNC_NUM; i++)
510 {
511 if (er_register & (1 << i))
512 {
513 func_num++;
514 }
515 }
516 return func_num;
517 }
518
lm_er_get_first_func_of_opp_path(struct _lm_device_t * pdev)519 u8_t lm_er_get_first_func_of_opp_path(struct _lm_device_t *pdev)
520 {
521 lm_status_t lm_status = LM_STATUS_SUCCESS;
522 u32_t por_aux_register = 0;
523 u8_t opposite_path = 0;
524 u8_t i = 0;
525 u8_t func_of_opp_path = 0xFF;
526
527 if (IS_ASSIGNED_TO_VM_PFDEV(pdev))
528 {
529 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
530 if (LM_STATUS_SUCCESS == lm_status)
531 {
532 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
533 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
534 if (LM_STATUS_SUCCESS != lm_status)
535 {
536 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
537 }
538 opposite_path = !PATH_ID(pdev);
539 for (i = 0; i < MAX_FUNC_NUM/2; i++)
540 {
541 if (por_aux_register & (1 << (i*2 + opposite_path)))
542 {
543 func_of_opp_path = i*2 + opposite_path;
544 break;
545 }
546 }
547 }
548 else
549 {
550 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
551 }
552 }
553 else
554 {
555 func_of_opp_path = !PATH_ID(pdev);
556 }
557 return func_of_opp_path;
558 }
559
lm_er_inc_load_cnt(lm_device_t * pdev,u8_t sync_it)560 u32_t lm_er_inc_load_cnt(lm_device_t *pdev, u8_t sync_it)
561 {
562 lm_status_t lm_status = LM_STATUS_SUCCESS;
563 u32_t counter = 0;
564 u32_t por_aux_register = 0;
565 u32_t func_er_bit = 0;
566
567 if (sync_it)
568 {
569 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
570 }
571
572 if (LM_STATUS_SUCCESS == lm_status)
573 {
574 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
575 func_er_bit = lm_er_get_func_bit(pdev);
576 if ((por_aux_register & func_er_bit))
577 {
578 if (sync_it)
579 {
580 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
581 }
582 DbgMessage(pdev, FATAL, "HW Recovery bit was not cleared in previous session.\n");
583 pdev->debug_info.er_bit_is_set_already = TRUE;
584 pdev->debug_info.er_bit_from_previous_sessions++;
585 }
586 else
587 {
588 por_aux_register |= func_er_bit;
589 REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
590 pdev->debug_info.er_bit_is_set_already = FALSE;
591 if (sync_it)
592 {
593 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
594 }
595 }
596 if (LM_STATUS_SUCCESS != lm_status)
597 {
598 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
599 }
600 counter = lm_er_get_number_of_functions(por_aux_register);
601 }
602 else
603 {
604 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
605 }
606 return counter;
607 }
608
lm_er_dec_load_cnt(lm_device_t * pdev,u8_t sync_it)609 u32_t lm_er_dec_load_cnt(lm_device_t *pdev, u8_t sync_it)
610 {
611 lm_status_t lm_status = LM_STATUS_SUCCESS;
612 u32_t counter = 0;
613 u32_t por_aux_register = 0;
614 u32_t func_er_bit = 0;
615
616 if (sync_it)
617 {
618 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
619 }
620
621 if (LM_STATUS_SUCCESS == lm_status)
622 {
623 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
624 func_er_bit = lm_er_get_func_bit(pdev);
625 if (!(por_aux_register & func_er_bit))
626 {
627 if (sync_it)
628 {
629 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
630 }
631 DbgMessage(pdev, FATAL, "HW Recovery bit is clear already.\n");
632 }
633 else
634 {
635 por_aux_register &= ~func_er_bit;
636 REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
637 if (sync_it)
638 {
639 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
640 }
641 }
642 if (LM_STATUS_SUCCESS != lm_status)
643 {
644 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
645 }
646 counter = lm_er_get_number_of_functions(por_aux_register);
647 }
648 else
649 {
650 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
651 }
652 return counter;
653 }
654
lm_er_get_load_cnt(lm_device_t * pdev,u8_t sync_it)655 u32_t lm_er_get_load_cnt(lm_device_t *pdev, u8_t sync_it)
656 {
657 lm_status_t lm_status = LM_STATUS_SUCCESS;
658 u32_t counter = 0;
659 u32_t por_aux_register = 0;
660
661 if (sync_it)
662 {
663 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
664 }
665
666 if (LM_STATUS_SUCCESS == lm_status)
667 {
668 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
669 if (sync_it)
670 {
671 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
672 if (LM_STATUS_SUCCESS != lm_status)
673 {
674 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
675 }
676 }
677 counter = lm_er_get_number_of_functions(por_aux_register);
678 }
679 else
680 {
681 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
682 }
683 return counter;
684 }
685
lm_er_clear_load_cnt(lm_device_t * pdev,u8_t sync_it)686 void lm_er_clear_load_cnt(lm_device_t *pdev, u8_t sync_it)
687 {
688 lm_status_t lm_status = LM_STATUS_SUCCESS;
689
690 if (sync_it)
691 {
692 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
693 }
694 if (LM_STATUS_SUCCESS == lm_status)
695 {
696 REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, 0);
697 if (sync_it)
698 {
699 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
700 if (LM_STATUS_SUCCESS != lm_status)
701 {
702 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
703 }
704 }
705 }
706 else
707 {
708 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
709 }
710 }
711
lm_er_set_recover_done(lm_device_t * pdev,u8_t sync_it)712 void lm_er_set_recover_done(lm_device_t *pdev, u8_t sync_it)
713 {
714 lm_status_t lm_status = LM_STATUS_SUCCESS;
715 u32_t por_aux_register = 0;
716
717
718 DbgMessage(pdev, FATAL, "Setting recovery in progress = 0\n");
719 if (sync_it)
720 {
721 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
722 }
723 if (LM_STATUS_SUCCESS == lm_status)
724 {
725 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
726 por_aux_register &= ~LM_ERROR_RECOVERY_IN_PROGRESS_FLAG;
727 REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
728 if (sync_it)
729 {
730 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
731 if (LM_STATUS_SUCCESS != lm_status)
732 {
733 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
734 }
735 }
736 }
737 else
738 {
739 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
740 }
741 }
742
lm_er_set_recover_in_progress(lm_device_t * pdev,u8_t sync_it)743 void lm_er_set_recover_in_progress(lm_device_t *pdev, u8_t sync_it)
744 {
745 lm_status_t lm_status = LM_STATUS_SUCCESS;
746 u32_t por_aux_register = 0;
747
748 DbgMessage(pdev, FATAL, "Setting recovery in progress = 1\n");
749 if (sync_it)
750 {
751 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
752 }
753 if (LM_STATUS_SUCCESS == lm_status)
754 {
755 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
756 por_aux_register |= LM_ERROR_RECOVERY_IN_PROGRESS_FLAG;
757 REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
758 if (sync_it)
759 {
760 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
761 if (LM_STATUS_SUCCESS != lm_status)
762 {
763 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
764 }
765 }
766 }
767 else
768 {
769 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
770 }
771 }
772
773
lm_er_recovery_in_progress(lm_device_t * pdev,u8_t sync_it)774 u8_t lm_er_recovery_in_progress(lm_device_t *pdev, u8_t sync_it)
775 {
776 lm_status_t lm_status = LM_STATUS_SUCCESS;
777 u32_t por_aux_register = 0;
778 u8_t is_progress = FALSE;
779
780 if (sync_it)
781 {
782 lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
783 }
784 if (LM_STATUS_SUCCESS == lm_status)
785 {
786 por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
787 if (sync_it)
788 {
789 lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
790 if (LM_STATUS_SUCCESS != lm_status)
791 {
792 DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
793 }
794 }
795 if (por_aux_register & LM_ERROR_RECOVERY_IN_PROGRESS_FLAG)
796 {
797 is_progress = TRUE;
798 }
799 }
800 else
801 {
802 DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
803 }
804 return is_progress;
805 }
806
807