root/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/lm_niv.c
/*******************************************************************************
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright 2014 QLogic Corporation
 * The contents of this file are subject to the terms of the
 * QLogic End User License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License at
 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
 * QLogic_End_User_Software_License.txt
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 *
 * Module Description:
 *
 *
 * History:
 *    11/29/10 Alon Elhanani       Inception.
 ******************************************************************************/

#include "lm5710.h"
#include "mcp_shmem.h"
#include "mac_stats.h"

static void lm_niv_set_loopback_mode_imp(struct _lm_device_t *pdev, IN const u8_t b_enable )
{
   lm_status_t                                             lm_status     = LM_STATUS_SUCCESS;
   struct function_update_data*            data              = LM_SLOWPATH(pdev, niv_function_update_data);
   const lm_address_t                              data_phys     = LM_SLOWPATH_PHYS(pdev, niv_function_update_data);
   const niv_ramrod_state_t                        initial_state = b_enable ? NIV_RAMROD_SET_LOOPBACK_POSTED :NIV_RAMROD_CLEAR_LOOPBACK_POSTED ;

   data->vif_id_change_flg                         = FALSE;
   data->afex_default_vlan_change_flg  = TRUE;
   data->afex_default_vlan                         = mm_cpu_to_le16(NIV_DEFAULT_VLAN(pdev));
   data->allowed_priorities_change_flg = TRUE;
   data->allowed_priorities                        = NIV_ALLOWED_PRIORITIES(pdev);
   data->network_cos_mode_change_flg   = FALSE;

   data->lb_mode_en                                        = b_enable;
   data->lb_mode_en_change_flg             = 1;
   data->echo                                              = FUNC_UPDATE_RAMROD_SOURCE_NIV;

   lm_status = lm_niv_post_command(pdev,RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, data_phys.as_u64, initial_state);
}

/**lm_niv_cli_update
 * Update each client with new NIV default VLAN
 *
 * @param pdev the device to use
 *
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other
 *            failure code on failure.
 */
static lm_status_t lm_niv_clients_update(IN                lm_device_t *pdev)
{
   lm_status_t lm_status             = LM_STATUS_FAILURE;
   u16_t           silent_vlan_value = NIV_DEFAULT_VLAN(pdev);
   u16_t           silent_vlan_mask  = ETHERNET_VLAN_ID_MASK;
   u8_t            cid                       = 0;
   u8_t            client_id         = 0;

   if(FUNC_MF_CFG_AFEX_VLAN_TRUNK_TAG_NATIVE_MODE == AFEX_VLAN_MODE(pdev))
   {
           // In this mode FW should remove all VLANS
           silent_vlan_value   = 0;
           silent_vlan_mask        = 0;
   }

   /* init l2 client conn param with default mtu values */
   for (cid = 0; cid < (LM_SB_CNT(pdev) + MAX_NON_RSS_CHAINS); cid++) //pdev->params.l2_cli_con_params
   {
           /* We want only Ethernet clients. For ethernet cid == client_id, we base the following check on that */
           if((OOO_CID(pdev) != cid) && //For OOO_CID we don't want to strip the VLAN
              (FWD_CID(pdev) != cid))   //The FWD_CID is TX only In T7.4 we should enable only for RX clients.
           {
                   client_id = cid; // TODO: For ethernet client_id == cid... extra parameter added for terminology clearness incase this changes in the future.
                   lm_status = lm_update_eth_client(pdev, client_id, silent_vlan_value, silent_vlan_mask, 1, 1);

                   if((LM_STATUS_ABORTED != lm_status) &&
                      (LM_STATUS_SUCCESS != lm_status))
                   {
                           return lm_status;
                   }
           }
   }

   return LM_STATUS_SUCCESS;
}

static void lm_niv_set_loopback_mode_enable(struct _lm_device_t *pdev)
{
   lm_status_t lm_status                           = LM_STATUS_FAILURE;

   lm_hardware_mf_info_t   *mf_info        = &pdev->hw_info.mf_info;

   // loopback tests will use default vlan 0x1 must be a value diffrent from zero,
   // TODO : ask Barak that DIAG test will change the value in SHMEM.
   mf_info->default_vlan = 0x1;
   mf_info->niv_allowed_priorities = 0xff;

   lm_niv_set_loopback_mode_imp(pdev, TRUE);

   lm_status = lm_niv_clients_update(pdev);

   if (LM_STATUS_SUCCESS != lm_status)
   {
      DbgBreakMsg("lm_niv_cli_update failed ");
   }
}

static void lm_niv_set_loopback_mode_disable(struct _lm_device_t *pdev)
{
   lm_hardware_mf_info_t   *mf_info         = &pdev->hw_info.mf_info;

   // loopback tests revert values (has no real effect except debugging)
   mf_info->default_vlan = 0;
   mf_info->niv_allowed_priorities = 0;

   lm_niv_set_loopback_mode_imp(pdev, FALSE);
}

lm_status_t lm_niv_set_loopback_mode(struct _lm_device_t *pdev, IN const u8_t b_enable)
{
   lm_status_t lm_status = LM_STATUS_SUCCESS;

   if (b_enable)
   {
#ifdef EDIAG
           lm_niv_set_loopback_mode_enable(pdev);
#else
           lm_status = MM_REGISTER_LPME(pdev, lm_niv_set_loopback_mode_enable, TRUE, FALSE);
#endif
   }
   else
   {
#ifdef EDIAG
           lm_niv_set_loopback_mode_disable(pdev);
#else
           lm_status = MM_REGISTER_LPME(pdev, lm_niv_set_loopback_mode_disable, TRUE, FALSE);
#endif
   }

   return lm_status;
}

/**lm_niv_vif_enable
 * enable current function or change its parameters. This
 * function must be run in PASSIVE IRQL.
 *
 * @param pdev the device to use
 *
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other
 *            failure code on failure.
 */
static lm_status_t lm_niv_vif_enable(lm_device_t *pdev)
{
   lm_status_t lm_status                   = LM_STATUS_FAILURE;
   u16_t           vif_id                          = 0;
   u16_t           default_vlan            = 0;
   u8_t            allowed_priorities  = 0;
   const u32_t VLAN_PRIORITY_SHIFT = 13;

   ///Refresh MF CFG values
   lm_status = lm_get_shmem_mf_cfg_info_niv(pdev);

   if (LM_STATUS_SUCCESS != lm_status)
   {
           return lm_status;
   }

   //Reconfigure rate-limit
   MM_ACQUIRE_PHY_LOCK(pdev);
   lm_reload_link_and_cmng(pdev);
   MM_RELEASE_PHY_LOCK(pdev);

   ///Send function-update ramrod and wait for completion
   vif_id                     = VIF_ID(pdev);
   default_vlan       = NIV_DEFAULT_VLAN(pdev) | (NIV_DEFAULT_COS(pdev) << VLAN_PRIORITY_SHIFT);
   allowed_priorities = NIV_ALLOWED_PRIORITIES(pdev);


   lm_status = lm_niv_vif_update(pdev,vif_id, default_vlan, allowed_priorities);
   if (LM_STATUS_SUCCESS != lm_status)
   {
           return lm_status;
   }

   /* init l2 client conn param with default mtu values */
   lm_status = lm_niv_clients_update(pdev);
   if (LM_STATUS_SUCCESS != lm_status)
   {
           DbgBreakMsg("lm_niv_cli_update failed ");
           return lm_status;
   }

   ///notify "link-up" to miniport
   MM_ACQUIRE_PHY_LOCK(pdev);
   // cq64469 - verify that the link is up before reporting it as active to the miniport
   if (pdev->vars.link.link_up)
   {
           pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
   }
   mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
   MM_RELEASE_PHY_LOCK(pdev);

   return lm_status;
}

/** lm_niv_vif_disable
 * disable current function. This function must be run in
 * PASSIVE IRQL.
 *
 * @param pdev the device to use
 *
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other
 *            failure code on failure.
 */
static lm_status_t lm_niv_vif_disable(lm_device_t *pdev)
{
   lm_status_t lm_status = LM_STATUS_FAILURE;

   ///indicate "link-down"
   MM_ACQUIRE_PHY_LOCK(pdev);

   pdev->vars.link_status = LM_STATUS_LINK_DOWN;
   mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);

   MM_RELEASE_PHY_LOCK(pdev);

   ///Send function-update ramrod with vif_id=0xFFFF and wait for completion
   lm_status = lm_niv_vif_update(pdev,INVALID_VIF_ID, 0, 0);
   if (LM_STATUS_SUCCESS != lm_status)
   {
           return lm_status;
   }

   return lm_status;
}

/**lm_niv_vif_delete
 * Delete current function. . This function must be run in
 * PASSIVE IRQL.
 *
 * @param pdev the device to use
 *
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other
 *            failure code on failure.
 */
static lm_status_t lm_niv_vif_delete(lm_device_t *pdev)
{
   lm_status_t lm_status = LM_STATUS_FAILURE;

   ///Send a vif-list ramrod with VIF_LIST_RULE_CLEAR_FUNC opcode and wait for completion
   lm_status = lm_niv_vif_list_update(pdev, VIF_LIST_RULE_CLEAR_FUNC, 0/*list_index*/, 0/*func_bit_map*/ ,ABS_FUNC_ID(pdev)/*func_to_clear*/);
   if (LM_STATUS_SUCCESS != lm_status)
   {
           DbgBreakMsg("Failed to clear VIF lists on VIF delete.\n");
           return lm_status;
   }

   lm_status = lm_niv_vif_disable(pdev);
   if (LM_STATUS_SUCCESS != lm_status)
   {
           DbgBreakMsg("Failed to disable VIF on VIF delete.\n");
           return lm_status;
   }

   return lm_status;
}

#define NIV_STATS_ASSIGN_HI_LO(_field, _val) _field##_hi = U64_HI((_val));\
                                                                                    _field##_lo = U64_LO((_val));
/**lm_chip_stats_to_niv_stats
 * Copy relevant fields from driver statistics to the format
 * written to the SHMEM for NIV stats.
 *
 * @param pdev the device to take the stats from
 * @param p_afex_stats the SHMEM structure
 */
static void lm_niv_chip_stats_to_niv_stats(lm_device_t* pdev, OUT struct afex_stats* p_afex_stats)
{
    b10_l2_chip_statistics_t stats           = {0};
    lm_stats_fw_t            *fw_stats       = &pdev->vars.stats.stats_mirror.stats_fw;
    fcoe_stats_info_t        *fcoe_stats_mfw = &pdev->vars.stats.stats_mirror.stats_drv.drv_info_to_mfw.fcoe_stats;
    u64_t                    sum_64          = 0;

   lm_stats_get_l2_chip_stats(pdev, &stats, L2_CHIP_STATISTICS_VER_NUM_1);

    sum_64 = stats.IfHCOutUcastPkts + fw_stats->fcoe.fcoe_tx_pkt_cnt + (HILO_U64(fcoe_stats_mfw->tx_frames_hi, fcoe_stats_mfw->tx_frames_lo ));
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_unicast_frames, sum_64 );

    sum_64 = stats.IfHCOutUcastOctets + fw_stats->fcoe.fcoe_tx_byte_cnt + (HILO_U64(fcoe_stats_mfw->tx_bytes_hi, fcoe_stats_mfw->tx_bytes_lo ));
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_unicast_bytes,  sum_64 );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_multicast_frames,  stats.IfHCOutMulticastPkts );
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_multicast_bytes,   stats.IfHCOutMulticastOctets );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_broadcast_frames,  stats.IfHCOutBroadcastPkts );
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_broadcast_bytes,   stats.IfHCOutBroadcastOctets );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_frames_discarded, 0 );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_frames_dropped,    fw_stats->eth_xstorm_common.client_statistics[LM_CLI_IDX_NDIS].error_drop_pkts);

    sum_64 = stats.IfHCInUcastPkts + fw_stats->fcoe.fcoe_rx_pkt_cnt + (HILO_U64( fcoe_stats_mfw->rx_frames_hi, fcoe_stats_mfw->rx_frames_lo ));
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_unicast_frames, sum_64 );

    sum_64 = stats.IfHCInUcastOctets + fw_stats->fcoe.fcoe_rx_byte_cnt + (HILO_U64( fcoe_stats_mfw->rx_bytes_hi, fcoe_stats_mfw->rx_bytes_lo ));
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_unicast_bytes,  sum_64 );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_multicast_frames,  stats.IfHCInMulticastPkts );
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_multicast_bytes,   stats.IfHCInMulticastOctets );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_broadcast_frames,  stats.IfHCInBroadcastPkts );
    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_broadcast_bytes,   stats.IfHCInBroadcastOctets );

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_frames_discarded,  stats.IfInTTL0Discards +
                                                                                                                   stats.EtherStatsOverrsizePkts +
                                                                                                                   fw_stats->eth_tstorm_common.client_statistics[LM_CLI_IDX_NDIS].checksum_discard);

    NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_frames_dropped,    stats.IfInMBUFDiscards+
                                                                                                                   fw_stats->fcoe.fcoe_rx_drop_pkt_cnt_tstorm +
                                                                                                                   fw_stats->fcoe.fcoe_rx_drop_pkt_cnt_ustorm );
}

/**lm_niv_stats_get
 * Update NIV statistics in SHMEM. This function runs in PASSIVE
 * IRQL as an LPME.
 *
 * @param pdev the device to use
 */
static void lm_niv_stats_get(lm_device_t *pdev)
{
   u32_t            mcp_resp        = 0;
   u32_t            output_offset   = 0;
   u32_t            *field_ptr      = NULL;
   int              bytes_written   = 0;
   const u32_t      func_mailbox_id = FUNC_MAILBOX_ID(pdev);
   const u32_t      offset          = OFFSETOF(shmem2_region_t, afex_scratchpad_addr_to_write[func_mailbox_id]);
   struct afex_stats afex_stats_var = {0};

    // verify that change in struct afex_stats won't corrupt our small stack
    ASSERT_STATIC( sizeof(afex_stats_var) >= 100 );

    lm_niv_chip_stats_to_niv_stats(pdev, &afex_stats_var);

   ///Read from SHMEM2 the address where the response should be placed
   LM_SHMEM2_READ(pdev, offset, &output_offset);

   ///Write the response to the scratchpad field by field.
    field_ptr = (u32_t*)&afex_stats_var;
    for (bytes_written = 0; bytes_written  < sizeof(afex_stats_var); bytes_written += sizeof(u32_t))
   {
           REG_WR(pdev, output_offset + bytes_written, *field_ptr);
           ++field_ptr;
   }
   ///ACK the MCP message
   lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_STATSGET_ACK, 0, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
   DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_STATSGET_ACK);
}

/**lm_niv_vif_list_set
 * Modify local information about VIF lists. This function runs
 * in PASSIVE IRQL as an LPME. (PMF only)
 *
 * @param pdev the device to use
 */
static void lm_niv_vif_list_set(lm_device_t *pdev)
{
   lm_status_t lm_status           = LM_STATUS_FAILURE;
   u32_t           list_idx                = 0;
   u32_t           list_bitmap     = 0;
   u32_t           mcp_resp                = 0;
   const u32_t func_mailbox_id = FUNC_MAILBOX_ID(pdev);
   u32_t           offset                  = 0;

   ///Read VIF list id+bitfield from SHMEM2
   offset                  = OFFSETOF(struct shmem2_region, afex_param1_to_driver[func_mailbox_id]);
   LM_SHMEM2_READ(pdev, offset, &list_idx);
   DbgBreakIf(list_idx > 0xFFFF);

   offset                  = OFFSETOF(struct shmem2_region, afex_param2_to_driver[func_mailbox_id]);
   LM_SHMEM2_READ(pdev, offset, &list_bitmap);
   DbgBreakIf(list_bitmap > 0xFF);

   ///Send a vif-list ramrod with VIF_LIST_RULE_SET opcode and wait for completion
   lm_status = lm_niv_vif_list_update(pdev, VIF_LIST_RULE_SET,(u16_t)list_idx, (u8_t)list_bitmap,0);
   DbgBreakIf(lm_status != LM_STATUS_SUCCESS);

   ///ACK the MCP message
   lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_LISTSET_ACK, 0, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
   DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_LISTSET_ACK);
}

/**lm_niv_vif_list_get
 * Update NIV statistics in SHMEM. This function runs in PASSIVE
 * IRQL as an LPME.
 *
 * @param pdev the device to use
 *
 */
static void lm_niv_vif_list_get(lm_device_t *pdev)
{
   lm_status_t lm_status           = LM_STATUS_FAILURE;
   u32_t           list_idx                = 0;
   u32_t           mcp_resp                = 0;
   const u32_t func_mailbox_id = FUNC_MAILBOX_ID(pdev);
   const u32_t offset              = OFFSETOF(struct shmem2_region, afex_param1_to_driver[func_mailbox_id]);

   ///Read list ID from SHMEM2
   LM_SHMEM2_READ(pdev, offset, &list_idx);
   DbgBreakIf(list_idx > 0xFFFF);

   ///Send a vif-list ramrod with VIF_LIST_RULE_GET opcode and wait for completion
   lm_status = lm_niv_vif_list_update(pdev, VIF_LIST_RULE_GET, (u16_t)list_idx, 0, 0);
   DbgBreakIf (LM_STATUS_SUCCESS != lm_status);

   ///Write response to SHMEM and ACK the MCP message
   lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_LISTGET_ACK, pdev->slowpath_info.last_vif_list_bitmap, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
   DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_LISTGET_ACK);
}

/**lm_niv_vif_set
 * Handle a VIF-SET command. This function runs in PASSIVE IRQL
 * as an LPME.
 *
 * @param pdev the device to use
 */
static void lm_niv_vif_set(lm_device_t *pdev)
{
   //lm_status_t lm_status           = LM_STATUS_FAILURE;
   u32_t           func_mf_config  = 0;
   u32_t           mcp_resp                = 0;
   u32_t           val                     = 0;
   const u32_t abs_func_id         = ABS_FUNC_ID(pdev);
   const u32_t offset              = OFFSETOF(mf_cfg_t, func_mf_config[abs_func_id].config);

   ///read FUNC-DISABLED and FUNC-DELETED from func_mf_cfg
   LM_MFCFG_READ(pdev, offset, &func_mf_config);

   pdev->hw_info.mf_info.func_mf_cfg = func_mf_config ;

   ///if it's enable, call lm_niv_vif_enable
   ///if it's disable, call lm_niv_vif_disable
   ///if it's delete, call lm_niv_vif_delete
   val = GET_FLAGS(func_mf_config, FUNC_MF_CFG_FUNC_DISABLED|FUNC_MF_CFG_FUNC_DELETED);
   switch(val)
   {
   case FUNC_MF_CFG_FUNC_DISABLED:
           {
                   lm_niv_vif_disable(pdev);
           }
           break;

   case FUNC_MF_CFG_FUNC_DELETED|FUNC_MF_CFG_FUNC_DISABLED:
           {
                   lm_niv_vif_delete(pdev);
           }
           break;

   case 0: //neither=enabled
           {
                   lm_niv_vif_enable(pdev);
           }
           break;

   default:
           {
                   DbgBreakIf(1);//invalid value - FUNC_DELETED without FUNC_DISABLED
           }
           break;
   }

   ///ACK the MCP message
   lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_VIFSET_ACK, 0, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
   DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_VIFSET_ACK);
}

typedef struct _lm_niv_event_function_t
{
   u32_t niv_event_flag;
   void (*function)(lm_device_t*);
} lm_niv_event_function_t;

/**lm_niv_event
 * handle a NIV-related MCP general attention by scheduling the
 * appropriate work item.
 *
 * @param pdev the device to use
 * @param niv_event the DRIVER_STATUS flags that the MCP sent.
 *                                 It's assumed that only NIV-related flags are
 *                                 set.
 *
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other
 *            failure code on failure.
 */
lm_status_t lm_niv_event(lm_device_t *pdev, const u32_t niv_event)
{
   lm_status_t                                              lm_status                      = LM_STATUS_FAILURE;
   u32_t                                                            event_idx                      = 0;
   u32_t                                                            handled_events                 = 0;
   u32_t                                                            cur_event                      = 0;
   static const lm_niv_event_function_t event_functions_arr[]  = { {DRV_STATUS_AFEX_VIFSET_REQ,   lm_niv_vif_set},
                                                                                                                                   {DRV_STATUS_AFEX_LISTGET_REQ,  lm_niv_vif_list_get},
                                                                                                                                   {DRV_STATUS_AFEX_LISTSET_REQ,  lm_niv_vif_list_set},
                                                                                                                                   {DRV_STATUS_AFEX_STATSGET_REQ, lm_niv_stats_get},
                                                                                                                             };

   //for every possible flag: if it's set, schedule a WI with the associated function and set the same flag in handled_events
   for (event_idx = 0; event_idx < ARRSIZE(event_functions_arr); ++event_idx)
   {
           cur_event = event_functions_arr[event_idx].niv_event_flag;

           if (GET_FLAGS(niv_event, cur_event))
           {
                   lm_status = MM_REGISTER_LPME(pdev, event_functions_arr[event_idx].function, TRUE, TRUE);
                   if (lm_status != LM_STATUS_SUCCESS)
                   {
                           DbgBreakIf(lm_status != LM_STATUS_SUCCESS);
                           return lm_status;
                   }
                   SET_FLAGS(handled_events, cur_event);
           }
   }

   //make sure there we no unknown events set.
   if (handled_events != niv_event)
   {
           DbgBreakIf(handled_events != niv_event);
           return LM_STATUS_INVALID_PARAMETER;
   }

   return lm_status;
}