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 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) 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) || (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 = BYPASS_PAGE_CTL0; 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 mask = BYPASS_WDT_ENABLE_M; 476 switch (timeout) { 477 case 0: /* disables the timer */ 478 break; 479 case 1: 480 arg = BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT; 481 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 482 mask |= BYPASS_WDT_VALUE_M; 483 break; 484 case 2: 485 arg = BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT; 486 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 487 mask |= BYPASS_WDT_VALUE_M; 488 break; 489 case 3: 490 arg = BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT; 491 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 492 mask |= BYPASS_WDT_VALUE_M; 493 break; 494 case 4: 495 arg = BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT; 496 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 497 mask |= BYPASS_WDT_VALUE_M; 498 break; 499 case 8: 500 arg = BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT; 501 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 502 mask |= BYPASS_WDT_VALUE_M; 503 break; 504 case 16: 505 arg = BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT; 506 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 507 mask |= BYPASS_WDT_VALUE_M; 508 break; 509 case 32: 510 arg = BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT; 511 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 512 mask |= BYPASS_WDT_VALUE_M; 513 break; 514 default: 515 return (EINVAL); 516 } 517 /* Set the new watchdog */ 518 ixgbe_bypass_mutex_enter(adapter); 519 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg); 520 ixgbe_bypass_mutex_clear(adapter); 521 522 return (error); 523 } /* ixgbe_bp_wd_set */ 524 525 /************************************************************************ 526 * ixgbe_bp_wd_reset - Reset the Watchdog timer 527 * 528 * To activate this it must be called with any argument. 529 ************************************************************************/ 530 static int 531 ixgbe_bp_wd_reset(SYSCTLFN_ARGS) 532 { 533 struct sysctlnode node = *rnode; 534 struct adapter *adapter = (struct adapter *)node.sysctl_data; 535 struct ixgbe_hw *hw = &adapter->hw; 536 u32 sec, year; 537 int cmd, count = 0, error = 0; 538 int reset_wd = 0; 539 540 node.sysctl_data = &reset_wd; 541 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 542 if ((error) || (newp == NULL)) 543 return (error); 544 545 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET; 546 547 /* Resync the FW time while writing to CTL1 anyway */ 548 ixgbe_get_bypass_time(&year, &sec); 549 550 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID; 551 cmd |= BYPASS_CTL1_OFFTRST; 552 553 ixgbe_bypass_wd_mutex_enter(adapter); 554 error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd); 555 556 /* Read until it matches what we wrote, or we time out */ 557 do { 558 if (count++ > 10) { 559 error = IXGBE_BYPASS_FW_WRITE_FAILURE; 560 break; 561 } 562 if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) { 563 error = IXGBE_ERR_INVALID_ARGUMENT; 564 break; 565 } 566 } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd)); 567 568 reset_wd = 0; 569 ixgbe_bypass_wd_mutex_clear(adapter); 570 return (error); 571 } /* ixgbe_bp_wd_reset */ 572 573 /************************************************************************ 574 * ixgbe_bp_log - Display the bypass log 575 * 576 * You must pass a non-zero arg to sysctl 577 ************************************************************************/ 578 static int 579 ixgbe_bp_log(SYSCTLFN_ARGS) 580 { 581 struct sysctlnode node = *rnode; 582 struct adapter *adapter = (struct adapter *)node.sysctl_data; 583 struct ixgbe_hw *hw = &adapter->hw; 584 u32 cmd, base, head; 585 u32 log_off, count = 0; 586 static int status = 0; 587 u8 data; 588 struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS]; 589 int i, error = 0; 590 591 node.sysctl_data = &status; 592 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 593 if ((error) || (newp == NULL)) 594 return (error); 595 596 /* Keep the log display single-threaded */ 597 while (atomic_cas_uint(&adapter->bypass.log, 0, 1) == 0) 598 usec_delay(3000); 599 600 ixgbe_bypass_mutex_enter(adapter); 601 602 /* Find Current head of the log eeprom offset */ 603 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 604 cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 605 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 606 if (error) 607 goto unlock_err; 608 609 /* wait for the write to stick */ 610 msec_delay(100); 611 612 /* Now read the results */ 613 cmd &= ~BYPASS_WE; 614 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 615 if (error) 616 goto unlock_err; 617 618 ixgbe_bypass_mutex_clear(adapter); 619 620 base = status & BYPASS_CTL2_DATA_M; 621 head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; 622 623 /* address of the first log */ 624 log_off = base + (head * 5); 625 626 /* extract all the log entries */ 627 while (count < BYPASS_MAX_LOGS) { 628 eeprom[count].logs = 0; 629 eeprom[count].actions = 0; 630 631 /* Log 5 bytes store in on u32 and a u8 */ 632 for (i = 0; i < 4; i++) { 633 ixgbe_bypass_mutex_enter(adapter); 634 error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, 635 &data); 636 ixgbe_bypass_mutex_clear(adapter); 637 if (error) 638 return (-EINVAL); 639 eeprom[count].logs += data << (8 * i); 640 } 641 642 ixgbe_bypass_mutex_enter(adapter); 643 error = hw->mac.ops.bypass_rd_eep(hw, 644 log_off + i, &eeprom[count].actions); 645 ixgbe_bypass_mutex_clear(adapter); 646 if (error) 647 return (-EINVAL); 648 649 /* Quit if not a unread log */ 650 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) 651 break; 652 /* 653 * Log looks good so store the address where it's 654 * Unread Log bit is so we can clear it after safely 655 * pulling out all of the log data. 656 */ 657 eeprom[count].clear_off = log_off; 658 659 count++; 660 head = head ? head - 1 : BYPASS_MAX_LOGS; 661 log_off = base + (head * 5); 662 } 663 664 /* reverse order (oldest first) for output */ 665 while (count--) { 666 int year; 667 u32 mon, days, hours, min, sec; 668 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; 669 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> 670 BYPASS_LOG_EVENT_SHIFT; 671 u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; 672 u16 day_mon[2][13] = { 673 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 674 {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 675 }; 676 const char *event_str[] = {"unknown", "main on", "aux on", 677 "main off", "aux off", "WDT", "user" }; 678 const char *action_str[] = {"ignore", "normal", "bypass", 679 "isolate",}; 680 681 /* verify vaild data 1 - 6 */ 682 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) 683 event = 0; 684 685 /* 686 * time is in sec's this year, so convert to something 687 * printable. 688 */ 689 ixgbe_get_bypass_time(&year, &sec); 690 days = time / SEC_PER_DAY; 691 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) 692 continue; 693 mon = i + 1; /* display month as 1-12 */ 694 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); 695 days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ 696 time %= SEC_PER_DAY; 697 hours = time / (60 * 60); 698 time %= (60 * 60); 699 min = time / 60; 700 sec = time % 60; 701 device_printf(adapter->dev, 702 "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", 703 mon, days, hours, min, sec, event_str[event], 704 action_str[action]); 705 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; 706 cmd |= ((eeprom[count].clear_off + 3) 707 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 708 cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); 709 710 ixgbe_bypass_mutex_enter(adapter); 711 712 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 713 714 /* wait for the write to stick */ 715 msec_delay(100); 716 717 ixgbe_bypass_mutex_clear(adapter); 718 719 if (error) 720 return (-EINVAL); 721 } 722 723 status = 0; /* reset */ 724 /* Another log command can now run */ 725 while (atomic_cas_uint(&adapter->bypass.log, 1, 0) == 0) 726 usec_delay(3000); 727 return(error); 728 729 unlock_err: 730 ixgbe_bypass_mutex_clear(adapter); 731 status = 0; /* reset */ 732 while (atomic_cas_uint(&adapter->bypass.log, 1, 0) == 0) 733 usec_delay(3000); 734 return (-EINVAL); 735 } /* ixgbe_bp_log */ 736 737 /************************************************************************ 738 * ixgbe_bypass_init - Set up infrastructure for the bypass feature 739 * 740 * Do time and sysctl initialization here. This feature is 741 * only enabled for the first port of a bypass adapter. 742 ************************************************************************/ 743 void 744 ixgbe_bypass_init(struct adapter *adapter) 745 { 746 struct ixgbe_hw *hw = &adapter->hw; 747 device_t dev = adapter->dev; 748 u32 mask, value, sec, year; 749 struct sysctllog **log; 750 const struct sysctlnode *rnode, *cnode; 751 752 if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS)) 753 return; 754 755 /* First set up time for the hardware */ 756 ixgbe_get_bypass_time(&year, &sec); 757 758 mask = BYPASS_CTL1_TIME_M 759 | BYPASS_CTL1_VALID_M 760 | BYPASS_CTL1_OFFTRST_M; 761 762 value = (sec & BYPASS_CTL1_TIME_M) 763 | BYPASS_CTL1_VALID 764 | BYPASS_CTL1_OFFTRST; 765 766 ixgbe_bypass_mutex_enter(adapter); 767 hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); 768 ixgbe_bypass_mutex_clear(adapter); 769 770 /* Now set up the SYSCTL infrastructure */ 771 log = &adapter->sysctllog; 772 if ((rnode = ixgbe_sysctl_instance(adapter)) == NULL) { 773 aprint_error_dev(dev, "could not create sysctl root\n"); 774 return; 775 } 776 777 /* 778 * The log routine is kept separate from the other 779 * children so a general display command like: 780 * `sysctl dev.ix.0.bypass` will not show the log. 781 */ 782 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 783 CTLTYPE_INT, "bypass_log", SYSCTL_DESCR("Bypass Log"), 784 ixgbe_bp_log, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 785 786 /* All other setting are hung from the 'bypass' node */ 787 sysctl_createv(log, 0, &rnode, &rnode, 0, 788 CTLTYPE_NODE, "bypass", SYSCTL_DESCR("Bypass"), 789 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 790 791 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READONLY, 792 CTLTYPE_INT, "version", SYSCTL_DESCR("Bypass Version"), 793 ixgbe_bp_version, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 794 795 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 796 CTLTYPE_INT, "state", SYSCTL_DESCR("Bypass State"), 797 ixgbe_bp_set_state, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 798 799 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 800 CTLTYPE_INT, "timeout", SYSCTL_DESCR("Bypass Timeout"), 801 ixgbe_bp_timeout, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 802 803 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 804 CTLTYPE_INT, "main_on", SYSCTL_DESCR("Bypass Main On"), 805 ixgbe_bp_main_on, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 806 807 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 808 CTLTYPE_INT, "main_off", SYSCTL_DESCR("Bypass Main Off"), 809 ixgbe_bp_main_off, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 810 811 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 812 CTLTYPE_INT, "aux_on", SYSCTL_DESCR("Bypass Aux On"), 813 ixgbe_bp_aux_on, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 814 815 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 816 CTLTYPE_INT, "aux_off", SYSCTL_DESCR("Bypass Aux Off"), 817 ixgbe_bp_aux_off, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 818 819 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 820 CTLTYPE_INT, "wd_set", SYSCTL_DESCR("Set BP Watchdog"), 821 ixgbe_bp_wd_set, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 822 823 sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE, 824 CTLTYPE_INT, "wd_reset", SYSCTL_DESCR("Bypass WD Reset"), 825 ixgbe_bp_wd_reset, 0, (void *)adapter, 0, CTL_CREATE, CTL_EOL); 826 827 adapter->feat_en |= IXGBE_FEATURE_BYPASS; 828 829 return; 830 } /* ixgbe_bypass_init */ 831 832