1 /****************************************************************************** 2 3 Copyright (c) 2001-2017, Intel Corporation 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 9 1. Redistributions of source code must retain the above copyright notice, 10 this list of conditions and the following disclaimer. 11 12 2. Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 16 3. Neither the name of the Intel Corporation nor the names of its 17 contributors may be used to endorse or promote products derived from 18 this software without specific prior written permission. 19 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 POSSIBILITY OF SUCH DAMAGE. 31 32 ******************************************************************************/ 33 /*$FreeBSD: head/sys/dev/ixgbe/if_bypass.c 327031 2017-12-20 18:15:06Z erj $*/ 34 35 36 #include "ixgbe.h" 37 38 /************************************************************************ 39 * ixgbe_bypass_mutex_enter 40 * 41 * Mutex support for the bypass feature. Using a dual lock 42 * to facilitate a privileged access to the watchdog update 43 * over other threads. 44 ************************************************************************/ 45 static void 46 ixgbe_bypass_mutex_enter(struct adapter *adapter) 47 { 48 while (atomic_cas_uint(&adapter->bypass.low, 0, 1) == 0) 49 usec_delay(3000); 50 while (atomic_cas_uint(&adapter->bypass.high, 0, 1) == 0) 51 usec_delay(3000); 52 return; 53 } /* ixgbe_bypass_mutex_enter */ 54 55 /************************************************************************ 56 * ixgbe_bypass_mutex_clear 57 ************************************************************************/ 58 static void 59 ixgbe_bypass_mutex_clear(struct adapter *adapter) 60 { 61 while (atomic_cas_uint(&adapter->bypass.high, 1, 0) == 0) 62 usec_delay(6000); 63 while (atomic_cas_uint(&adapter->bypass.low, 1, 0) == 0) 64 usec_delay(6000); 65 return; 66 } /* ixgbe_bypass_mutex_clear */ 67 68 /************************************************************************ 69 * ixgbe_bypass_wd_mutex_enter 70 * 71 * Watchdog entry is allowed to simply grab the high priority 72 ************************************************************************/ 73 static void 74 ixgbe_bypass_wd_mutex_enter(struct adapter *adapter) 75 { 76 while (atomic_cas_uint(&adapter->bypass.high, 0, 1) == 0) 77 usec_delay(3000); 78 return; 79 } /* ixgbe_bypass_wd_mutex_enter */ 80 81 /************************************************************************ 82 * ixgbe_bypass_wd_mutex_clear 83 ************************************************************************/ 84 static void 85 ixgbe_bypass_wd_mutex_clear(struct adapter *adapter) 86 { 87 while (atomic_cas_uint(&adapter->bypass.high, 1, 0) == 0) 88 usec_delay(6000); 89 return; 90 } /* ixgbe_bypass_wd_mutex_clear */ 91 92 /************************************************************************ 93 * ixgbe_get_bypass_time 94 ************************************************************************/ 95 static void 96 ixgbe_get_bypass_time(u32 *year, u32 *sec) 97 { 98 struct timespec current; 99 100 *year = 1970; /* time starts at 01/01/1970 */ 101 nanotime(¤t); 102 *sec = current.tv_sec; 103 104 while(*sec > SEC_THIS_YEAR(*year)) { 105 *sec -= SEC_THIS_YEAR(*year); 106 (*year)++; 107 } 108 } /* ixgbe_get_bypass_time */ 109 110 /************************************************************************ 111 * ixgbe_bp_version 112 * 113 * Display the feature version 114 ************************************************************************/ 115 static int 116 ixgbe_bp_version(SYSCTLFN_ARGS) 117 { 118 struct sysctlnode node = *rnode; 119 struct adapter *adapter = (struct adapter *)node.sysctl_data; 120 struct ixgbe_hw *hw = &adapter->hw; 121 int error = 0; 122 static int featversion = 0; 123 u32 cmd; 124 125 ixgbe_bypass_mutex_enter(adapter); 126 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 127 cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) & 128 BYPASS_CTL2_OFFSET_M; 129 if ((error = hw->mac.ops.bypass_rw(hw, cmd, &featversion) != 0)) 130 goto err; 131 msec_delay(100); 132 cmd &= ~BYPASS_WE; 133 if ((error = hw->mac.ops.bypass_rw(hw, cmd, &featversion) != 0)) 134 goto err; 135 ixgbe_bypass_mutex_clear(adapter); 136 featversion &= BYPASS_CTL2_DATA_M; 137 node.sysctl_data = &featversion; 138 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 139 return (error); 140 err: 141 ixgbe_bypass_mutex_clear(adapter); 142 return (error); 143 144 } /* ixgbe_bp_version */ 145 146 /************************************************************************ 147 * ixgbe_bp_set_state 148 * 149 * Show/Set the Bypass State: 150 * 1 = NORMAL 151 * 2 = BYPASS 152 * 3 = ISOLATE 153 * 154 * With no argument the state is displayed, 155 * passing a value will set it. 156 ************************************************************************/ 157 static int 158 ixgbe_bp_set_state(SYSCTLFN_ARGS) 159 { 160 struct sysctlnode node = *rnode; 161 struct adapter *adapter = (struct adapter *)node.sysctl_data; 162 struct ixgbe_hw *hw = &adapter->hw; 163 int error = 0; 164 static int state = 0; 165 166 /* Get the current state */ 167 ixgbe_bypass_mutex_enter(adapter); 168 error = hw->mac.ops.bypass_rw(hw, 169 BYPASS_PAGE_CTL0, &state); 170 ixgbe_bypass_mutex_clear(adapter); 171 if (error != 0) 172 return (error); 173 state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3; 174 175 node.sysctl_data = &state; 176 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 177 if ((error != 0) || (newp == NULL)) 178 return (error); 179 180 /* Sanity check new state */ 181 switch (state) { 182 case BYPASS_NORM: 183 case BYPASS_BYPASS: 184 case BYPASS_ISOLATE: 185 break; 186 default: 187 return (EINVAL); 188 } 189 ixgbe_bypass_mutex_enter(adapter); 190 if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 191 BYPASS_MODE_OFF_M, state) != 0)) 192 goto out; 193 /* Set AUTO back on so FW can receive events */ 194 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 195 BYPASS_MODE_OFF_M, BYPASS_AUTO); 196 out: 197 ixgbe_bypass_mutex_clear(adapter); 198 usec_delay(6000); 199 return (error); 200 } /* ixgbe_bp_set_state */ 201 202 /************************************************************************ 203 * The following routines control the operational 204 * "rules" of the feature, what behavior will occur 205 * when particular events occur. 206 * Values are: 207 * 0 - no change for the event (NOP) 208 * 1 - go to Normal operation 209 * 2 - go to Bypass operation 210 * 3 - go to Isolate operation 211 * Calling the entry with no argument just displays 212 * the current rule setting. 213 ************************************************************************/ 214 215 /************************************************************************ 216 * ixgbe_bp_timeout 217 * 218 * This is to set the Rule for the watchdog, 219 * not the actual watchdog timeout value. 220 ************************************************************************/ 221 static int 222 ixgbe_bp_timeout(SYSCTLFN_ARGS) 223 { 224 struct sysctlnode node = *rnode; 225 struct adapter *adapter = (struct adapter *)node.sysctl_data; 226 struct ixgbe_hw *hw = &adapter->hw; 227 int error = 0; 228 static int timeout = 0; 229 230 /* Get the current value */ 231 ixgbe_bypass_mutex_enter(adapter); 232 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout); 233 ixgbe_bypass_mutex_clear(adapter); 234 if (error) 235 return (error); 236 timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3; 237 238 node.sysctl_data = &timeout; 239 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 240 if ((error) || (newp == NULL)) 241 return (error); 242 243 /* Sanity check on the setting */ 244 switch (timeout) { 245 case BYPASS_NOP: 246 case BYPASS_NORM: 247 case BYPASS_BYPASS: 248 case BYPASS_ISOLATE: 249 break; 250 default: 251 return (EINVAL); 252 } 253 254 /* Set the new state */ 255 ixgbe_bypass_mutex_enter(adapter); 256 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 257 BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT); 258 ixgbe_bypass_mutex_clear(adapter); 259 usec_delay(6000); 260 return (error); 261 } /* ixgbe_bp_timeout */ 262 263 /************************************************************************ 264 * ixgbe_bp_main_on 265 ************************************************************************/ 266 static int 267 ixgbe_bp_main_on(SYSCTLFN_ARGS) 268 { 269 struct sysctlnode node = *rnode; 270 struct adapter *adapter = (struct adapter *)node.sysctl_data; 271 struct ixgbe_hw *hw = &adapter->hw; 272 int error = 0; 273 static int main_on = 0; 274 275 ixgbe_bypass_mutex_enter(adapter); 276 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on); 277 main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3; 278 ixgbe_bypass_mutex_clear(adapter); 279 if (error) 280 return (error); 281 282 node.sysctl_data = &main_on; 283 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 284 if ((error) || (newp == NULL)) 285 return (error); 286 287 /* Sanity check on the setting */ 288 switch (main_on) { 289 case BYPASS_NOP: 290 case BYPASS_NORM: 291 case BYPASS_BYPASS: 292 case BYPASS_ISOLATE: 293 break; 294 default: 295 return (EINVAL); 296 } 297 298 /* Set the new state */ 299 ixgbe_bypass_mutex_enter(adapter); 300 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 301 BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT); 302 ixgbe_bypass_mutex_clear(adapter); 303 usec_delay(6000); 304 return (error); 305 } /* ixgbe_bp_main_on */ 306 307 /************************************************************************ 308 * ixgbe_bp_main_off 309 ************************************************************************/ 310 static int 311 ixgbe_bp_main_off(SYSCTLFN_ARGS) 312 { 313 struct sysctlnode node = *rnode; 314 struct adapter *adapter = (struct adapter *)node.sysctl_data; 315 struct ixgbe_hw *hw = &adapter->hw; 316 int error = 0; 317 static int main_off = 0; 318 319 ixgbe_bypass_mutex_enter(adapter); 320 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off); 321 ixgbe_bypass_mutex_clear(adapter); 322 if (error) 323 return (error); 324 main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3; 325 326 node.sysctl_data = &main_off; 327 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 328 if ((error) || (newp == NULL)) 329 return (error); 330 331 /* Sanity check on the setting */ 332 switch (main_off) { 333 case BYPASS_NOP: 334 case BYPASS_NORM: 335 case BYPASS_BYPASS: 336 case BYPASS_ISOLATE: 337 break; 338 default: 339 return (EINVAL); 340 } 341 342 /* Set the new state */ 343 ixgbe_bypass_mutex_enter(adapter); 344 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 345 BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT); 346 ixgbe_bypass_mutex_clear(adapter); 347 usec_delay(6000); 348 return (error); 349 } /* ixgbe_bp_main_off */ 350 351 /************************************************************************ 352 * ixgbe_bp_aux_on 353 ************************************************************************/ 354 static int 355 ixgbe_bp_aux_on(SYSCTLFN_ARGS) 356 { 357 struct sysctlnode node = *rnode; 358 struct adapter *adapter = (struct adapter *)node.sysctl_data; 359 struct ixgbe_hw *hw = &adapter->hw; 360 int error = 0; 361 static int aux_on = 0; 362 363 ixgbe_bypass_mutex_enter(adapter); 364 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on); 365 ixgbe_bypass_mutex_clear(adapter); 366 if (error) 367 return (error); 368 aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3; 369 370 node.sysctl_data = &aux_on; 371 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 372 if ((error) || (newp == NULL)) 373 return (error); 374 375 /* Sanity check on the setting */ 376 switch (aux_on) { 377 case BYPASS_NOP: 378 case BYPASS_NORM: 379 case BYPASS_BYPASS: 380 case BYPASS_ISOLATE: 381 break; 382 default: 383 return (EINVAL); 384 } 385 386 /* Set the new state */ 387 ixgbe_bypass_mutex_enter(adapter); 388 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 389 BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT); 390 ixgbe_bypass_mutex_clear(adapter); 391 usec_delay(6000); 392 return (error); 393 } /* ixgbe_bp_aux_on */ 394 395 /************************************************************************ 396 * ixgbe_bp_aux_off 397 ************************************************************************/ 398 static int 399 ixgbe_bp_aux_off(SYSCTLFN_ARGS) 400 { 401 struct sysctlnode node = *rnode; 402 struct adapter *adapter = (struct adapter *)node.sysctl_data; 403 struct ixgbe_hw *hw = &adapter->hw; 404 int error = 0; 405 static int aux_off = 0; 406 407 ixgbe_bypass_mutex_enter(adapter); 408 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off); 409 ixgbe_bypass_mutex_clear(adapter); 410 if (error) 411 return (error); 412 aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3; 413 414 node.sysctl_data = &aux_off; 415 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 416 if ((error) || (newp == NULL)) 417 return (error); 418 419 /* Sanity check on the setting */ 420 switch (aux_off) { 421 case BYPASS_NOP: 422 case BYPASS_NORM: 423 case BYPASS_BYPASS: 424 case BYPASS_ISOLATE: 425 break; 426 default: 427 return (EINVAL); 428 } 429 430 /* Set the new state */ 431 ixgbe_bypass_mutex_enter(adapter); 432 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 433 BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT); 434 ixgbe_bypass_mutex_clear(adapter); 435 usec_delay(6000); 436 return (error); 437 } /* ixgbe_bp_aux_off */ 438 439 /************************************************************************ 440 * ixgbe_bp_wd_set - Set the Watchdog timer value 441 * 442 * Valid settings are: 443 * - 0 will disable the watchdog 444 * - 1, 2, 3, 4, 8, 16, 32 445 * - anything else is invalid and will be ignored 446 ************************************************************************/ 447 static int 448 ixgbe_bp_wd_set(SYSCTLFN_ARGS) 449 { 450 struct sysctlnode node = *rnode; 451 struct adapter *adapter = (struct adapter *)node.sysctl_data; 452 struct ixgbe_hw *hw = &adapter->hw; 453 int error, tmp; 454 static int timeout = 0; 455 u32 mask, arg; 456 457 /* Get the current hardware value */ 458 ixgbe_bypass_mutex_enter(adapter); 459 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp); 460 ixgbe_bypass_mutex_clear(adapter); 461 if (error) 462 return (error); 463 /* 464 * If armed keep the displayed value, 465 * else change the display to zero. 466 */ 467 if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0) 468 timeout = 0; 469 470 node.sysctl_data = &timeout; 471 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 472 if ((error) || (newp == NULL)) 473 return (error); 474 475 arg = 0x1 << BYPASS_WDT_ENABLE_SHIFT; 476 mask = BYPASS_WDT_ENABLE_M | BYPASS_WDT_VALUE_M; 477 switch (timeout) { 478 case 0: /* disables the timer */ 479 arg = BYPASS_PAGE_CTL0; 480 mask = BYPASS_WDT_ENABLE_M; 481 break; 482 case 1: 483 arg |= BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT; 484 break; 485 case 2: 486 arg |= BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT; 487 break; 488 case 3: 489 arg |= BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT; 490 break; 491 case 4: 492 arg |= BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT; 493 break; 494 case 8: 495 arg |= BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT; 496 break; 497 case 16: 498 arg |= BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT; 499 break; 500 case 32: 501 arg |= BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT; 502 break; 503 default: 504 return (EINVAL); 505 } 506 507 /* Set the new watchdog */ 508 ixgbe_bypass_mutex_enter(adapter); 509 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg); 510 ixgbe_bypass_mutex_clear(adapter); 511 512 return (error); 513 } /* ixgbe_bp_wd_set */ 514 515 /************************************************************************ 516 * ixgbe_bp_wd_reset - Reset the Watchdog timer 517 * 518 * To activate this it must be called with any argument. 519 ************************************************************************/ 520 static int 521 ixgbe_bp_wd_reset(SYSCTLFN_ARGS) 522 { 523 struct sysctlnode node = *rnode; 524 struct adapter *adapter = (struct adapter *)node.sysctl_data; 525 struct ixgbe_hw *hw = &adapter->hw; 526 u32 sec, year; 527 int cmd, count = 0, error = 0; 528 int reset_wd = 0; 529 530 node.sysctl_data = &reset_wd; 531 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 532 if ((error) || (newp == NULL)) 533 return (error); 534 535 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET; 536 537 /* Resync the FW time while writing to CTL1 anyway */ 538 ixgbe_get_bypass_time(&year, &sec); 539 540 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID; 541 cmd |= BYPASS_CTL1_OFFTRST; 542 543 ixgbe_bypass_wd_mutex_enter(adapter); 544 error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd); 545 546 /* Read until it matches what we wrote, or we time out */ 547 do { 548 if (count++ > 10) { 549 error = IXGBE_BYPASS_FW_WRITE_FAILURE; 550 break; 551 } 552 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd); 553 if (error != 0) { 554 error = IXGBE_ERR_INVALID_ARGUMENT; 555 break; 556 } 557 } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd)); 558 559 reset_wd = 0; 560 ixgbe_bypass_wd_mutex_clear(adapter); 561 return (error); 562 } /* ixgbe_bp_wd_reset */ 563 564 /************************************************************************ 565 * ixgbe_bp_log - Display the bypass log 566 * 567 * You must pass a non-zero arg to sysctl 568 ************************************************************************/ 569 static int 570 ixgbe_bp_log(SYSCTLFN_ARGS) 571 { 572 struct sysctlnode node = *rnode; 573 struct adapter *adapter = (struct adapter *)node.sysctl_data; 574 struct ixgbe_hw *hw = &adapter->hw; 575 u32 cmd, base, head; 576 u32 log_off, count = 0; 577 static int status = 0; 578 u8 data; 579 struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS]; 580 int i, error = 0; 581 582 node.sysctl_data = &status; 583 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 584 if ((error) || (newp == NULL)) 585 return (error); 586 587 /* Keep the log display single-threaded */ 588 while (atomic_cas_uint(&adapter->bypass.log, 0, 1) == 0) 589 usec_delay(3000); 590 591 ixgbe_bypass_mutex_enter(adapter); 592 593 /* Find Current head of the log eeprom offset */ 594 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 595 cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 596 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 597 if (error) 598 goto unlock_err; 599 600 /* wait for the write to stick */ 601 msec_delay(100); 602 603 /* Now read the results */ 604 cmd &= ~BYPASS_WE; 605 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 606 if (error) 607 goto unlock_err; 608 609 ixgbe_bypass_mutex_clear(adapter); 610 611 base = status & BYPASS_CTL2_DATA_M; 612 head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; 613 614 /* address of the first log */ 615 log_off = base + (head * 5); 616 617 /* extract all the log entries */ 618 while (count < BYPASS_MAX_LOGS) { 619 eeprom[count].logs = 0; 620 eeprom[count].actions = 0; 621 622 /* Log 5 bytes store in on u32 and a u8 */ 623 for (i = 0; i < 4; i++) { 624 ixgbe_bypass_mutex_enter(adapter); 625 error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, 626 &data); 627 ixgbe_bypass_mutex_clear(adapter); 628 if (error) 629 return (EINVAL); 630 eeprom[count].logs += data << (8 * i); 631 } 632 633 ixgbe_bypass_mutex_enter(adapter); 634 error = hw->mac.ops.bypass_rd_eep(hw, 635 log_off + i, &eeprom[count].actions); 636 ixgbe_bypass_mutex_clear(adapter); 637 if (error) 638 return (EINVAL); 639 640 /* Quit if not a unread log */ 641 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) 642 break; 643 /* 644 * Log looks good so store the address where it's 645 * Unread Log bit is so we can clear it after safely 646 * pulling out all of the log data. 647 */ 648 eeprom[count].clear_off = log_off; 649 650 count++; 651 head = head ? head - 1 : BYPASS_MAX_LOGS; 652 log_off = base + (head * 5); 653 } 654 655 /* reverse order (oldest first) for output */ 656 while (count--) { 657 int year; 658 u32 mon, days, hours, min, sec; 659 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; 660 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> 661 BYPASS_LOG_EVENT_SHIFT; 662 u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; 663 u16 day_mon[2][13] = { 664 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 665 {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 666 }; 667 const char *event_str[] = {"unknown", "main on", "aux on", 668 "main off", "aux off", "WDT", "user" }; 669 const char *action_str[] = {"ignore", "normal", "bypass", 670 "isolate",}; 671 672 /* verify vaild data 1 - 6 */ 673 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) 674 event = 0; 675 676 /* 677 * time is in sec's this year, so convert to something 678 * printable. 679 */ 680 ixgbe_get_bypass_time(&year, &sec); 681 days = time / SEC_PER_DAY; 682 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) 683 continue; 684 mon = i + 1; /* display month as 1-12 */ 685 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); 686 days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ 687 time %= SEC_PER_DAY; 688 hours = time / (60 * 60); 689 time %= (60 * 60); 690 min = time / 60; 691 sec = time % 60; 692 device_printf(adapter->dev, 693 "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", 694 mon, days, hours, min, sec, event_str[event], 695 action_str[action]); 696 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; 697 cmd |= ((eeprom[count].clear_off + 3) 698 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 699 cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); 700 701 ixgbe_bypass_mutex_enter(adapter); 702 703 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 704 705 /* wait for the write to stick */ 706 msec_delay(100); 707 708 ixgbe_bypass_mutex_clear(adapter); 709 710 if (error) 711 return (EINVAL); 712 } 713 714 status = 0; /* reset */ 715 /* Another log command can now run */ 716 while (atomic_cas_uint(&adapter->bypass.log, 1, 0) == 0) 717 usec_delay(3000); 718 return (error); 719 720 unlock_err: 721 ixgbe_bypass_mutex_clear(adapter); 722 status = 0; /* reset */ 723 while (atomic_cas_uint(&adapter->bypass.log, 1, 0) == 0) 724 usec_delay(3000); 725 return (EINVAL); 726 } /* ixgbe_bp_log */ 727 728 /************************************************************************ 729 * ixgbe_bypass_init - Set up infrastructure for the bypass feature 730 * 731 * Do time and sysctl initialization here. This feature is 732 * only enabled for the first port of a bypass adapter. 733 ************************************************************************/ 734 void 735 ixgbe_bypass_init(struct adapter *adapter) 736 { 737 struct ixgbe_hw *hw = &adapter->hw; 738 device_t dev = adapter->dev; 739 struct sysctllog **log; 740 const struct sysctlnode *rnode, *cnode; 741 u32 mask, value, sec, year; 742 743 if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS)) 744 return; 745 746 /* First set up time for the hardware */ 747 ixgbe_get_bypass_time(&year, &sec); 748 749 mask = BYPASS_CTL1_TIME_M 750 | BYPASS_CTL1_VALID_M 751 | BYPASS_CTL1_OFFTRST_M; 752 753 value = (sec & BYPASS_CTL1_TIME_M) 754 | BYPASS_CTL1_VALID 755 | BYPASS_CTL1_OFFTRST; 756 757 ixgbe_bypass_mutex_enter(adapter); 758 hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); 759 ixgbe_bypass_mutex_clear(adapter); 760 761 /* Now set up the SYSCTL infrastructure */ 762 log = &adapter->sysctllog; 763 if ((rnode = ixgbe_sysctl_instance(adapter)) == NULL) { 764 aprint_error_dev(dev, "could not create sysctl root\n"); 765 return; 766 } 767 768 /* 769 * The log routine is kept separate from the other 770 * children so a general display command like: 771 * `sysctl dev.ix.0.bypass` will not show the log. 772 */ 773 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 774 CTLTYPE_INT, "bypass_log", SYSCTL_DESCR("Bypass Log"), 775 ixgbe_bp_log, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 776 777 /* All other setting are hung from the 'bypass' node */ 778 sysctl_createv(log, 0, &rnode, &rnode, 0, 779 CTLTYPE_NODE, "bypass", SYSCTL_DESCR("Bypass"), 780 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 781 782 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READONLY, 783 CTLTYPE_INT, "version", SYSCTL_DESCR("Bypass Version"), 784 ixgbe_bp_version, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 785 786 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 787 CTLTYPE_INT, "state", SYSCTL_DESCR("Bypass State"), 788 ixgbe_bp_set_state, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 789 790 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 791 CTLTYPE_INT, "timeout", SYSCTL_DESCR("Bypass Timeout"), 792 ixgbe_bp_timeout, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 793 794 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 795 CTLTYPE_INT, "main_on", SYSCTL_DESCR("Bypass Main On"), 796 ixgbe_bp_main_on, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 797 798 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 799 CTLTYPE_INT, "main_off", SYSCTL_DESCR("Bypass Main Off"), 800 ixgbe_bp_main_off, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 801 802 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 803 CTLTYPE_INT, "aux_on", SYSCTL_DESCR("Bypass Aux On"), 804 ixgbe_bp_aux_on, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 805 806 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 807 CTLTYPE_INT, "aux_off", SYSCTL_DESCR("Bypass Aux Off"), 808 ixgbe_bp_aux_off, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 809 810 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 811 CTLTYPE_INT, "wd_set", SYSCTL_DESCR("Set BP Watchdog"), 812 ixgbe_bp_wd_set, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 813 814 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 815 CTLTYPE_INT, "wd_reset", SYSCTL_DESCR("Bypass WD Reset"), 816 ixgbe_bp_wd_reset, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 817 818 adapter->feat_en |= IXGBE_FEATURE_BYPASS; 819 } /* ixgbe_bypass_init */ 820 821