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