xref: /titanic_51/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/lm_power.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  *      This file contains functions that handle power management and WOL
35  *      functionality
36  *
37  ******************************************************************************/
38 
39 #include "lm5710.h"
40 
41 /*******************************************************************************
42  * Description:
43  *
44  * Return:
45  ******************************************************************************/
46 u32_t
47 init_nwuf_57710(
48     lm_device_t *pdev,
49     lm_nwuf_list_t *nwuf_list)
50 {
51     lm_nwuf_t* nwuf       = NULL ;
52     u32_t      nwuf_cnt   = 0 ;
53     u32_t      offset     = 0 ;
54     u8_t       mask       = 0 ;
55     u32_t      val        = 0 ;
56     u64_t      val_64     = 0 ;
57     u32_t      val_32[2]  = {0} ;
58     u32_t      mod        = 0 ;
59     u32_t      idx        = 0 ;
60     u32_t      bit        = 0 ;
61     u32_t      reg_len    = 0 ;
62     u32_t      reg_crc    = 0 ;
63     u32_t      reg_be     = 0 ;
64     u32_t      reg_offset = 0 ;
65     if CHK_NULL(pdev)
66     {
67         return 0 ;
68     }
69     ASSERT_STATIC(LM_NWUF_PATTERN_SIZE <= 128 );
70     // Write the size + crc32 of the patterns
71     for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
72     {
73         nwuf = &nwuf_list->nwuf_arr[idx];
74         // find NIG registers names
75 #define LM_NIG_ACPI_PAT_LEN_IDX(_func,_idx) NIG_REG_LLH##_func##_ACPI_PAT_##_idx##_LEN
76 #define LM_NIG_ACPI_PAT_CRC_IDX(_func,_idx) NIG_REG_LLH##_func##_ACPI_PAT_##_idx##_CRC
77         switch( idx )
78         { /* TBD - E1H: currenlty assuming split registers in NIG */
79         case 0:
80             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,0) : LM_NIG_ACPI_PAT_LEN_IDX(1,0) ;
81             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,0) : LM_NIG_ACPI_PAT_CRC_IDX(1,0) ;
82             break;
83         case 1:
84             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,1) : LM_NIG_ACPI_PAT_LEN_IDX(1,1) ;
85             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,1) : LM_NIG_ACPI_PAT_CRC_IDX(1,1) ;
86             break;
87         case 2:
88             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,2) : LM_NIG_ACPI_PAT_LEN_IDX(1,2) ;
89             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,2) : LM_NIG_ACPI_PAT_CRC_IDX(1,2) ;
90             break;
91         case 3:
92             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,3) : LM_NIG_ACPI_PAT_LEN_IDX(1,3) ;
93             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,3) : LM_NIG_ACPI_PAT_CRC_IDX(1,3) ;
94             break;
95         case 4:
96             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,4) : LM_NIG_ACPI_PAT_LEN_IDX(1,4) ;
97             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,4) : LM_NIG_ACPI_PAT_CRC_IDX(1,4) ;
98             break;
99         case 5:
100             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,5) : LM_NIG_ACPI_PAT_LEN_IDX(1,5) ;
101             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,5) : LM_NIG_ACPI_PAT_CRC_IDX(1,5) ;
102             break;
103         case 6:
104             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,6) : LM_NIG_ACPI_PAT_LEN_IDX(1,6) ;
105             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,6) : LM_NIG_ACPI_PAT_CRC_IDX(1,6) ;
106             break;
107         case 7:
108             reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,7) : LM_NIG_ACPI_PAT_LEN_IDX(1,7) ;
109             reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,7) : LM_NIG_ACPI_PAT_CRC_IDX(1,7) ;
110             break;
111         default:
112             DbgBreakMsg("Invalid index\n") ;
113             return 0 ;
114         } // switch idx
115         // write pattern length
116         val = nwuf->pattern_size;
117         DbgMessage(pdev, VERBOSE, "init_nwuf_57710: idx[%d] crc_mask=0x%08x size=%d\n", idx, nwuf->crc32, val  );
118         // Init NIG registers
119 #if !(defined(DOS) || defined(__LINUX))
120         if (0)
121         {
122             val = min( nwuf->size * 8, 64 ) ;
123             if( val != nwuf->size * 8 )
124             {
125                 DbgMessage(pdev, WARN, "init_nwuf_57710: idx[%d] Updated size=%03d-->%03d\n", idx, nwuf->size * 8, val ) ;
126             }
127         }
128 #endif
129         REG_WR( pdev,  reg_len, val ) ;
130         // write crc value
131         val = nwuf->crc32 ;
132         REG_WR( pdev,  reg_crc, val ) ;
133      } // LM_MAX_NWUF_CNT loop
134     // byte enable mask
135     reg_be = (0 == PORT_ID(pdev)) ? NIG_REG_LLH0_ACPI_BE_MEM_DATA : NIG_REG_LLH1_ACPI_BE_MEM_DATA ;
136 // create a matrix following LLH_vlsi_spec_rev4.doc document:
137 //
138 //        63                                                     56      7                                                        0
139 //        +------------------------------------------------------------------------------------------------------------------------+
140 //word 0  |Pattern 7 bit 0 | Pattern 6 bit 0 |....|Pattern 0 bit 0|..... |Pattern 7 bit 7 | Pattern 6 bit 7 |....|Pattern 0 bit 7  |
141 //        +------------------------------------------------------------------------------------------------------------------------+
142 //word 1  |Pattern 7 bit 8 | Pattern 6 bit 8 |....|Pattern 0 bit 8|..... |Pattern 7 bit 15| Pattern 6 bit 15|....|Pattern 0 bit 15 |
143 //        +------------------------------------------------------------------------------------------------------------------------+
144 //        |                                                      ..........                                                        |
145 //        +------------------------------------------------------------------------------------------------------------------------+
146 //        |                                                      ..........                                                        |
147 //        +------------------------------------------------------------------------------------------------------------------------+
148 //        |                                                                                                                        |
149 //        +------------------------------------------------------------------------------------------------------------------------+
150 //        |                                                      ..........                                                        |
151 //        +------------------------------------------------------------------------------------------------------------------------+
152 //word 15 |Pattern 7bit 120| Pattern6 bit120 |....|Pattern0 bit120|..... |Pattern7 bit 127| Pattern6 bit 127|....|Pattern0 bit 127 |
153 //        +------------------------------------------------------------------------------------------------------------------------+
154 
155     for(offset = 0; offset <= LM_NWUF_PATTERN_SIZE; offset++)
156     {
157         mod = offset%8 ;
158         if ( ( 0 == mod ) && ( offset!= 0 ) )
159         {
160             // write to the registers, WB (write using DMAE)
161             reg_offset  = ( offset / 8 ) - 1  ; // 0 - 15
162             val = (reg_offset*sizeof(u64_t)) ;
163             // For yet to be explained reasons, using WR_DMAE write it to the opposite port.
164             // We'll always use indirect writes
165             if( 0 )//pdev->vars.b_is_dmae_ready )
166             {
167                 REG_WR_DMAE( pdev,  reg_be+val, &val_64 ) ;
168             }
169             else
170             {
171                 val_32[0] = U64_LO(val_64);
172                 val_32[1] = U64_HI(val_64);
173                 REG_WR_IND( pdev,  reg_be+val,   val_32[0] ) ;
174                 REG_WR_IND( pdev,  reg_be+val+4, val_32[1] ) ;
175             }
176             // reset for next 8 iterations
177             val_64 = 0 ;
178         }
179         // after write - nothing to do!
180         if( LM_NWUF_PATTERN_SIZE == offset )
181         {
182             break ;
183         }
184         for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
185         {
186             nwuf = &nwuf_list->nwuf_arr[idx];
187             if(nwuf->size == 0 || offset > nwuf->size * 8)
188             {
189                 continue;
190             }
191             mask = nwuf->mask[(offset/8)]; // 0-15
192             bit = mod ;
193             if( mask & (1 << bit) )
194             {
195                 val_64  |= 0x1ULL << idx;
196             }
197         } // LM_MAX_NWUF_CNT
198         if( mod != 7 )
199         {
200             val_64  = val_64 << 8 ;
201         }
202     } // LM_NWUF_PATTERN_SIZE
203     nwuf_cnt = 0;
204     // count total items
205     for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
206     {
207         nwuf = &nwuf_list->nwuf_arr[idx];
208         if(nwuf->size == 0)
209         {
210             continue;
211         }
212         nwuf_cnt++ ;
213     }
214     return nwuf_cnt;
215 } /* init_nwuf_57510 */
216 
217 /*******************************************************************************
218  * Description:
219  *         Configures nwuf packets.
220  *         (for wide bus)
221  * Return:
222  ******************************************************************************/
223 void lm_set_d3_nwuf(       lm_device_t*      pdev,
224                      const lm_wake_up_mode_t wake_up_mode )
225 {
226     const u8_t port_id     = PORT_ID(pdev);
227     u8_t  abs_func_id      = ABS_FUNC_ID(pdev); // for debugging only
228     u8_t  nwuf_reg_value   = 0 ;
229     u32_t cnt              = 0 ;
230     u32_t offset           = 0;
231 
232     UNREFERENCED_PARAMETER_( abs_func_id );
233 
234     /* Set up interesting packet detection. */
235     if ( 0 != GET_FLAGS(wake_up_mode, LM_WAKE_UP_MODE_NWUF) )
236     {
237         // This comment - from TETON
238         /* Also need to be documented in the prm - to prevent a false
239          * detection, we need to disable ACP_EN if there is no pattern
240          * programmed.  There is no way of preventing false detection
241          * by intializing the pattern buffer a certain way. */
242         if( (cnt = init_nwuf_57710(pdev, &pdev->nwuf_list)) )
243         {
244             DbgMessage(pdev, WARN, "LM_WAKE_UP_MODE_NWUF is ON cnt=%d\n", cnt );
245             nwuf_reg_value = 1 ;
246         }
247         else
248         {
249             DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_NWUF is ON cnt=0\n" );
250             nwuf_reg_value = 0 ;
251         }
252 
253         // Enable ACPI register (split)
254         offset = (0 == port_id) ? NIG_REG_LLH0_ACPI_ENABLE :NIG_REG_LLH1_ACPI_ENABLE;
255         REG_WR( pdev, offset, nwuf_reg_value ) ;
256 
257         if( !CHIP_IS_E1(pdev) )
258         {
259             // mark function for enablement in nig
260             lm_set_func_en(pdev, TRUE);
261 
262             // for E2 and above, we need to set also NIG_REG_PX_ACPI_MF_GLOBAL_EN to 1
263             // This register is global per port.
264             // The "algorithm" will be - if ANY of the vnic is enabled - we enable ACPI for the port (logic OR)
265             // The patterns themselves should prevent a "false positive" wake up for a function
266             // All the above is relevant for MF SI mode!
267             if ( !CHIP_IS_E1x(pdev)   &&
268                  nwuf_reg_value       &&
269                  ( IS_MF_SI_MODE(pdev) ) )
270             {
271                 // TODO - NIV (T7.0) should be different behaviour!
272                 DbgBreakIf( CHIP_IS_E1(pdev) ); // if someone will take this if block out of "if( !IS_E1(pdev)"
273                 DbgBreakIf( !nwuf_reg_value );
274 
275                 offset = (0 == port_id) ? NIG_REG_P0_ACPI_MF_GLOBAL_EN :NIG_REG_P1_ACPI_MF_GLOBAL_EN;
276 
277                 REG_WR( pdev, offset, nwuf_reg_value ) ;
278             }
279         }
280         DbgMessage(pdev, WARN, "ACPI_ENABLE=%d\n", nwuf_reg_value );
281     }
282     else
283     {
284         DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_NWUF is OFF\n" );
285     }
286 } /* lm_set_d3_nwuf */
287 /*******************************************************************************
288  * Description:
289  *         Configures magic packets.
290  * Return:
291  ******************************************************************************/
292 void lm_set_d3_mpkt( lm_device_t*            pdev,
293                      const lm_wake_up_mode_t wake_up_mode )
294 {
295     u32_t       emac_base     = 0 ;
296     u32_t       val           = 0 ;
297     u32_t       offset        = 0 ;
298     u8_t  const b_enable_mpkt = ( 0 != GET_FLAGS(wake_up_mode, LM_WAKE_UP_MODE_MAGIC_PACKET) );
299     u8_t*       mac_addr      = &pdev->params.mac_addr[0]; //&pdev->hw_info.mac_addr[0];
300 
301     if CHK_NULL(pdev)
302     {
303         DbgBreakIf(!pdev) ;
304         return;
305     }
306     /* Set up magic packet detection. */
307     if( b_enable_mpkt )
308     {
309         DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_MAGIC_PACKET is ON\n" );
310     }
311     else
312     {
313         DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_MAGIC_PACKET is OFF\n" );
314     }
315     emac_base = ( 0 == PORT_ID(pdev) ) ? GRCBASE_EMAC0 : GRCBASE_EMAC1 ;
316 
317     /* The mac address is written to entries 1-5 to
318        preserve entry 0 which is used by the PMF */
319     val = (mac_addr[0] << 8) | mac_addr[1];
320     offset = EMAC_REG_EMAC_MAC_MATCH + (VNIC_ID(pdev)+ 1)*8 ;
321     REG_WR(pdev, emac_base+ offset , b_enable_mpkt ? val:0);
322 
323     val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
324           (mac_addr[4] << 8)  |  mac_addr[5];
325     offset+= 4;
326     REG_WR(pdev, emac_base+ offset, b_enable_mpkt ? val:0);
327 }
328 
329 /*******************************************************************************
330  * Description:
331  *
332  * Return:
333  ******************************************************************************/
334 STATIC void
335 set_d0_power_state(
336     lm_device_t *pdev,
337     u8_t set_pci_pm)
338 {
339     u32_t idx = 0;
340     UNREFERENCED_PARAMETER_(set_pci_pm);
341     DbgMessage(pdev, INFORM, "### set_d0_power_state\n");
342 #if 0
343     u32_t val;
344     /* This step should be done by the OS or the caller.  Windows is
345      * already doing this. */
346     if(set_pci_pm)
347     {
348         /* Set the device to D0 state.  If a device is already in D3 state,
349          * we will not be able to read the PCICFG_PM_CSR register using the
350          * PCI memory command, we need to use config access here. */
351         mm_read_pci(
352             pdev,
353             OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
354             &val);
355         /* Set the device to D0 state.  This may be already done by the OS. */
356         val &= ~PCICFG_PM_CSR_STATE;
357         val |= PCICFG_PM_CSR_STATE_D0 | PCICFG_PM_CSR_PME_STATUS;
358         mm_write_pci(
359             pdev,
360             OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
361             val);
362     }
363 #endif
364     /* With 5706_A1, the chip gets a reset coming out of D3.  Wait
365      * for the boot to code finish running before we continue.  Without
366      * this wait, we could run into lockup or the PHY may not work. */
367     if(CHIP_ID(pdev) == CHIP_ID_5706_A1)
368     {
369         for(idx = 0; idx < 1000; idx++)
370         {
371             mm_wait(pdev, 15);
372         }
373     }
374 #if 0 // PWR_TODO - WOL wait for spec
375     /* Clear the ACPI_RCVD and MPKT_RCVD bits and disable magic packet. */
376     val = REG_RD(pdev, emac.emac_mode);
377     val |= EMAC_MODE_MPKT_RCVD | EMAC_MODE_ACPI_RCVD;
378     val &= ~EMAC_MODE_MPKT;
379     REG_WR(pdev, emac.emac_mode, val);
380     /* Disable interesting packet detection. */
381     val = REG_RD(pdev, rpm.rpm_config);
382     val &= ~RPM_CONFIG_ACPI_ENA;
383     REG_WR(pdev, rpm.rpm_config, val);
384 #endif // if 0
385 } /* set_d0_power_state */
386 
387 
388 /*******************************************************************************
389  * Description:
390  *
391  * Return:
392  ******************************************************************************/
393 void
394 lm_set_power_state(
395     lm_device_t*      pdev,
396     lm_power_state_t  power_state,
397     lm_wake_up_mode_t wake_up_mode,     /* Valid when power_state is D3. */
398     u8_t              set_pci_pm )
399 {
400     UNREFERENCED_PARAMETER_(wake_up_mode);
401     switch( power_state )
402     {
403     case LM_POWER_STATE_D0:
404         set_d0_power_state(pdev, set_pci_pm);
405         break;
406     default:
407         //set_d3_power_state(pdev, wake_up_mode, set_pci_pm);
408         break;
409     }
410 } /* lm_set_power_state */
411 
412 void lm_set_func_en(struct _lm_device_t *pdev, const u8_t b_enable)
413 {
414     const u8_t bus_num = INST_ID_TO_BUS_NUM(PFDEV(pdev)->vars.inst_id) ;
415 
416     if (pdev->params.pfunc_abs < ARRSIZE(g_lm_chip_global[0].func_en))
417     {
418         g_lm_chip_global[bus_num].func_en[pdev->params.pfunc_abs] = b_enable;
419     }
420 }
421 
422 u8_t lm_get_func_en(struct _lm_device_t *pdev, const u8_t pfunc_abs)
423 {
424     const u8_t bus_num = INST_ID_TO_BUS_NUM(PFDEV(pdev)->vars.inst_id) ;
425 
426     if (pfunc_abs < ARRSIZE(g_lm_chip_global[0].func_en))
427     {
428         return g_lm_chip_global[bus_num].func_en[pfunc_abs];
429     }
430 
431     return 0;
432 }
433 
434 #define DEFINITIVE_PF_FOR_MPS 0 //PF0 defines the MPS value for all PFs when the device is in ARI mode.
435 
436 void lm_pcie_state_save_for_d3(struct _lm_device_t *pdev)
437 {
438     static const u32_t pcicfg_device_control_offset     = PCICFG_OFFSET + PCICFG_DEVICE_CONTROL;
439     static const u32_t PCICFG_DEVICE_CONTROL_MPS_MASK   = 0x000000E0;
440     const u8_t abs_func_id                              = ABS_FUNC_ID(pdev);
441 
442     u32_t pf0_pcie_status_control = 0;
443 
444     //save PF0's PCIE_REG_PCIER_DEVICE_STATUS_CONTROL, since Windows does not restore the MPS value properly when resuming from
445     //D3. See CQ57271.
446     if (DEFINITIVE_PF_FOR_MPS != abs_func_id)
447     {
448         lm_pretend_func(pdev, DEFINITIVE_PF_FOR_MPS);
449         pf0_pcie_status_control = REG_RD(pdev, pcicfg_device_control_offset);
450         pdev->hw_info.saved_pf0_pcie_mps = GET_FLAGS(pf0_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
451         lm_pretend_func(pdev, abs_func_id);
452     }
453 }
454 
455 void lm_pcie_state_restore_for_d0(struct _lm_device_t *pdev)
456 {
457     static const u32_t pcicfg_device_control_offset     = PCICFG_OFFSET + PCICFG_DEVICE_CONTROL;
458     static const u32_t PCICFG_DEVICE_CONTROL_MPS_MASK   = 0x000000E0;
459     const u8_t abs_func_id                              = ABS_FUNC_ID(pdev);
460 
461     u32_t pf0_pcie_status_control = 0;
462     u32_t pf0_mps = 0;
463     u32_t own_pcie_status_control = REG_RD(pdev, pcicfg_device_control_offset);
464     u32_t own_mps = GET_FLAGS(own_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
465 
466     //restore PF0's PCIE_REG_PCIER_DEVICE_STATUS_CONTROL, since Windows does not restore the MPS value properly when resuming from
467     //D3. See CQ57271.
468     if((DEFINITIVE_PF_FOR_MPS != ABS_FUNC_ID(pdev)) && // if we're not PF0 ourselves,
469        (INVALID_MPS != pdev->hw_info.saved_pf0_pcie_mps)) //and if there was a previous value saved
470     {
471         lm_pretend_func(pdev, DEFINITIVE_PF_FOR_MPS);
472 
473         //read current MPS value of PF0
474         pf0_pcie_status_control = REG_RD(pdev, pcicfg_device_control_offset);
475         pf0_mps = GET_FLAGS(pf0_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
476 
477         //if it's different than the value we saved when going down to D3, and it's different then
478         //current PF's MPS - restore it
479         if ( ( pf0_mps != pdev->hw_info.saved_pf0_pcie_mps) &&
480              ( pf0_mps != own_mps) )
481         {
482             RESET_FLAGS(pf0_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
483             SET_FLAGS(pf0_pcie_status_control, pdev->hw_info.saved_pf0_pcie_mps);
484 
485             REG_WR(pdev, pcicfg_device_control_offset, pf0_pcie_status_control);
486 
487 			++pdev->debug_info.pf0_mps_overwrite;
488         }
489 
490         lm_pretend_func(pdev, abs_func_id);
491     }
492 }
493 
494 /*******************************************************************************
495  * Description:
496  *
497  * Return:
498  ******************************************************************************/
499 static lm_nwuf_t * find_nwuf( lm_nwuf_list_t* nwuf_list,
500                               u32_t           mask_size,
501                               u8_t*           byte_mask,
502                               u8_t*           pattern )
503 {
504     lm_nwuf_t *nwuf;
505     u8_t found;
506     u32_t idx;
507     u32_t j;
508     u32_t k;
509     ASSERT_STATIC(LM_MAX_NWUF_CNT==8);
510     for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
511     {
512         nwuf = &nwuf_list->nwuf_arr[idx];
513         if(nwuf->size != mask_size)
514         {
515             continue;
516         }
517         found = TRUE;
518         for(j = 0; j < mask_size && found == TRUE; j++)
519         {
520             if(nwuf->mask[j] != byte_mask[j])
521             {
522                 found = FALSE;
523                 break;
524             }
525             for(k = 0; k < 8; k++)
526             {
527                 if((byte_mask[j] & (1 << k)) &&
528                     (nwuf->pattern[j*8 + k] != pattern[j*8 + k]))
529                 {
530                     found = FALSE;
531                     break;
532                 }
533             }
534         }
535         if(found)
536         {
537             return nwuf;
538         }
539     }
540     return NULL;
541 } /* find_nwuf */
542 /*******************************************************************************
543  * Description:
544  *
545  * Return:
546  ******************************************************************************/
547 lm_status_t lm_add_nwuf( lm_device_t* pdev,
548                          u32_t        mask_size,
549                          u8_t*        byte_mask,
550                          u8_t*        pattern )
551 {
552     lm_nwuf_t* nwuf        = NULL ;
553     u32_t      idx         = 0 ;
554     u32_t      j           = 0 ;
555     u32_t      k           = 0 ;
556     u32_t      zero_serial = 0 ;
557     if( ERR_IF(0 == mask_size) || ERR_IF( mask_size > LM_NWUF_PATTERN_MASK_SIZE ) )
558     {
559         DbgBreakMsg("Invalid byte mask size\n");
560         return LM_STATUS_FAILURE;
561     }
562     /* If this is a duplicate entry, we are done. */
563     nwuf = find_nwuf(&pdev->nwuf_list, mask_size, byte_mask, pattern);
564     // according to DTM test (WHQL) we should fail duplicate adding
565     if( NULL != nwuf )
566     {
567         DbgMessage(pdev, WARN, "Duplicated nwuf entry.\n");
568         return LM_STATUS_EXISTING_OBJECT;
569     }
570     /* Find an empty slot. */
571     nwuf = NULL;
572     for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
573     {
574         if(pdev->nwuf_list.nwuf_arr[idx].size == 0)
575         {
576             nwuf = &pdev->nwuf_list.nwuf_arr[idx] ;
577             break;
578         }
579     }
580     if( NULL == nwuf )
581     {
582         DbgMessage(pdev, WARN, "Cannot add Nwuf, exceeded maximum.\n");
583         return LM_STATUS_RESOURCE;
584     }
585     pdev->nwuf_list.cnt++;
586     /* Save nwuf data. */
587     nwuf->size         = mask_size;
588     // apply the mask on the pattern
589     for(j = 0; j < mask_size; j++)
590     {
591         nwuf->mask[j] = byte_mask[j];
592         for(k = 0; k < 8; k++)
593         {
594             if(byte_mask[j] & (1 << k))
595             {
596                 nwuf->pattern[j*8 + k] = pattern[j*8 + k];
597                 zero_serial = 0;
598             }
599             else
600             {
601                 nwuf->pattern[j*8 + k] = 0;
602                 ++zero_serial;
603             }
604         }
605     }
606     // Decrement from pattern size last bits that are not enabled (revresed)
607     // TODO: When pattern size will be added to the interface, this calculation (zero_serial) is not needed, and
608     //       pattern size would be the original pattern size as recieved from OS
609     nwuf->pattern_size = mask_size*8 - zero_serial ;
610     j = nwuf->pattern_size/8 ;
611     if( nwuf->pattern_size % 8 )
612     {
613         j++;
614     }
615     j*= 8;
616     // TODO: when patter size will be added to the interface, j should be: mask_size*8
617     // calc the CRC using the same NIG algorithem and save it
618     nwuf->crc32 = calc_crc32( nwuf->pattern, j, 0xffffffff /*seed*/, 1 /*complement*/ ) ;
619 #define WOL_DBG_PRINT 0
620 #if (WOL_DBG_PRINT) // this is to debug wolpattern WHQL test
621     {
622         printk("lm_add_nwuf: pattern[%u] mask_size=%03u pattern_size=%03u (%03u) crc calc size=%03u\n",
623                  idx,
624                  nwuf->size,
625                  nwuf->pattern_size,
626                  nwuf->size*8,
627                  j );
628         printk("pattern[%u] CRC=0x%08x\n",idx, nwuf->crc32 ) ;
629         //printk("Pattern (original) size=%03u\n", nwuf->pattern_size ) ;
630 
631         for( idx = 0 ; idx < nwuf->size*8 ; idx++ )
632         {
633             printk("%02X", pattern[idx] ) ;
634             if( idx != nwuf->size*8-1 )
635             {
636                 printk("-") ;
637             }
638             if( ( 0!= idx ) && 0 == ( idx % 32 ) )
639             {
640                 printk("\n") ;
641             }
642         }
643         printk("\nPattern (masked):\n");
644         for( idx = 0 ; idx < nwuf->size*8 ; idx++ )
645         {
646             printk("%02X", nwuf->pattern[idx] ) ;
647             if( idx != nwuf->size*8-1 )
648             {
649                 printk("-") ;
650             }
651             if( ( 0!= idx ) && 0 == ( idx % 32 ) )
652             {
653                 printk("\n") ;
654             }
655         }
656         printk("\nmask (size=%03u)\n", nwuf->size) ;
657         for( idx = 0 ; idx < nwuf->size ; idx++ )
658         {
659             printk("%02X", byte_mask[idx] ) ;
660             if( idx != nwuf->size-1 )
661             {
662                 printk("-") ;
663             }
664         }
665         printk("\n") ;
666     }
667 #endif // WOL_DBG_PRINT
668     if ERR_IF( 0xffffffff == nwuf->crc32 )
669     {
670         DbgBreakMsg("Invalid crc32\n") ;
671     }
672     return LM_STATUS_SUCCESS;
673 } /* lm_add_nwuf */
674 
675 /*******************************************************************************
676  * Description:
677  *
678  * Return:
679  ******************************************************************************/
680 lm_status_t lm_del_nwuf( lm_device_t* pdev,
681                          u32_t        mask_size,
682                          u8_t*        byte_mask,
683                          u8_t *       pattern )
684 {
685     lm_nwuf_t *nwuf;
686     u32_t k;
687     if(mask_size == 0 || mask_size > LM_NWUF_PATTERN_MASK_SIZE)
688     {
689         DbgBreakMsg("Invalid byte mask size\n");
690         return LM_STATUS_FAILURE;
691     }
692     /* Look for a matching pattern. */
693     nwuf = find_nwuf(&pdev->nwuf_list, mask_size, byte_mask, pattern);
694     if(nwuf)
695     {
696         /*
697         printk("lm_del_nwuf: pattern[?] mask_size=%03u(%03u) cnt=%u crc32=0x%08x %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X....\n",
698                  nwuf->size, nwuf->size*8, pdev->nwuf_list.cnt-1, nwuf->crc32,
699                  nwuf->pattern[0],  nwuf->pattern[1], nwuf->pattern[2], nwuf->pattern[3],
700                  nwuf->pattern[4],  nwuf->pattern[5], nwuf->pattern[6], nwuf->pattern[7],
701                  nwuf->pattern[8],  nwuf->pattern[9], nwuf->pattern[10], nwuf->pattern[11],
702                  nwuf->pattern[12], nwuf->pattern[13], nwuf->pattern[14], nwuf->pattern[15] ) ;
703         */
704         nwuf->size = 0;
705         nwuf->crc32 = 0 ;
706         for(k = 0; k < LM_NWUF_PATTERN_MASK_SIZE; k++)
707         {
708             nwuf->mask[k] = 0;
709         }
710         for(k = 0; k < LM_NWUF_PATTERN_SIZE; k++)
711         {
712             nwuf->pattern[k] = 0xff;
713         }
714         pdev->nwuf_list.cnt--;
715     }
716     else
717     {
718         // according to DTM test (WHQL) we should fail non exists delete
719         DbgMessage(pdev, WARN, "not exists nwuf entry. mask_size=%03d\n", mask_size );
720         return LM_STATUS_OBJECT_NOT_FOUND;
721     }
722     return LM_STATUS_SUCCESS;
723 } /* lm_del_nwuf */
724 
725 /*******************************************************************************
726  * Description:
727  *
728  * Return:
729  ******************************************************************************/
730 void
731 lm_clear_nwuf(
732     lm_device_t *pdev)
733 {
734     u32_t j;
735     u32_t k;
736     for(j = 0; j < LM_MAX_NWUF_CNT; j++)
737     {
738         pdev->nwuf_list.nwuf_arr[j].size = 0;
739         for(k = 0; k < LM_NWUF_PATTERN_MASK_SIZE; k++)
740         {
741             pdev->nwuf_list.nwuf_arr[j].mask[k] = 0;
742         }
743         for(k = 0; k < LM_NWUF_PATTERN_SIZE; k++)
744         {
745             pdev->nwuf_list.nwuf_arr[j].pattern[k] = 0xff;
746         }
747     }
748     pdev->nwuf_list.cnt = 0;
749 } /* lm_clear_nwuf */
750 
751 
752