xref: /titanic_51/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/lm_niv.c (revision d14abf155341d55053c76eeec58b787a456b753b)
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  *
35  *
36  * History:
37  *    11/29/10 Alon Elhanani       Inception.
38  ******************************************************************************/
39 
40 #include "lm5710.h"
41 #include "mcp_shmem.h"
42 #include "mac_stats.h"
43 
44 static void lm_niv_set_loopback_mode_imp(struct _lm_device_t *pdev, IN const u8_t b_enable )
45 {
46    lm_status_t                                             lm_status     = LM_STATUS_SUCCESS;
47    struct function_update_data*            data              = LM_SLOWPATH(pdev, niv_function_update_data);
48    const lm_address_t                              data_phys     = LM_SLOWPATH_PHYS(pdev, niv_function_update_data);
49    const niv_ramrod_state_t                        initial_state = b_enable ? NIV_RAMROD_SET_LOOPBACK_POSTED :NIV_RAMROD_CLEAR_LOOPBACK_POSTED ;
50 
51    data->vif_id_change_flg                         = FALSE;
52    data->afex_default_vlan_change_flg  = TRUE;
53    data->afex_default_vlan                         = mm_cpu_to_le16(NIV_DEFAULT_VLAN(pdev));
54    data->allowed_priorities_change_flg = TRUE;
55    data->allowed_priorities                        = NIV_ALLOWED_PRIORITIES(pdev);
56    data->network_cos_mode_change_flg   = FALSE;
57 
58    data->lb_mode_en                                        = b_enable;
59    data->lb_mode_en_change_flg             = 1;
60    data->echo                                              = FUNC_UPDATE_RAMROD_SOURCE_NIV;
61 
62    lm_status = lm_niv_post_command(pdev,RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, data_phys.as_u64, initial_state);
63 }
64 
65 /**lm_niv_cli_update
66  * Update each client with new NIV default VLAN
67  *
68  * @param pdev the device to use
69  *
70  * @return lm_status_t LM_STATUS_SUCCESS on success, some other
71  *            failure code on failure.
72  */
73 static lm_status_t lm_niv_clients_update(IN                lm_device_t *pdev)
74 {
75    lm_status_t lm_status             = LM_STATUS_FAILURE;
76    u16_t           silent_vlan_value = NIV_DEFAULT_VLAN(pdev);
77    u16_t           silent_vlan_mask  = ETHERNET_VLAN_ID_MASK;
78    u8_t            cid                       = 0;
79    u8_t            client_id         = 0;
80 
81    if(FUNC_MF_CFG_AFEX_VLAN_TRUNK_TAG_NATIVE_MODE == AFEX_VLAN_MODE(pdev))
82    {
83            // In this mode FW should remove all VLANS
84            silent_vlan_value   = 0;
85            silent_vlan_mask        = 0;
86    }
87 
88    /* init l2 client conn param with default mtu values */
89    for (cid = 0; cid < (LM_SB_CNT(pdev) + MAX_NON_RSS_CHAINS); cid++) //pdev->params.l2_cli_con_params
90    {
91            /* We want only Ethernet clients. For ethernet cid == client_id, we base the following check on that */
92            if((OOO_CID(pdev) != cid) && //For OOO_CID we don't want to strip the VLAN
93               (FWD_CID(pdev) != cid))   //The FWD_CID is TX only In T7.4 we should enable only for RX clients.
94            {
95                    client_id = cid; // TODO: For ethernet client_id == cid... extra parameter added for terminology clearness incase this changes in the future.
96                    lm_status = lm_update_eth_client(pdev, client_id, silent_vlan_value, silent_vlan_mask, 1, 1);
97 
98                    if((LM_STATUS_ABORTED != lm_status) &&
99                       (LM_STATUS_SUCCESS != lm_status))
100                    {
101                            return lm_status;
102                    }
103            }
104    }
105 
106    return LM_STATUS_SUCCESS;
107 }
108 
109 static void lm_niv_set_loopback_mode_enable(struct _lm_device_t *pdev)
110 {
111    lm_status_t lm_status                           = LM_STATUS_FAILURE;
112 
113    lm_hardware_mf_info_t   *mf_info        = &pdev->hw_info.mf_info;
114 
115    // loopback tests will use default vlan 0x1 must be a value diffrent from zero,
116    // TODO : ask Barak that DIAG test will change the value in SHMEM.
117    mf_info->default_vlan = 0x1;
118    mf_info->niv_allowed_priorities = 0xff;
119 
120    lm_niv_set_loopback_mode_imp(pdev, TRUE);
121 
122    lm_status = lm_niv_clients_update(pdev);
123 
124    if (LM_STATUS_SUCCESS != lm_status)
125    {
126       DbgBreakMsg("lm_niv_cli_update failed ");
127    }
128 }
129 
130 static void lm_niv_set_loopback_mode_disable(struct _lm_device_t *pdev)
131 {
132    lm_hardware_mf_info_t   *mf_info         = &pdev->hw_info.mf_info;
133 
134    // loopback tests revert values (has no real effect except debugging)
135    mf_info->default_vlan = 0;
136    mf_info->niv_allowed_priorities = 0;
137 
138    lm_niv_set_loopback_mode_imp(pdev, FALSE);
139 }
140 
141 lm_status_t lm_niv_set_loopback_mode(struct _lm_device_t *pdev, IN const u8_t b_enable)
142 {
143    lm_status_t lm_status = LM_STATUS_SUCCESS;
144 
145    if (b_enable)
146    {
147 #ifdef EDIAG
148            lm_niv_set_loopback_mode_enable(pdev);
149 #else
150            lm_status = MM_REGISTER_LPME(pdev, lm_niv_set_loopback_mode_enable, TRUE, FALSE);
151 #endif
152    }
153    else
154    {
155 #ifdef EDIAG
156            lm_niv_set_loopback_mode_disable(pdev);
157 #else
158            lm_status = MM_REGISTER_LPME(pdev, lm_niv_set_loopback_mode_disable, TRUE, FALSE);
159 #endif
160    }
161 
162    return lm_status;
163 }
164 
165 /**lm_niv_vif_enable
166  * enable current function or change its parameters. This
167  * function must be run in PASSIVE IRQL.
168  *
169  * @param pdev the device to use
170  *
171  * @return lm_status_t LM_STATUS_SUCCESS on success, some other
172  *            failure code on failure.
173  */
174 static lm_status_t lm_niv_vif_enable(lm_device_t *pdev)
175 {
176    lm_status_t lm_status                   = LM_STATUS_FAILURE;
177    u16_t           vif_id                          = 0;
178    u16_t           default_vlan            = 0;
179    u8_t            allowed_priorities  = 0;
180    const u32_t VLAN_PRIORITY_SHIFT = 13;
181 
182    ///Refresh MF CFG values
183    lm_status = lm_get_shmem_mf_cfg_info_niv(pdev);
184 
185    if (LM_STATUS_SUCCESS != lm_status)
186    {
187            return lm_status;
188    }
189 
190    //Reconfigure rate-limit
191    MM_ACQUIRE_PHY_LOCK(pdev);
192    lm_reload_link_and_cmng(pdev);
193    MM_RELEASE_PHY_LOCK(pdev);
194 
195    ///Send function-update ramrod and wait for completion
196    vif_id                     = VIF_ID(pdev);
197    default_vlan       = NIV_DEFAULT_VLAN(pdev) | (NIV_DEFAULT_COS(pdev) << VLAN_PRIORITY_SHIFT);
198    allowed_priorities = NIV_ALLOWED_PRIORITIES(pdev);
199 
200 
201    lm_status = lm_niv_vif_update(pdev,vif_id, default_vlan, allowed_priorities);
202    if (LM_STATUS_SUCCESS != lm_status)
203    {
204            return lm_status;
205    }
206 
207    /* init l2 client conn param with default mtu values */
208    lm_status = lm_niv_clients_update(pdev);
209    if (LM_STATUS_SUCCESS != lm_status)
210    {
211            DbgBreakMsg("lm_niv_cli_update failed ");
212            return lm_status;
213    }
214 
215    ///notify "link-up" to miniport
216    MM_ACQUIRE_PHY_LOCK(pdev);
217    // cq64469 - verify that the link is up before reporting it as active to the miniport
218    if (pdev->vars.link.link_up)
219    {
220            pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
221    }
222    mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
223    MM_RELEASE_PHY_LOCK(pdev);
224 
225    return lm_status;
226 }
227 
228 /** lm_niv_vif_disable
229  * disable current function. This function must be run in
230  * PASSIVE IRQL.
231  *
232  * @param pdev the device to use
233  *
234  * @return lm_status_t LM_STATUS_SUCCESS on success, some other
235  *            failure code on failure.
236  */
237 static lm_status_t lm_niv_vif_disable(lm_device_t *pdev)
238 {
239    lm_status_t lm_status = LM_STATUS_FAILURE;
240 
241    ///indicate "link-down"
242    MM_ACQUIRE_PHY_LOCK(pdev);
243 
244    pdev->vars.link_status = LM_STATUS_LINK_DOWN;
245    mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
246 
247    MM_RELEASE_PHY_LOCK(pdev);
248 
249    ///Send function-update ramrod with vif_id=0xFFFF and wait for completion
250    lm_status = lm_niv_vif_update(pdev,INVALID_VIF_ID, 0, 0);
251    if (LM_STATUS_SUCCESS != lm_status)
252    {
253            return lm_status;
254    }
255 
256    return lm_status;
257 }
258 
259 /**lm_niv_vif_delete
260  * Delete current function. . This function must be run in
261  * PASSIVE IRQL.
262  *
263  * @param pdev the device to use
264  *
265  * @return lm_status_t LM_STATUS_SUCCESS on success, some other
266  *            failure code on failure.
267  */
268 static lm_status_t lm_niv_vif_delete(lm_device_t *pdev)
269 {
270    lm_status_t lm_status = LM_STATUS_FAILURE;
271 
272    ///Send a vif-list ramrod with VIF_LIST_RULE_CLEAR_FUNC opcode and wait for completion
273    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*/);
274    if (LM_STATUS_SUCCESS != lm_status)
275    {
276            DbgBreakMsg("Failed to clear VIF lists on VIF delete.\n");
277            return lm_status;
278    }
279 
280    lm_status = lm_niv_vif_disable(pdev);
281    if (LM_STATUS_SUCCESS != lm_status)
282    {
283            DbgBreakMsg("Failed to disable VIF on VIF delete.\n");
284            return lm_status;
285    }
286 
287    return lm_status;
288 }
289 
290 #define NIV_STATS_ASSIGN_HI_LO(_field, _val) _field##_hi = U64_HI((_val));\
291                                                                                     _field##_lo = U64_LO((_val));
292 /**lm_chip_stats_to_niv_stats
293  * Copy relevant fields from driver statistics to the format
294  * written to the SHMEM for NIV stats.
295  *
296  * @param pdev the device to take the stats from
297  * @param p_afex_stats the SHMEM structure
298  */
299 static void lm_niv_chip_stats_to_niv_stats(lm_device_t* pdev, OUT struct afex_stats* p_afex_stats)
300 {
301     b10_l2_chip_statistics_t stats           = {0};
302     lm_stats_fw_t            *fw_stats       = &pdev->vars.stats.stats_mirror.stats_fw;
303     fcoe_stats_info_t        *fcoe_stats_mfw = &pdev->vars.stats.stats_mirror.stats_drv.drv_info_to_mfw.fcoe_stats;
304     u64_t                    sum_64          = 0;
305 
306    lm_stats_get_l2_chip_stats(pdev, &stats, L2_CHIP_STATISTICS_VER_NUM_1);
307 
308     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 ));
309     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_unicast_frames, sum_64 );
310 
311     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 ));
312     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_unicast_bytes,  sum_64 );
313 
314     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_multicast_frames,  stats.IfHCOutMulticastPkts );
315     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_multicast_bytes,   stats.IfHCOutMulticastOctets );
316 
317     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_broadcast_frames,  stats.IfHCOutBroadcastPkts );
318     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_broadcast_bytes,   stats.IfHCOutBroadcastOctets );
319 
320     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->tx_frames_discarded, 0 );
321 
322     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);
323 
324     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 ));
325     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_unicast_frames, sum_64 );
326 
327     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 ));
328     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_unicast_bytes,  sum_64 );
329 
330     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_multicast_frames,  stats.IfHCInMulticastPkts );
331     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_multicast_bytes,   stats.IfHCInMulticastOctets );
332 
333     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_broadcast_frames,  stats.IfHCInBroadcastPkts );
334     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_broadcast_bytes,   stats.IfHCInBroadcastOctets );
335 
336     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_frames_discarded,  stats.IfInTTL0Discards +
337                                                                                                                    stats.EtherStatsOverrsizePkts +
338                                                                                                                    fw_stats->eth_tstorm_common.client_statistics[LM_CLI_IDX_NDIS].checksum_discard);
339 
340     NIV_STATS_ASSIGN_HI_LO(p_afex_stats->rx_frames_dropped,    stats.IfInMBUFDiscards+
341                                                                                                                    fw_stats->fcoe.fcoe_rx_drop_pkt_cnt_tstorm +
342                                                                                                                    fw_stats->fcoe.fcoe_rx_drop_pkt_cnt_ustorm );
343 }
344 
345 /**lm_niv_stats_get
346  * Update NIV statistics in SHMEM. This function runs in PASSIVE
347  * IRQL as an LPME.
348  *
349  * @param pdev the device to use
350  */
351 static void lm_niv_stats_get(lm_device_t *pdev)
352 {
353    u32_t            mcp_resp        = 0;
354    u32_t            output_offset   = 0;
355    u32_t            *field_ptr      = NULL;
356    int              bytes_written   = 0;
357    const u32_t      func_mailbox_id = FUNC_MAILBOX_ID(pdev);
358    const u32_t      offset          = OFFSETOF(shmem2_region_t, afex_scratchpad_addr_to_write[func_mailbox_id]);
359    struct afex_stats afex_stats_var = {0};
360 
361     // verify that change in struct afex_stats won't corrupt our small stack
362     ASSERT_STATIC( sizeof(afex_stats_var) >= 100 );
363 
364     lm_niv_chip_stats_to_niv_stats(pdev, &afex_stats_var);
365 
366    ///Read from SHMEM2 the address where the response should be placed
367    LM_SHMEM2_READ(pdev, offset, &output_offset);
368 
369    ///Write the response to the scratchpad field by field.
370     field_ptr = (u32_t*)&afex_stats_var;
371     for (bytes_written = 0; bytes_written  < sizeof(afex_stats_var); bytes_written += sizeof(u32_t))
372    {
373            REG_WR(pdev, output_offset + bytes_written, *field_ptr);
374            ++field_ptr;
375    }
376    ///ACK the MCP message
377    lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_STATSGET_ACK, 0, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
378    DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_STATSGET_ACK);
379 }
380 
381 /**lm_niv_vif_list_set
382  * Modify local information about VIF lists. This function runs
383  * in PASSIVE IRQL as an LPME. (PMF only)
384  *
385  * @param pdev the device to use
386  */
387 static void lm_niv_vif_list_set(lm_device_t *pdev)
388 {
389    lm_status_t lm_status           = LM_STATUS_FAILURE;
390    u32_t           list_idx                = 0;
391    u32_t           list_bitmap     = 0;
392    u32_t           mcp_resp                = 0;
393    const u32_t func_mailbox_id = FUNC_MAILBOX_ID(pdev);
394    u32_t           offset                  = 0;
395 
396    ///Read VIF list id+bitfield from SHMEM2
397    offset                  = OFFSETOF(struct shmem2_region, afex_param1_to_driver[func_mailbox_id]);
398    LM_SHMEM2_READ(pdev, offset, &list_idx);
399    DbgBreakIf(list_idx > 0xFFFF);
400 
401    offset                  = OFFSETOF(struct shmem2_region, afex_param2_to_driver[func_mailbox_id]);
402    LM_SHMEM2_READ(pdev, offset, &list_bitmap);
403    DbgBreakIf(list_bitmap > 0xFF);
404 
405    ///Send a vif-list ramrod with VIF_LIST_RULE_SET opcode and wait for completion
406    lm_status = lm_niv_vif_list_update(pdev, VIF_LIST_RULE_SET,(u16_t)list_idx, (u8_t)list_bitmap,0);
407    DbgBreakIf(lm_status != LM_STATUS_SUCCESS);
408 
409    ///ACK the MCP message
410    lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_LISTSET_ACK, 0, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
411    DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_LISTSET_ACK);
412 }
413 
414 /**lm_niv_vif_list_get
415  * Update NIV statistics in SHMEM. This function runs in PASSIVE
416  * IRQL as an LPME.
417  *
418  * @param pdev the device to use
419  *
420  */
421 static void lm_niv_vif_list_get(lm_device_t *pdev)
422 {
423    lm_status_t lm_status           = LM_STATUS_FAILURE;
424    u32_t           list_idx                = 0;
425    u32_t           mcp_resp                = 0;
426    const u32_t func_mailbox_id = FUNC_MAILBOX_ID(pdev);
427    const u32_t offset              = OFFSETOF(struct shmem2_region, afex_param1_to_driver[func_mailbox_id]);
428 
429    ///Read list ID from SHMEM2
430    LM_SHMEM2_READ(pdev, offset, &list_idx);
431    DbgBreakIf(list_idx > 0xFFFF);
432 
433    ///Send a vif-list ramrod with VIF_LIST_RULE_GET opcode and wait for completion
434    lm_status = lm_niv_vif_list_update(pdev, VIF_LIST_RULE_GET, (u16_t)list_idx, 0, 0);
435    DbgBreakIf (LM_STATUS_SUCCESS != lm_status);
436 
437    ///Write response to SHMEM and ACK the MCP message
438    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);
439    DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_LISTGET_ACK);
440 }
441 
442 /**lm_niv_vif_set
443  * Handle a VIF-SET command. This function runs in PASSIVE IRQL
444  * as an LPME.
445  *
446  * @param pdev the device to use
447  */
448 static void lm_niv_vif_set(lm_device_t *pdev)
449 {
450    //lm_status_t lm_status           = LM_STATUS_FAILURE;
451    u32_t           func_mf_config  = 0;
452    u32_t           mcp_resp                = 0;
453    u32_t           val                     = 0;
454    const u32_t abs_func_id         = ABS_FUNC_ID(pdev);
455    const u32_t offset              = OFFSETOF(mf_cfg_t, func_mf_config[abs_func_id].config);
456 
457    ///read FUNC-DISABLED and FUNC-DELETED from func_mf_cfg
458    LM_MFCFG_READ(pdev, offset, &func_mf_config);
459 
460    pdev->hw_info.mf_info.func_mf_cfg = func_mf_config ;
461 
462    ///if it's enable, call lm_niv_vif_enable
463    ///if it's disable, call lm_niv_vif_disable
464    ///if it's delete, call lm_niv_vif_delete
465    val = GET_FLAGS(func_mf_config, FUNC_MF_CFG_FUNC_DISABLED|FUNC_MF_CFG_FUNC_DELETED);
466    switch(val)
467    {
468    case FUNC_MF_CFG_FUNC_DISABLED:
469            {
470                    lm_niv_vif_disable(pdev);
471            }
472            break;
473 
474    case FUNC_MF_CFG_FUNC_DELETED|FUNC_MF_CFG_FUNC_DISABLED:
475            {
476                    lm_niv_vif_delete(pdev);
477            }
478            break;
479 
480    case 0: //neither=enabled
481            {
482                    lm_niv_vif_enable(pdev);
483            }
484            break;
485 
486    default:
487            {
488                    DbgBreakIf(1);//invalid value - FUNC_DELETED without FUNC_DISABLED
489            }
490            break;
491    }
492 
493    ///ACK the MCP message
494    lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_AFEX_VIFSET_ACK, 0, MCP_CMD_DEFAULT_TIMEOUT, &mcp_resp);
495    DbgBreakIf(mcp_resp != FW_MSG_CODE_AFEX_VIFSET_ACK);
496 }
497 
498 typedef struct _lm_niv_event_function_t
499 {
500    u32_t niv_event_flag;
501    void (*function)(lm_device_t*);
502 } lm_niv_event_function_t;
503 
504 /**lm_niv_event
505  * handle a NIV-related MCP general attention by scheduling the
506  * appropriate work item.
507  *
508  * @param pdev the device to use
509  * @param niv_event the DRIVER_STATUS flags that the MCP sent.
510  *                                 It's assumed that only NIV-related flags are
511  *                                 set.
512  *
513  * @return lm_status_t LM_STATUS_SUCCESS on success, some other
514  *            failure code on failure.
515  */
516 lm_status_t lm_niv_event(lm_device_t *pdev, const u32_t niv_event)
517 {
518    lm_status_t                                              lm_status                      = LM_STATUS_FAILURE;
519    u32_t                                                            event_idx                      = 0;
520    u32_t                                                            handled_events                 = 0;
521    u32_t                                                            cur_event                      = 0;
522    static const lm_niv_event_function_t event_functions_arr[]  = { {DRV_STATUS_AFEX_VIFSET_REQ,   lm_niv_vif_set},
523                                                                                                                                    {DRV_STATUS_AFEX_LISTGET_REQ,  lm_niv_vif_list_get},
524                                                                                                                                    {DRV_STATUS_AFEX_LISTSET_REQ,  lm_niv_vif_list_set},
525                                                                                                                                    {DRV_STATUS_AFEX_STATSGET_REQ, lm_niv_stats_get},
526                                                                                                                              };
527 
528    //for every possible flag: if it's set, schedule a WI with the associated function and set the same flag in handled_events
529    for (event_idx = 0; event_idx < ARRSIZE(event_functions_arr); ++event_idx)
530    {
531            cur_event = event_functions_arr[event_idx].niv_event_flag;
532 
533            if (GET_FLAGS(niv_event, cur_event))
534            {
535                    lm_status = MM_REGISTER_LPME(pdev, event_functions_arr[event_idx].function, TRUE, TRUE);
536                    if (lm_status != LM_STATUS_SUCCESS)
537                    {
538                            DbgBreakIf(lm_status != LM_STATUS_SUCCESS);
539                            return lm_status;
540                    }
541                    SET_FLAGS(handled_events, cur_event);
542            }
543    }
544 
545    //make sure there we no unknown events set.
546    if (handled_events != niv_event)
547    {
548            DbgBreakIf(handled_events != niv_event);
549            return LM_STATUS_INVALID_PARAMETER;
550    }
551 
552    return lm_status;
553 }
554