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
init_nwuf_57710(lm_device_t * pdev,lm_nwuf_list_t * nwuf_list)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 ******************************************************************************/
lm_set_d3_nwuf(lm_device_t * pdev,const lm_wake_up_mode_t wake_up_mode)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 ******************************************************************************/
lm_set_d3_mpkt(lm_device_t * pdev,const lm_wake_up_mode_t wake_up_mode)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
set_d0_power_state(lm_device_t * pdev,u8_t set_pci_pm)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
lm_set_power_state(lm_device_t * pdev,lm_power_state_t power_state,lm_wake_up_mode_t wake_up_mode,u8_t set_pci_pm)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
lm_set_func_en(struct _lm_device_t * pdev,const u8_t b_enable)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
lm_get_func_en(struct _lm_device_t * pdev,const u8_t pfunc_abs)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
lm_pcie_state_save_for_d3(struct _lm_device_t * pdev)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
lm_pcie_state_restore_for_d0(struct _lm_device_t * pdev)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 ******************************************************************************/
find_nwuf(lm_nwuf_list_t * nwuf_list,u32_t mask_size,u8_t * byte_mask,u8_t * pattern)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 ******************************************************************************/
lm_add_nwuf(lm_device_t * pdev,u32_t mask_size,u8_t * byte_mask,u8_t * pattern)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 ******************************************************************************/
lm_del_nwuf(lm_device_t * pdev,u32_t mask_size,u8_t * byte_mask,u8_t * pattern)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
lm_clear_nwuf(lm_device_t * pdev)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