#include "lm5710.h"
#include "aeu_inputs.h"
#include "lm_defs.h"
#include "general_atten_bits.h"
lm_status_t lm_er_acquire_leader_lock(lm_device_t * pdev)
{
return lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_LEADER_0, FALSE);
}
lm_status_t lm_er_release_leader_lock(lm_device_t * pdev)
{
return lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_LEADER_0);
}
void lm_er_disable_close_the_gate(lm_device_t *pdev)
{
u32_t val;
DbgMessage(pdev, INFORMer, "Disabling \"close the gates\"\n");
if (CHIP_IS_E2(pdev) || CHIP_IS_E3(pdev))
{
val = REG_RD(pdev, MISC_REG_AEU_GENERAL_MASK);
val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK |
MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK);
REG_WR(pdev, MISC_REG_AEU_GENERAL_MASK, val);
}
}
static void lm_er_set_234_gates(lm_device_t *pdev, u8_t close_g8)
{
u32_t val, enable_bit;
enable_bit = close_g8? 1 : 0;
REG_WR(pdev, PXP_REG_HST_DISCARD_DOORBELLS, enable_bit);
REG_WR(pdev, PXP_REG_HST_DISCARD_INTERNAL_WRITES, enable_bit);
val = REG_RD(pdev, IGU_REG_BLOCK_CONFIGURATION);
close_g8? RESET_FLAGS(val, IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE) :
SET_FLAGS(val, IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE);
REG_WR(pdev, IGU_REG_BLOCK_CONFIGURATION, val);
DbgMessage(pdev, FATAL, "%s gates #2, #3 and #4\n",
close_g8 ? "closing" : "opening");
}
static void lm_er_pxp_prep(lm_device_t *pdev)
{
if (!CHIP_IS_E1(pdev))
{
REG_WR(pdev, PXP2_REG_RD_START_INIT, 0);
REG_WR(pdev, PXP2_REG_RQ_RBC_DONE, 0);
}
}
static void lm_er_process_kill_chip_reset(lm_device_t *pdev, u8_t reset_mcp)
{
u32_t not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2;
not_reset_mask1 =
MISC_REGISTERS_RESET_REG_1_RST_HC |
MISC_REGISTERS_RESET_REG_1_RST_PXPV |
MISC_REGISTERS_RESET_REG_1_RST_PXP;
not_reset_mask2 =
MISC_REGISTERS_RESET_REG_2_RST_PCI_MDIO |
MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE |
MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE |
MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE |
MISC_REGISTERS_RESET_REG_2_RST_RBCN |
MISC_REGISTERS_RESET_REG_2_RST_GRC |
MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B;
reset_mask1 = 0xffffffff;
reset_mask2 = 0x1ffff;
if (!reset_mcp)
{
RESET_FLAGS(reset_mask2, MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CPU);
RESET_FLAGS(reset_mask2, MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CORE);
}
if (CHIP_IS_E3(pdev))
{
reset_mask2 |= MISC_REGISTERS_RESET_REG_2_MSTAT0;
reset_mask2 |= MISC_REGISTERS_RESET_REG_2_MSTAT1;
}
REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
reset_mask2 & (~not_reset_mask2));
REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
reset_mask1 & (~not_reset_mask1));
REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, reset_mask2);
REG_WR(pdev, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1);
}
static lm_status_t lm_er_empty_tetris_buffer(lm_device_t * pdev)
{
u32_t cnt = 1000;
u32_t sr_cnt = 0;
u32_t blk_cnt = 0;
u32_t port_is_idle_0 = 0;
u32_t port_is_idle_1 = 0;
u32_t pgl_exp_rom2 = 0;
u32_t pgl_b_reg_tags = 0;
do {
sr_cnt = REG_RD(pdev, PXP2_REG_RD_SR_CNT);
blk_cnt = REG_RD(pdev, PXP2_REG_RD_BLK_CNT);
port_is_idle_0 = REG_RD(pdev, PXP2_REG_RD_PORT_IS_IDLE_0);
port_is_idle_1 = REG_RD(pdev, PXP2_REG_RD_PORT_IS_IDLE_1);
pgl_exp_rom2 = REG_RD(pdev, PXP2_REG_PGL_EXP_ROM2);
pgl_b_reg_tags = REG_RD(pdev, PGLUE_B_REG_TAGS_63_32);
if (TRUE
&& (sr_cnt >= 0x7e)
&& (blk_cnt == 0xa0)
&& ((port_is_idle_0 & 0x1) == 0x1)
&& ((port_is_idle_1 & 0x1) == 0x1)
&& (pgl_exp_rom2 == 0xffffffff)
&& (!CHIP_IS_E3(pdev) || (pgl_b_reg_tags == 0xffffffff)))
{
break;
}
mm_wait(pdev, 1000);
} while (cnt-- > 0);
if (cnt == 0) {
DbgMessage(pdev, FATAL, "Tetris buffer didn't get empty or there are still outstanding read requests after 1s!\n");
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",
sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2);
return LM_STATUS_BUSY;
}
return LM_STATUS_SUCCESS;
}
static lm_status_t lm_er_poll_igu_vq(lm_device_t * pdev)
{
u32_t cnt = 1000;
u32_t pend_bits = 0;
do {
pend_bits = REG_RD(pdev, IGU_REG_PENDING_BITS_STATUS);
if (pend_bits == 0)
{
break;
}
mm_wait(pdev, 1000);
} while (cnt-- > 0);
if (cnt == 0) {
DbgMessage(pdev, FATAL, "Still pending IGU requests pend_bits=%x!\n", pend_bits);
return LM_STATUS_BUSY;
}
return LM_STATUS_SUCCESS;
}
static lm_status_t lm_er_process_kill(lm_device_t *pdev, u8_t reset_mcp)
{
lm_status_t lm_status = LM_STATUS_FAILURE;
u32_t magic_val = 0;
lm_status = lm_er_empty_tetris_buffer(pdev);
if (lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_er_set_234_gates(pdev, TRUE);
lm_status = lm_er_poll_igu_vq(pdev);
if (lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
REG_WR(pdev, MISC_REG_UNPREPARED, 0);
mm_wait(pdev, 1000);
if (reset_mcp)
{
lm_reset_mcp_prep(pdev, &magic_val);
}
lm_er_pxp_prep(pdev);
lm_er_process_kill_chip_reset(pdev, reset_mcp);
if (reset_mcp)
{
lm_status = lm_reset_mcp_comp(pdev, magic_val);
if (lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
}
lm_loader_reset(pdev);
lm_er_set_234_gates(pdev, FALSE);
REG_WR(pdev, MISC_REG_AEU_GENERAL_ATTN_20 , 0);
return 0;
}
lm_status_t lm_er_leader_reset(lm_device_t *pdev)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t cnt = 1;
u8_t reset_mcp = FALSE;
u8_t function_of_opposite_path = 0;
function_of_opposite_path = !PATH_ID(pdev);
do
{
lm_status = lm_er_process_kill(pdev, reset_mcp);
if (lm_status != LM_STATUS_SUCCESS)
{
break;
}
if (!reset_mcp)
{
lm_pretend_func(pdev, function_of_opposite_path);
reset_mcp = TRUE;
}
} while (cnt--);
lm_pretend_func(pdev, ABS_FUNC_ID(pdev));
return lm_status;
}
lm_status_t lm_er_notify_other_path(lm_device_t *pdev)
{
u8_t function_of_opposite_path = 0;
DbgMessage(pdev, FATAL, "lm_er_notify_other_path\n");
function_of_opposite_path = lm_er_get_first_func_of_opp_path(pdev);
if (function_of_opposite_path != 0xFF)
{
lm_pretend_func(pdev, function_of_opposite_path);
REG_WR(pdev, MISC_REG_AEU_GENERAL_ATTN_20 , 1);
lm_pretend_func(pdev, ABS_FUNC_ID(pdev));
}
else
{
DbgMessage(pdev, FATAL, "No ebnabled functions on path%d, the pah is not notfied about ER\n",!PATH_ID(pdev));
}
return LM_STATUS_SUCCESS;
}
void lm_er_config_close_the_g8(lm_device_t *pdev)
{
u32_t val;
if (!pdev->params.enable_error_recovery || CHIP_IS_E1x(pdev))
{
return;
}
val = REG_RD(pdev, MISC_REG_AEU_ENABLE2_NIG_0);
SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT);
REG_WR(pdev, MISC_REG_AEU_ENABLE2_NIG_0, val);
val = REG_RD(pdev, MISC_REG_AEU_ENABLE2_PXP_0);
SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT);
REG_WR(pdev, MISC_REG_AEU_ENABLE2_PXP_0, val);
val = REG_RD(pdev, MISC_REG_AEU_ENABLE4_NIG_0);
SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_GRC_MAPPED_GENERAL_ATTN20);
REG_WR(pdev, MISC_REG_AEU_ENABLE4_NIG_0, val);
val = REG_RD(pdev, MISC_REG_AEU_ENABLE4_PXP_0);
SET_FLAGS(val, AEU_INPUTS_ATTN_BITS_GRC_MAPPED_GENERAL_ATTN20);
REG_WR(pdev, MISC_REG_AEU_ENABLE4_PXP_0, val);
}
u32_t lm_er_get_func_bit(struct _lm_device_t *pdev)
{
u32_t func_bit = 1 << ABS_FUNC_ID(pdev);
return func_bit;
}
u32_t lm_er_get_number_of_functions(u32_t er_register)
{
u8_t i = 0;
u32_t func_num = 0;
for (i = 0; i < MAX_FUNC_NUM; i++)
{
if (er_register & (1 << i))
{
func_num++;
}
}
return func_num;
}
u8_t lm_er_get_first_func_of_opp_path(struct _lm_device_t *pdev)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t por_aux_register = 0;
u8_t opposite_path = 0;
u8_t i = 0;
u8_t func_of_opp_path = 0xFF;
if (IS_ASSIGNED_TO_VM_PFDEV(pdev))
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
opposite_path = !PATH_ID(pdev);
for (i = 0; i < MAX_FUNC_NUM/2; i++)
{
if (por_aux_register & (1 << (i*2 + opposite_path)))
{
func_of_opp_path = i*2 + opposite_path;
break;
}
}
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
}
else
{
func_of_opp_path = !PATH_ID(pdev);
}
return func_of_opp_path;
}
u32_t lm_er_inc_load_cnt(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t counter = 0;
u32_t por_aux_register = 0;
u32_t func_er_bit = 0;
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
func_er_bit = lm_er_get_func_bit(pdev);
if ((por_aux_register & func_er_bit))
{
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
}
DbgMessage(pdev, FATAL, "HW Recovery bit was not cleared in previous session.\n");
pdev->debug_info.er_bit_is_set_already = TRUE;
pdev->debug_info.er_bit_from_previous_sessions++;
}
else
{
por_aux_register |= func_er_bit;
REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
pdev->debug_info.er_bit_is_set_already = FALSE;
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
}
}
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
counter = lm_er_get_number_of_functions(por_aux_register);
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
return counter;
}
u32_t lm_er_dec_load_cnt(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t counter = 0;
u32_t por_aux_register = 0;
u32_t func_er_bit = 0;
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
func_er_bit = lm_er_get_func_bit(pdev);
if (!(por_aux_register & func_er_bit))
{
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
}
DbgMessage(pdev, FATAL, "HW Recovery bit is clear already.\n");
}
else
{
por_aux_register &= ~func_er_bit;
REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
}
}
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
counter = lm_er_get_number_of_functions(por_aux_register);
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
return counter;
}
u32_t lm_er_get_load_cnt(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t counter = 0;
u32_t por_aux_register = 0;
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
}
counter = lm_er_get_number_of_functions(por_aux_register);
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
return counter;
}
void lm_er_clear_load_cnt(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, 0);
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
}
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
}
void lm_er_set_recover_done(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t por_aux_register = 0;
DbgMessage(pdev, FATAL, "Setting recovery in progress = 0\n");
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
por_aux_register &= ~LM_ERROR_RECOVERY_IN_PROGRESS_FLAG;
REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
}
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
}
void lm_er_set_recover_in_progress(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t por_aux_register = 0;
DbgMessage(pdev, FATAL, "Setting recovery in progress = 1\n");
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
por_aux_register |= LM_ERROR_RECOVERY_IN_PROGRESS_FLAG;
REG_WR(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER, por_aux_register);
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
}
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
}
u8_t lm_er_recovery_in_progress(lm_device_t *pdev, u8_t sync_it)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t por_aux_register = 0;
u8_t is_progress = FALSE;
if (sync_it)
{
lm_status = lm_hw_lock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG, TRUE);
}
if (LM_STATUS_SUCCESS == lm_status)
{
por_aux_register = REG_RD(pdev, LM_ERROR_RECOVERY_COUNTER_HW_REGISTER);
if (sync_it)
{
lm_status = lm_hw_unlock(pdev, HW_LOCK_RESOURCE_RECOVERY_REG);
if (LM_STATUS_SUCCESS != lm_status)
{
DbgBreakMsg("Failed to release HW Recovery Counter lock.\n");
}
}
if (por_aux_register & LM_ERROR_RECOVERY_IN_PROGRESS_FLAG)
{
is_progress = TRUE;
}
}
else
{
DbgBreakMsg("Failed to acquire HW Recovery Counter lock.\n");
}
return is_progress;
}