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