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