root/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/l2_dbg.c
#include "lm5710.h"
#include "command.h"

/* Zeros all attn_bits/ack back to the start, along with the state and the original mask of AEU lines
 *
 * Parameters:
 * pdev      - this is the LM device
 */
static void dbg_zero_all_attn(lm_device_t *pdev)
{
        volatile struct host_def_status_block *def_sb = NULL;

        DbgMessage(pdev, INFORMi, "dbg_zero_all_attn() inside!\n");

    def_sb = lm_get_default_status_block(pdev);
    DbgBreakIf(!def_sb);

    def_sb->atten_status_block.attn_bits     = 0;
    def_sb->atten_status_block.attn_bits_ack = 0;
    pdev->vars.aeu_mask_attn_func            = 0x303;
    pdev->vars.attn_state                    = 0;
}

/* modifies attn_bits to '1' asserted state
 *
 * Parameters:
 * pdev      - this is the LM device
 * lines_to_assert - lines which goes up (asserted)
 */
static void dbg_assert_attn_lines(lm_device_t *pdev, u16_t lines_to_assert)
{
        volatile struct host_def_status_block *def_sb = NULL;

        DbgMessage1(pdev, INFORMi, "dbg_assert_attn_lines() inside! lines_to_assert:0x%x\n", lines_to_assert);

    def_sb = lm_get_default_status_block(pdev);
    DbgBreakIf(!def_sb);
    DbgBreakIf(mm_le32_to_cpu(def_sb->atten_status_block.attn_bits) & lines_to_assert);

    /*
    attns bits  line_to_assert
        1           1             -> ERROR
        1           0             -> 1
        0           0             -> 0
        0           1             -> 1
    */
    def_sb->atten_status_block.attn_bits |= mm_cpu_to_le32(lines_to_assert);
}

/* modifies attn_bits to '0' deasserted state
 *
 * Parameters:
 * pdev      - this is the LM device
 * lines_to_deassert - lines which goes down (deasserted)
 */
static void dbg_deassert_attn_lines(lm_device_t *pdev, u16_t lines_to_deassert)
{
        volatile struct host_def_status_block *def_sb = NULL;

        DbgMessage1(pdev, INFORMi, "dbg_deassert_attn_lines() inside! lines_to_deassert:0x%x\n", lines_to_deassert);

    def_sb = lm_get_default_status_block(pdev);
    DbgBreakIf(!def_sb);
    DbgBreakIf(~mm_le32_to_cpu(def_sb->atten_status_block.attn_bits) & lines_to_deassert);
/*
    attns bits  line_to_deassert
        1           1             -> 0
        1           0             -> 1
        0           0             -> 0
        0           1             -> ERROR
*/
    def_sb->atten_status_block.attn_bits ^= mm_cpu_to_le32(lines_to_deassert);
}

/* modifies attn_ack to '1' asserted state
 *
 * Parameters:
 * pdev      - this is the LM device
 * assert_lines_to_ack - lines for which we simulate a write of '1' to the attn_ack (asserted)
 */
static void dbg_ack_assert_attn_lines(lm_device_t *pdev, u16_t assert_lines_to_ack)
{
        volatile struct host_def_status_block *def_sb = NULL;

        DbgMessage1(pdev, INFORMi, "dbg_ack_assert_attn_lines() inside! assert_lines_to_ack:0x%x\n", assert_lines_to_ack);

    def_sb = lm_get_default_status_block(pdev);
    DbgBreakIf(!def_sb);
    DbgBreakIf(mm_le32_to_cpu(def_sb->atten_status_block.attn_bits_ack) & assert_lines_to_ack);
/*
    attns bits ack  assert_lines_to_ack
        1                1             -> ERROR
        1                0             -> 1
        0                0             -> 0
        0                1             -> 1
*/
    def_sb->atten_status_block.attn_bits_ack ^= mm_cpu_to_le32(assert_lines_to_ack);
}

/* modifies attn_ack to '0' deasserted state
 *
 * Parameters:
 * pdev      - this is the LM device
 * deassert_lines_to_ack - lines for which we simulate a write of '0' to the attn_ack (deasserted)
 */
/*
static void dbg_ack_deassert_attn_lines(lm_device_t *pdev, u16_t deassert_lines_to_ack)
{
        volatile struct host_def_status_block *def_sb = NULL;

        DbgMessage1(pdev, INFORMi, "dbg_ack_deassert_attn_lines() inside! deassert_lines_to_ack:0x%x\n", deassert_lines_to_ack);

    def_sb = lm_get_default_status_block(pdev);
    DbgBreakIf(!def_sb);
    DbgBreakIf(~def_sb->atten_status_block.attn_bits_ack & deassert_lines_to_ack);

    //attns bits ack  deassert_lines_to_ack
    //    1                1             -> 0
    //    1                0             -> 1
    //    0                0             -> 0
    //    0                1             -> ERROR

    def_sb->atten_status_block.attn_bits_ack ^= deassert_lines_to_ack;
}
*/

static void dbg_change_sb_index(lm_device_t *pdev, u8_t rss_id)
{
        volatile struct host_status_block *rss_sb         = NULL;
        volatile struct host_def_status_block *def_sb = NULL;

        DbgBreakIf(!pdev || rss_id > MAX_RSS_CHAINS);
        DbgMessage(pdev, INFORMi, "dbg_change_sb_index() inside!\n");
        //this is the default status block
        if(rss_id == DEF_STATUS_BLOCK_INDEX)
        {
                def_sb = lm_get_default_status_block(pdev);
                DbgBreakIf(!def_sb);
                //increment the status index of all storms for this status block
                def_sb->c_def_status_block.status_block_index = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->c_def_status_block.status_block_index) + 1);
                def_sb->u_def_status_block.status_block_index = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->u_def_status_block.status_block_index) + 1);
                def_sb->x_def_status_block.status_block_index = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->x_def_status_block.status_block_index) + 1);
                def_sb->t_def_status_block.status_block_index = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->t_def_status_block.status_block_index) + 1);
                def_sb->atten_status_block.attn_bits_index    = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->atten_status_block.attn_bits_index) + 1);

                DbgMessage6(pdev, INFORMi, "dbg_change_sb_index():sb#%d indices are now: c_def_prod_idx:%d, u_def_prod_idx:%d, x_def_prod_idx:%d, t_def_prod_idx:%d\n",
                        rss_id,
                        mm_le16_to_cpu(def_sb->c_def_status_block.status_block_index),
                        mm_le16_to_cpu(def_sb->u_def_status_block.status_block_index),
                        mm_le16_to_cpu(def_sb->x_def_status_block.status_block_index),
                        mm_le16_to_cpu(def_sb->t_def_status_block.status_block_index),
                        mm_le16_to_cpu(def_sb->atten_status_block.attn_bits_index));
        }
        //it is one of the non-default status block
        else
        {
                rss_sb = lm_get_status_block(pdev, rss_id);
                DbgBreakIf(!rss_sb);
                //increment the status index of all storms for this status block
                rss_sb->c_status_block.status_block_index = mm_cpu_to_le16(mm_le16_to_cpu(rss_sb->c_status_block.status_block_index) + 1);
                rss_sb->u_status_block.status_block_index = mm_cpu_to_le16(mm_le16_to_cpu(rss_sb->u_status_block.status_block_index) + 1);

                DbgMessage3(pdev, INFORMi, "dbg_change_sb_index():sb#%d indices are now: c_rss_prod_idx:%d, u_rss_prod_idx:%d\n",
                        rss_id,
                        mm_le16_to_cpu(rss_sb->c_status_block.status_block_index),
                        mm_le16_to_cpu(rss_sb->u_status_block.status_block_index));
        }
}

/* UM calls this in case there was a change in the default status block.
 * This function does the work of the DPC.
 * Parameters:
 * pdev   - this is the LM device
 * sb_idx - this is the index where the status block lies in the array under the lm_device
 */
static void dbg_def_sb_dpc(lm_device_t *pdev)
{
        u8_t is_updated               = 0;
    u32_t cnt                     = 0;
    //Attntion vars
    u32_t total_activ_to_ack      = 0;
    u32_t cnt_acks                = 0;
    u32_t activity_flg            = 0;
    u16_t lcl_attn_bits           = 0;
    u16_t lcl_attn_ack            = 0;
    u16_t asserted_proc_grps      = 0;
    u16_t deasserted_proc_grps    = 0;
    u32_t dpc_loop_cnt            = 1; //hard-coded! part of the UM device params.

        DbgBreakIf(!pdev);
        DbgMessage(pdev, INFORMi, "dbg_def_sb_dpc(): inside!\n");

        //check if the default status block has changed, thus have a new status index.
        //it is possible that even here, there is no difference in the index due to hw queues races(the DMA op is delayed)so bail out.
        if ((is_updated = lm_is_def_sb_updated(pdev)) == 0)
        {
                //Agreed with Shay that we don't need to ack the index in case it matches the local copy, just enable ints
                DbgMessage(pdev, INFORMi, "dbg_def_sb_dpc(): no change in status index so get out!\n");
                lm_int_ack_sb(pdev, DEF_STATUS_BLOCK_INDEX, TSTORM_ID, DEF_SB_INDEX_OF_TSTORM(pdev), IGU_INT_ENABLE, 0);


                return;
        }
        for(cnt = 0; cnt < dpc_loop_cnt; cnt++)
        {
        //update the local copy of indices with the newly fresh indices values just read from the default status block
                lm_update_hc_indices(pdev, DEF_STATUS_BLOCK_INDEX, &activity_flg);

        DbgBreakIf(!(activity_flg & LM_DEF_EVENT_MASK));

        total_activ_to_ack |= activity_flg;

        //attn bits handling
        if (activity_flg & LM_DEF_ATTN_ACTIVE)
        {
            lcl_attn_bits = 0;
            lcl_attn_ack  = 0;
            lm_get_attn_info(pdev, &lcl_attn_bits, &lcl_attn_ack);

            GET_ATTN_CHNG_GROUPS(pdev, lcl_attn_bits, lcl_attn_ack, &asserted_proc_grps, &deasserted_proc_grps);

            DbgMessage2(pdev, INFORMi, "dbg_def_sb_dpc(): asserted_proc_grps:0x%x, deasserted_proc_grps:0x%x\n", asserted_proc_grps, deasserted_proc_grps);

            if (asserted_proc_grps)
                lm_handle_assertion_processing(pdev, asserted_proc_grps);

            if (deasserted_proc_grps)
                lm_handle_deassertion_processing(pdev, deasserted_proc_grps);
        }

        if (activity_flg & LM_DEF_USTORM_ACTIVE)
        {
            //TODO: USTORM protocol indices processing processing
        }
        if (activity_flg & LM_DEF_CSTORM_ACTIVE)
        {
            //TODO: CSTORM protocol indices processing processing
        }
        activity_flg = 0;
        //if no change beneath our legs, get out.
        if ((is_updated = lm_is_def_sb_updated(pdev)) == 0)
        {
            break;
        }
        }
    //optimization to ack only the relevant parts to chip, and the last one must enable ints.
    cnt_acks = count_bits(total_activ_to_ack);

    DbgMessage2(pdev, INFORMi, "um_bdrv_def_dpc(): cnt_acks:%d, total_activ_to_ack:0x%x\n", cnt_acks, total_activ_to_ack);

    if (total_activ_to_ack & LM_DEF_ATTN_ACTIVE)
        lm_int_ack_sb(pdev, DEF_STATUS_BLOCK_INDEX, ATTENTION_ID, DEF_SB_INDEX_OF_ATTN(pdev), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

    if (total_activ_to_ack & LM_DEF_USTORM_ACTIVE)
        lm_int_ack_sb(pdev, DEF_STATUS_BLOCK_INDEX, USTORM_ID, DEF_SB_INDEX_OF_USTORM(pdev), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

    if (total_activ_to_ack & LM_DEF_CSTORM_ACTIVE)
        lm_int_ack_sb(pdev, DEF_STATUS_BLOCK_INDEX, CSTORM_ID, DEF_SB_INDEX_OF_CSTORM(pdev), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

    if (total_activ_to_ack & LM_DEF_XSTORM_ACTIVE)
        lm_int_ack_sb(pdev, DEF_STATUS_BLOCK_INDEX, XSTORM_ID, DEF_SB_INDEX_OF_XSTORM(pdev), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

    if (total_activ_to_ack & LM_DEF_TSTORM_ACTIVE)
                lm_int_ack_sb(pdev, DEF_STATUS_BLOCK_INDEX, TSTORM_ID, DEF_SB_INDEX_OF_TSTORM(pdev), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

                DbgMessage(pdev, INFORMi, "dbg_def_sb_dpc(): FINISH _______________________________________________\n");
}

/* UM calls this in case there was a change in the status block.
 * This function does the work of the DPC.
 * Parameters:
 * pdev   - this is the LM device
 * sb_idx - this is the index where the status block lies in the array under the lm_device
 */
static void dbg_sb_dpc(lm_device_t *pdev, u8_t rss_id)
{
        u8_t is_updated               = 0;
    u32_t activity_flg            = 0;
    u32_t total_activ_to_ack      = 0;
    u32_t cnt_acks                = 0;
    u32_t cnt                     = 0;
    u32_t dpc_loop_cnt            = 1; //hardcoded! - part of original UM device params.

        DbgBreakIf(!pdev);
        DbgBreakIf(rss_id >= MAX_RSS_CHAINS);

        DbgMessage1(pdev, INFORMi, "dbg_sb_dpc(): handling RSS status block #%d\n", rss_id);

        //check if the non-default status block has changed, thus have a new status index.
        //it is possible that even here, there is no difference in the index due to hw queues races(the DMA op is delayed)so bail out.
        if ((is_updated = lm_is_sb_updated(pdev, rss_id)) == 0)
        {
                //Agreed with Shay that we don't need to ack the index in case it matches the local copy, just enable ints
                DbgMessage(pdev, INFORMi, "handle_sb(): no change is status index so get out!\n");
                lm_int_ack_sb(pdev, rss_id, CSTORM_ID, SB_INDEX_OF_CSTORM(pdev,rss_id), IGU_INT_ENABLE, 0);

                return;
        }
        for(cnt = 0; cnt < dpc_loop_cnt; cnt++)
        {
        //update the local copy of indices with the newly fresh indices values just read from the status block
                lm_update_hc_indices(pdev, rss_id, &activity_flg);

        DbgBreakIf(!(activity_flg & LM_NON_DEF_EVENT_MASK));

        total_activ_to_ack |= activity_flg;

        if (activity_flg & LM_NON_DEF_USTORM_ACTIVE)
        {
            //Check for Rx completions
                if (lm_is_rx_completion(pdev, rss_id))
                {
                        //Call here service_rx_intr(pdev, rss_id);
                }
        }

        if (activity_flg & LM_NON_DEF_CSTORM_ACTIVE)
        {
            //Check for Tx completions
                if (lm_is_tx_completion(pdev, rss_id))
                {
                        //Call here service_tx_intr(pdev, rss_id);
                }
        }
        activity_flg = 0;
                //check whether the status block has been change meanwhile, if so, lets process again
                if ((is_updated = lm_is_sb_updated(pdev, rss_id)) == 0)
        {
            break;
        }
        }
    //optimization to ack only the relevant parts to chip, and the last one must enable ints.
    cnt_acks = count_bits(total_activ_to_ack);
    DbgMessage2(pdev, INFORMi, "dbg_sb_dpc(): cnt_acks:%d, total_activ_to_ack:0x%x\n", cnt_acks, total_activ_to_ack);

    if (total_activ_to_ack & LM_NON_DEF_USTORM_ACTIVE)
        lm_int_ack_sb(pdev, rss_id, USTORM_ID, SB_INDEX_OF_USTORM(pdev,rss_id), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

    if (total_activ_to_ack & LM_NON_DEF_CSTORM_ACTIVE)
        lm_int_ack_sb(pdev, rss_id, CSTORM_ID, SB_INDEX_OF_CSTORM(pdev,rss_id), --cnt_acks ? IGU_INT_NOP : IGU_INT_ENABLE, 1);

        //after all fast-path processing done, call this to enable posting pending requests to the SQ
        lm_sq_post_pending(pdev);
        DbgMessage(pdev, INFORMi, "handle_sb(): FINISH _______________________________________________\n");
}

static u8_t dbg_isr(lm_device_t *pdev, u32_t intr_status)
{
    u8_t intr_recognized;
        u8_t rss_id = 0;

    intr_recognized = FALSE;

        DbgBreakIf(!pdev);
        DbgMessage(pdev, INFORMi, "dbg_isr() inside!\n");

        //get the relevant status blocks for which we need to schedule the appropriate DPC
        //please note this implicitly de-asserts the interrupt line, which must not be forgotten to be enabled via the DPC
        //the LSB(bit 0) describes the default status blocks and bit 1-16 describe the RSS non-default status blocks.
        //In case RSS not supported, everything will arrive on RSS 0, that means that lm_get_interrupt_status()
        //will return on the maximum bit0 and bit1 toggled in that case.

    //intr_status = lm_get_interrupt_status(pdev);

        //this is not our interrupt so bail out!
        if (!intr_status)
        {
                return intr_recognized;
        }

    //TODO: In Windows, must assure that there is only one DPC running!
        //TODO: Get the CPU number on which this ISR is running (needed for RSS)

        //go over all the status blocks updates we received from reading the single ISR/multiple DPCs register,
        //and queue the corresponding DPCs for them.
        //Currently, RSS is not supported, but still, a scenario might occur where we need to queue both the fast-path DPC as well as
        //the slow-path DPC
        while(intr_status)
    {
        if(intr_status & 1)
        {
                        //this means that there is a change in the default sb, so queue the relevant DPC of the default sb.
                        if (rss_id == 0)
                        {
                                //This is the interface for Xdiag. In Windows, this will be the function which will get queued
                                //within the DPC object.
                                dbg_def_sb_dpc(pdev);
                        }

                        //take care of the non-default sb according to RSS.
                        else
                        {
                                //(rss_id - 1) is used since the non-default sbs are located in lm_device at indices 0-15
                                dbg_sb_dpc(pdev, rss_id - 1);
                        }
        }

                intr_status >>= 1;
        rss_id++;
    }

        intr_recognized = TRUE;

        DbgMessage1(pdev, INFORMi, "dbg_isr(): intr_recognized is:%s\n", intr_recognized ? "TRUE" : "FALSE");

    return intr_recognized;
} /* dbg_isr */


void dbg_sb_ints_test_suite(lm_device_t *pdev)
{
        u8_t index;
        volatile struct host_def_status_block *def_sb = NULL;
    def_sb = lm_get_default_status_block(pdev);

    //This part is dedicated to checking the entire status block mechanism and Interrupts API.
        //The test should change the default/non-default status block parameters and print as debug information
        //the whole status block fields.

        //print entire info of all status blocks!
        print_sb_info(pdev);

        //handle default status block (=DPC of status block) - nothing should happen yet!
        dbg_def_sb_dpc(pdev);

        //handle all rss non-default status blocks - nothing should happen yet
        for(index = 0; index < MAX_RSS_CHAINS; index++)
        {
                dbg_sb_dpc(pdev, index);
        }

        //now it's time to change the status index of "some" of the status block as if there
        //was a change regarding them
        for(index = 0; index <= MAX_RSS_CHAINS; index++)
        {
                //do update only for odd index status blocks and the default status block
                if((index % 2) || (index == MAX_RSS_CHAINS))
                {
                        dbg_change_sb_index(pdev, index);
                }
        }
    //assert groups: 0,1
    dbg_assert_attn_lines(pdev, 0x3);

    //This part is hardcoded for simulating a change on the default status block(0) and RSS sb: 1,3,5,7,9,11,13,15
    dbg_isr(pdev, 0x15555);

    //now we have for groups 0,1:
    //             attn_bits: 1 1
    //             attn_ack:  0 0
    //             mask:      0 0
    //             state:     1 1

    //simulate as if the chip wrote 1 1 to the attn_ack
    dbg_ack_assert_attn_lines(pdev, 0x3);

    //now we have for groups 0,1:
    //             attn_bits: 1 1
    //             attn_ack:  1 1
    //             mask:      0 0
    //             state:     1 1

    //simulate as if due to the mask of the AEU line, 0 has arrived at the line and written by chip to attn_bits
    dbg_deassert_attn_lines(pdev, 0x3);

    //now we have for groups 0,1:
    //             attn_bits: 0 0
    //             attn_ack:  1 1
    //             mask:      0 0
    //             state:     1 1

    //simulate an increment of the attn producer by chip due to change in attn bits/attn_ack from monitored state.
    def_sb->atten_status_block.attn_bits_index = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->atten_status_block.attn_bits_index) + 1) ;

    //Call the dbg ISR routine to simulate lines de-asserted at the default sb DPC only!
        dbg_isr(pdev, 0x1);

    //Set everything back to zero to start all over again!
    dbg_zero_all_attn(pdev);

    // **************************   Create an unacceptable state! ***************************

    //assert groups: 0,1
    dbg_assert_attn_lines(pdev, 0x3);

    //simulate as if the chip wrote 1 1 to the attn_ack
    dbg_ack_assert_attn_lines(pdev, 0x3);

    //now we have for groups 0,1:
    //             attn_bits: 1 1
    //             attn_ack:  1 1
    //             mask:      0 0
    //             state:     0 0

    def_sb->atten_status_block.attn_bits_index = mm_cpu_to_le16(mm_le16_to_cpu(def_sb->atten_status_block.attn_bits_index) + 1);

    dbg_isr(pdev, 0x1);
}