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