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 320688 2017-07-05 17:27:03Z 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 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 138 return (error); 139 err: 140 ixgbe_bypass_mutex_clear(adapter); 141 return (error); 142 143 } /* ixgbe_bp_version */ 144 145 /************************************************************************ 146 * ixgbe_bp_set_state 147 * 148 * Show/Set the Bypass State: 149 * 1 = NORMAL 150 * 2 = BYPASS 151 * 3 = ISOLATE 152 * 153 * With no argument the state is displayed, 154 * passing a value will set it. 155 ************************************************************************/ 156 static int 157 ixgbe_bp_set_state(SYSCTLFN_ARGS) 158 { 159 struct sysctlnode node = *rnode; 160 struct adapter *adapter = (struct adapter *)node.sysctl_data; 161 struct ixgbe_hw *hw = &adapter->hw; 162 int error = 0; 163 static int state = 0; 164 165 /* Get the current state */ 166 ixgbe_bypass_mutex_enter(adapter); 167 error = hw->mac.ops.bypass_rw(hw, 168 BYPASS_PAGE_CTL0, &state); 169 ixgbe_bypass_mutex_clear(adapter); 170 if (error) 171 return (error); 172 state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3; 173 174 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 175 if ((error) || (newp == NULL)) 176 return (error); 177 178 /* Sanity check new state */ 179 switch (state) { 180 case BYPASS_NORM: 181 case BYPASS_BYPASS: 182 case BYPASS_ISOLATE: 183 break; 184 default: 185 return (EINVAL); 186 } 187 ixgbe_bypass_mutex_enter(adapter); 188 if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 189 BYPASS_MODE_OFF_M, state) != 0)) 190 goto out; 191 /* Set AUTO back on so FW can receive events */ 192 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 193 BYPASS_MODE_OFF_M, BYPASS_AUTO); 194 out: 195 ixgbe_bypass_mutex_clear(adapter); 196 usec_delay(6000); 197 return (error); 198 } /* ixgbe_bp_set_state */ 199 200 /************************************************************************ 201 * The following routines control the operational 202 * "rules" of the feature, what behavior will occur 203 * when particular events occur. 204 * Values are: 205 * 0 - no change for the event (NOP) 206 * 1 - go to Normal operation 207 * 2 - go to Bypass operation 208 * 3 - go to Isolate operation 209 * Calling the entry with no argument just displays 210 * the current rule setting. 211 ************************************************************************/ 212 213 /************************************************************************ 214 * ixgbe_bp_timeout 215 * 216 * This is to set the Rule for the watchdog, 217 * not the actual watchdog timeout value. 218 ************************************************************************/ 219 static int 220 ixgbe_bp_timeout(SYSCTLFN_ARGS) 221 { 222 struct sysctlnode node = *rnode; 223 struct adapter *adapter = (struct adapter *)node.sysctl_data; 224 struct ixgbe_hw *hw = &adapter->hw; 225 int error = 0; 226 static int timeout = 0; 227 228 /* Get the current value */ 229 ixgbe_bypass_mutex_enter(adapter); 230 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout); 231 ixgbe_bypass_mutex_clear(adapter); 232 if (error) 233 return (error); 234 timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3; 235 236 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 237 if ((error) || (newp == NULL)) 238 return (error); 239 240 /* Sanity check on the setting */ 241 switch (timeout) { 242 case BYPASS_NOP: 243 case BYPASS_NORM: 244 case BYPASS_BYPASS: 245 case BYPASS_ISOLATE: 246 break; 247 default: 248 return (EINVAL); 249 } 250 251 /* Set the new state */ 252 ixgbe_bypass_mutex_enter(adapter); 253 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 254 BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT); 255 ixgbe_bypass_mutex_clear(adapter); 256 usec_delay(6000); 257 return (error); 258 } /* ixgbe_bp_timeout */ 259 260 /************************************************************************ 261 * ixgbe_bp_main_on 262 ************************************************************************/ 263 static int 264 ixgbe_bp_main_on(SYSCTLFN_ARGS) 265 { 266 struct sysctlnode node = *rnode; 267 struct adapter *adapter = (struct adapter *)node.sysctl_data; 268 struct ixgbe_hw *hw = &adapter->hw; 269 int error = 0; 270 static int main_on = 0; 271 272 ixgbe_bypass_mutex_enter(adapter); 273 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on); 274 main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3; 275 ixgbe_bypass_mutex_clear(adapter); 276 if (error) 277 return (error); 278 279 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 280 if ((error) || (newp == NULL)) 281 return (error); 282 283 /* Sanity check on the setting */ 284 switch (main_on) { 285 case BYPASS_NOP: 286 case BYPASS_NORM: 287 case BYPASS_BYPASS: 288 case BYPASS_ISOLATE: 289 break; 290 default: 291 return (EINVAL); 292 } 293 294 /* Set the new state */ 295 ixgbe_bypass_mutex_enter(adapter); 296 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 297 BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT); 298 ixgbe_bypass_mutex_clear(adapter); 299 usec_delay(6000); 300 return (error); 301 } /* ixgbe_bp_main_on */ 302 303 /************************************************************************ 304 * ixgbe_bp_main_off 305 ************************************************************************/ 306 static int 307 ixgbe_bp_main_off(SYSCTLFN_ARGS) 308 { 309 struct sysctlnode node = *rnode; 310 struct adapter *adapter = (struct adapter *)node.sysctl_data; 311 struct ixgbe_hw *hw = &adapter->hw; 312 int error = 0; 313 static int main_off = 0; 314 315 ixgbe_bypass_mutex_enter(adapter); 316 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off); 317 ixgbe_bypass_mutex_clear(adapter); 318 if (error) 319 return (error); 320 main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3; 321 322 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 323 if ((error) || (newp == NULL)) 324 return (error); 325 326 /* Sanity check on the setting */ 327 switch (main_off) { 328 case BYPASS_NOP: 329 case BYPASS_NORM: 330 case BYPASS_BYPASS: 331 case BYPASS_ISOLATE: 332 break; 333 default: 334 return (EINVAL); 335 } 336 337 /* Set the new state */ 338 ixgbe_bypass_mutex_enter(adapter); 339 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 340 BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT); 341 ixgbe_bypass_mutex_clear(adapter); 342 usec_delay(6000); 343 return (error); 344 } /* ixgbe_bp_main_off */ 345 346 /************************************************************************ 347 * ixgbe_bp_aux_on 348 ************************************************************************/ 349 static int 350 ixgbe_bp_aux_on(SYSCTLFN_ARGS) 351 { 352 struct sysctlnode node = *rnode; 353 struct adapter *adapter = (struct adapter *)node.sysctl_data; 354 struct ixgbe_hw *hw = &adapter->hw; 355 int error = 0; 356 static int aux_on = 0; 357 358 ixgbe_bypass_mutex_enter(adapter); 359 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on); 360 ixgbe_bypass_mutex_clear(adapter); 361 if (error) 362 return (error); 363 aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3; 364 365 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 366 if ((error) || (newp == NULL)) 367 return (error); 368 369 /* Sanity check on the setting */ 370 switch (aux_on) { 371 case BYPASS_NOP: 372 case BYPASS_NORM: 373 case BYPASS_BYPASS: 374 case BYPASS_ISOLATE: 375 break; 376 default: 377 return (EINVAL); 378 } 379 380 /* Set the new state */ 381 ixgbe_bypass_mutex_enter(adapter); 382 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 383 BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT); 384 ixgbe_bypass_mutex_clear(adapter); 385 usec_delay(6000); 386 return (error); 387 } /* ixgbe_bp_aux_on */ 388 389 /************************************************************************ 390 * ixgbe_bp_aux_off 391 ************************************************************************/ 392 static int 393 ixgbe_bp_aux_off(SYSCTLFN_ARGS) 394 { 395 struct sysctlnode node = *rnode; 396 struct adapter *adapter = (struct adapter *)node.sysctl_data; 397 struct ixgbe_hw *hw = &adapter->hw; 398 int error = 0; 399 static int aux_off = 0; 400 401 ixgbe_bypass_mutex_enter(adapter); 402 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off); 403 ixgbe_bypass_mutex_clear(adapter); 404 if (error) 405 return (error); 406 aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3; 407 408 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 409 if ((error) || (newp == NULL)) 410 return (error); 411 412 /* Sanity check on the setting */ 413 switch (aux_off) { 414 case BYPASS_NOP: 415 case BYPASS_NORM: 416 case BYPASS_BYPASS: 417 case BYPASS_ISOLATE: 418 break; 419 default: 420 return (EINVAL); 421 } 422 423 /* Set the new state */ 424 ixgbe_bypass_mutex_enter(adapter); 425 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 426 BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT); 427 ixgbe_bypass_mutex_clear(adapter); 428 usec_delay(6000); 429 return (error); 430 } /* ixgbe_bp_aux_off */ 431 432 /************************************************************************ 433 * ixgbe_bp_wd_set - Set the Watchdog timer value 434 * 435 * Valid settings are: 436 * - 0 will disable the watchdog 437 * - 1, 2, 3, 4, 8, 16, 32 438 * - anything else is invalid and will be ignored 439 ************************************************************************/ 440 static int 441 ixgbe_bp_wd_set(SYSCTLFN_ARGS) 442 { 443 struct sysctlnode node = *rnode; 444 struct adapter *adapter = (struct adapter *)node.sysctl_data; 445 struct ixgbe_hw *hw = &adapter->hw; 446 int error, tmp; 447 static int timeout = 0; 448 u32 mask, arg = BYPASS_PAGE_CTL0; 449 450 /* Get the current hardware value */ 451 ixgbe_bypass_mutex_enter(adapter); 452 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp); 453 ixgbe_bypass_mutex_clear(adapter); 454 if (error) 455 return (error); 456 /* 457 * If armed keep the displayed value, 458 * else change the display to zero. 459 */ 460 if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0) 461 timeout = 0; 462 463 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 464 if ((error) || (newp == NULL)) 465 return (error); 466 467 mask = BYPASS_WDT_ENABLE_M; 468 switch (timeout) { 469 case 0: /* disables the timer */ 470 break; 471 case 1: 472 arg = BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT; 473 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 474 mask |= BYPASS_WDT_VALUE_M; 475 break; 476 case 2: 477 arg = BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT; 478 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 479 mask |= BYPASS_WDT_VALUE_M; 480 break; 481 case 3: 482 arg = BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT; 483 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 484 mask |= BYPASS_WDT_VALUE_M; 485 break; 486 case 4: 487 arg = BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT; 488 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 489 mask |= BYPASS_WDT_VALUE_M; 490 break; 491 case 8: 492 arg = BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT; 493 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 494 mask |= BYPASS_WDT_VALUE_M; 495 break; 496 case 16: 497 arg = BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT; 498 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 499 mask |= BYPASS_WDT_VALUE_M; 500 break; 501 case 32: 502 arg = BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT; 503 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 504 mask |= BYPASS_WDT_VALUE_M; 505 break; 506 default: 507 return (EINVAL); 508 } 509 /* Set the new watchdog */ 510 ixgbe_bypass_mutex_enter(adapter); 511 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg); 512 ixgbe_bypass_mutex_clear(adapter); 513 514 return (error); 515 } /* ixgbe_bp_wd_set */ 516 517 /************************************************************************ 518 * ixgbe_bp_wd_reset - Reset the Watchdog timer 519 * 520 * To activate this it must be called with any argument. 521 ************************************************************************/ 522 static int 523 ixgbe_bp_wd_reset(SYSCTLFN_ARGS) 524 { 525 struct sysctlnode node = *rnode; 526 struct adapter *adapter = (struct adapter *)node.sysctl_data; 527 struct ixgbe_hw *hw = &adapter->hw; 528 u32 sec, year; 529 int cmd, count = 0, error = 0; 530 int reset_wd = 0; 531 532 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 533 if ((error) || (newp == NULL)) 534 return (error); 535 536 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET; 537 538 /* Resync the FW time while writing to CTL1 anyway */ 539 ixgbe_get_bypass_time(&year, &sec); 540 541 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID; 542 cmd |= BYPASS_CTL1_OFFTRST; 543 544 ixgbe_bypass_wd_mutex_enter(adapter); 545 error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd); 546 547 /* Read until it matches what we wrote, or we time out */ 548 do { 549 if (count++ > 10) { 550 error = IXGBE_BYPASS_FW_WRITE_FAILURE; 551 break; 552 } 553 if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) { 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 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 583 if ((error) || (newp == NULL)) 584 return (error); 585 586 /* Keep the log display single-threaded */ 587 while (atomic_cas_uint(&adapter->bypass.log, 0, 1) == 0) 588 usec_delay(3000); 589 590 ixgbe_bypass_mutex_enter(adapter); 591 592 /* Find Current head of the log eeprom offset */ 593 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 594 cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 595 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 596 if (error) 597 goto unlock_err; 598 599 /* wait for the write to stick */ 600 msec_delay(100); 601 602 /* Now read the results */ 603 cmd &= ~BYPASS_WE; 604 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 605 if (error) 606 goto unlock_err; 607 608 ixgbe_bypass_mutex_clear(adapter); 609 610 base = status & BYPASS_CTL2_DATA_M; 611 head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; 612 613 /* address of the first log */ 614 log_off = base + (head * 5); 615 616 /* extract all the log entries */ 617 while (count < BYPASS_MAX_LOGS) { 618 eeprom[count].logs = 0; 619 eeprom[count].actions = 0; 620 621 /* Log 5 bytes store in on u32 and a u8 */ 622 for (i = 0; i < 4; i++) { 623 ixgbe_bypass_mutex_enter(adapter); 624 error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, 625 &data); 626 ixgbe_bypass_mutex_clear(adapter); 627 if (error) 628 return (-EINVAL); 629 eeprom[count].logs += data << (8 * i); 630 } 631 632 ixgbe_bypass_mutex_enter(adapter); 633 error = hw->mac.ops.bypass_rd_eep(hw, 634 log_off + i, &eeprom[count].actions); 635 ixgbe_bypass_mutex_clear(adapter); 636 if (error) 637 return (-EINVAL); 638 639 /* Quit if not a unread log */ 640 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) 641 break; 642 /* 643 * Log looks good so store the address where it's 644 * Unread Log bit is so we can clear it after safely 645 * pulling out all of the log data. 646 */ 647 eeprom[count].clear_off = log_off; 648 649 count++; 650 head = head ? head - 1 : BYPASS_MAX_LOGS; 651 log_off = base + (head * 5); 652 } 653 654 /* reverse order (oldest first) for output */ 655 while (count--) { 656 int year; 657 u32 mon, days, hours, min, sec; 658 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; 659 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> 660 BYPASS_LOG_EVENT_SHIFT; 661 u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; 662 u16 day_mon[2][13] = { 663 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 664 {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 665 }; 666 const char *event_str[] = {"unknown", "main on", "aux on", 667 "main off", "aux off", "WDT", "user" }; 668 const char *action_str[] = {"ignore", "normal", "bypass", 669 "isolate",}; 670 671 /* verify vaild data 1 - 6 */ 672 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) 673 event = 0; 674 675 /* 676 * time is in sec's this year, so convert to something 677 * printable. 678 */ 679 ixgbe_get_bypass_time(&year, &sec); 680 days = time / SEC_PER_DAY; 681 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) 682 continue; 683 mon = i + 1; /* display month as 1-12 */ 684 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); 685 days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ 686 time %= SEC_PER_DAY; 687 hours = time / (60 * 60); 688 time %= (60 * 60); 689 min = time / 60; 690 sec = time % 60; 691 device_printf(adapter->dev, 692 "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", 693 mon, days, hours, min, sec, event_str[event], 694 action_str[action]); 695 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; 696 cmd |= ((eeprom[count].clear_off + 3) 697 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 698 cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); 699 700 ixgbe_bypass_mutex_enter(adapter); 701 702 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 703 704 /* wait for the write to stick */ 705 msec_delay(100); 706 707 ixgbe_bypass_mutex_clear(adapter); 708 709 if (error) 710 return (-EINVAL); 711 } 712 713 status = 0; /* reset */ 714 /* Another log command can now run */ 715 while (atomic_cas_uint(&adapter->bypass.log, 1, 0) == 0) 716 usec_delay(3000); 717 return(error); 718 719 unlock_err: 720 ixgbe_bypass_mutex_clear(adapter); 721 status = 0; /* reset */ 722 while (atomic_cas_uint(&adapter->bypass.log, 1, 0) == 0) 723 usec_delay(3000); 724 return (-EINVAL); 725 } /* ixgbe_bp_log */ 726 727 /************************************************************************ 728 * ixgbe_bypass_init - Set up infrastructure for the bypass feature 729 * 730 * Do time and sysctl initialization here. This feature is 731 * only enabled for the first port of a bypass adapter. 732 ************************************************************************/ 733 void 734 ixgbe_bypass_init(struct adapter *adapter) 735 { 736 struct ixgbe_hw *hw = &adapter->hw; 737 device_t dev = adapter->dev; 738 u32 mask, value, sec, year; 739 struct sysctllog **log; 740 const struct sysctlnode *rnode, *cnode; 741 742 if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS)) 743 return; 744 745 /* First set up time for the hardware */ 746 ixgbe_get_bypass_time(&year, &sec); 747 748 mask = BYPASS_CTL1_TIME_M 749 | BYPASS_CTL1_VALID_M 750 | BYPASS_CTL1_OFFTRST_M; 751 752 value = (sec & BYPASS_CTL1_TIME_M) 753 | BYPASS_CTL1_VALID 754 | BYPASS_CTL1_OFFTRST; 755 756 ixgbe_bypass_mutex_enter(adapter); 757 hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); 758 ixgbe_bypass_mutex_clear(adapter); 759 760 /* Now set up the SYSCTL infrastructure */ 761 log = &adapter->sysctllog; 762 if ((rnode = adapter->sysctltop) == NULL) { 763 aprint_error_dev(dev, "could not create sysctl root\n"); 764 return; 765 } 766 767 /* 768 * The log routine is kept separate from the other 769 * children so a general display command like: 770 * `sysctl dev.ix.0.bypass` will not show the log. 771 */ 772 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 773 CTLTYPE_INT, "bypass_log", SYSCTL_DESCR("Bypass Log"), 774 ixgbe_bp_log, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 775 776 /* All other setting are hung from the 'bypass' node */ 777 sysctl_createv(log, 0, &rnode, &rnode, 0, 778 CTLTYPE_NODE, "bypass", SYSCTL_DESCR("Bypass"), 779 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 780 781 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READONLY, 782 CTLTYPE_INT, "version", SYSCTL_DESCR("Bypass Version"), 783 ixgbe_bp_version, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 784 785 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 786 CTLTYPE_INT, "state", SYSCTL_DESCR("Bypass State"), 787 ixgbe_bp_set_state, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 788 789 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 790 CTLTYPE_INT, "timeout", SYSCTL_DESCR("Bypass Timeout"), 791 ixgbe_bp_timeout, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 792 793 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 794 CTLTYPE_INT, "main_on", SYSCTL_DESCR("Bypass Main On"), 795 ixgbe_bp_main_on, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 796 797 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 798 CTLTYPE_INT, "main_off", SYSCTL_DESCR("Bypass Main Off"), 799 ixgbe_bp_main_off, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 800 801 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 802 CTLTYPE_INT, "aux_on", SYSCTL_DESCR("Bypass Aux On"), 803 ixgbe_bp_aux_on, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 804 805 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 806 CTLTYPE_INT, "aux_off", SYSCTL_DESCR("Bypass Aux Off"), 807 ixgbe_bp_aux_off, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 808 809 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 810 CTLTYPE_INT, "wd_set", SYSCTL_DESCR("Set BP Watchdog"), 811 ixgbe_bp_wd_set, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 812 813 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 814 CTLTYPE_INT, "wd_reset", SYSCTL_DESCR("Bypass WD Reset"), 815 ixgbe_bp_wd_reset, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 816 817 adapter->feat_en |= IXGBE_FEATURE_BYPASS; 818 819 return; 820 } /* ixgbe_bypass_init */ 821 822