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 if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) { 534 error = IXGBE_ERR_INVALID_ARGUMENT; 535 break; 536 } 537 } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd)); 538 539 reset_wd = 0; 540 ixgbe_bypass_wd_mutex_clear(sc); 541 return (error); 542 } /* ixgbe_bp_wd_reset */ 543 544 /************************************************************************ 545 * ixgbe_bp_log - Display the bypass log 546 * 547 * You must pass a non-zero arg to sysctl 548 ************************************************************************/ 549 static int 550 ixgbe_bp_log(SYSCTL_HANDLER_ARGS) 551 { 552 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1; 553 struct ixgbe_hw *hw = &sc->hw; 554 u32 cmd, base, head; 555 u32 log_off, count = 0; 556 static int status = 0; 557 u8 data; 558 struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS]; 559 int i, error = 0; 560 561 error = sysctl_handle_int(oidp, &status, 0, req); 562 if ((error) || (req->newptr == NULL)) 563 return (error); 564 565 /* Keep the log display single-threaded */ 566 while (atomic_cmpset_int(&sc->bypass.log, 0, 1) == 0) 567 usec_delay(3000); 568 569 ixgbe_bypass_mutex_enter(sc); 570 571 /* Find Current head of the log eeprom offset */ 572 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 573 cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 574 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 575 if (error) 576 goto unlock_err; 577 578 /* wait for the write to stick */ 579 msec_delay(100); 580 581 /* Now read the results */ 582 cmd &= ~BYPASS_WE; 583 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 584 if (error) 585 goto unlock_err; 586 587 ixgbe_bypass_mutex_clear(sc); 588 589 base = status & BYPASS_CTL2_DATA_M; 590 head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; 591 592 /* address of the first log */ 593 log_off = base + (head * 5); 594 595 /* extract all the log entries */ 596 while (count < BYPASS_MAX_LOGS) { 597 eeprom[count].logs = 0; 598 eeprom[count].actions = 0; 599 600 /* Log 5 bytes store in on u32 and a u8 */ 601 for (i = 0; i < 4; i++) { 602 ixgbe_bypass_mutex_enter(sc); 603 error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, 604 &data); 605 ixgbe_bypass_mutex_clear(sc); 606 if (error) 607 return (EINVAL); 608 eeprom[count].logs += data << (8 * i); 609 } 610 611 ixgbe_bypass_mutex_enter(sc); 612 error = hw->mac.ops.bypass_rd_eep(hw, 613 log_off + i, &eeprom[count].actions); 614 ixgbe_bypass_mutex_clear(sc); 615 if (error) 616 return (EINVAL); 617 618 /* Quit if not a unread log */ 619 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) 620 break; 621 /* 622 * Log looks good so store the address where it's 623 * Unread Log bit is so we can clear it after safely 624 * pulling out all of the log data. 625 */ 626 eeprom[count].clear_off = log_off; 627 628 count++; 629 head = head ? head - 1 : BYPASS_MAX_LOGS; 630 log_off = base + (head * 5); 631 } 632 633 /* reverse order (oldest first) for output */ 634 while (count--) { 635 int year; 636 u32 mon, days, hours, min, sec; 637 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; 638 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> 639 BYPASS_LOG_EVENT_SHIFT; 640 u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; 641 u16 day_mon[2][13] = { 642 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 643 {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 644 }; 645 char *event_str[] = {"unknown", "main on", "aux on", 646 "main off", "aux off", "WDT", "user" }; 647 char *action_str[] = {"ignore", "normal", "bypass", "isolate",}; 648 649 /* verify vaild data 1 - 6 */ 650 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) 651 event = 0; 652 653 /* 654 * time is in sec's this year, so convert to something 655 * printable. 656 */ 657 ixgbe_get_bypass_time(&year, &sec); 658 days = time / SEC_PER_DAY; 659 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) 660 continue; 661 mon = i + 1; /* display month as 1-12 */ 662 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); 663 days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ 664 time %= SEC_PER_DAY; 665 hours = time / (60 * 60); 666 time %= (60 * 60); 667 min = time / 60; 668 sec = time % 60; 669 device_printf(sc->dev, 670 "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", 671 mon, days, hours, min, sec, event_str[event], 672 action_str[action]); 673 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; 674 cmd |= ((eeprom[count].clear_off + 3) 675 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 676 cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); 677 678 ixgbe_bypass_mutex_enter(sc); 679 680 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 681 682 /* wait for the write to stick */ 683 msec_delay(100); 684 685 ixgbe_bypass_mutex_clear(sc); 686 687 if (error) 688 return (EINVAL); 689 } 690 691 status = 0; /* reset */ 692 /* Another log command can now run */ 693 while (atomic_cmpset_int(&sc->bypass.log, 1, 0) == 0) 694 usec_delay(3000); 695 return (error); 696 697 unlock_err: 698 ixgbe_bypass_mutex_clear(sc); 699 status = 0; /* reset */ 700 while (atomic_cmpset_int(&sc->bypass.log, 1, 0) == 0) 701 usec_delay(3000); 702 return (EINVAL); 703 } /* ixgbe_bp_log */ 704 705 /************************************************************************ 706 * ixgbe_bypass_init - Set up infrastructure for the bypass feature 707 * 708 * Do time and sysctl initialization here. This feature is 709 * only enabled for the first port of a bypass adapter. 710 ************************************************************************/ 711 void 712 ixgbe_bypass_init(struct ixgbe_softc *sc) 713 { 714 struct ixgbe_hw *hw = &sc->hw; 715 device_t dev = sc->dev; 716 struct sysctl_oid *bp_node; 717 struct sysctl_oid_list *bp_list; 718 u32 mask, value, sec, year; 719 720 if (!(sc->feat_cap & IXGBE_FEATURE_BYPASS)) 721 return; 722 723 /* First set up time for the hardware */ 724 ixgbe_get_bypass_time(&year, &sec); 725 726 mask = BYPASS_CTL1_TIME_M 727 | BYPASS_CTL1_VALID_M 728 | BYPASS_CTL1_OFFTRST_M; 729 730 value = (sec & BYPASS_CTL1_TIME_M) 731 | BYPASS_CTL1_VALID 732 | BYPASS_CTL1_OFFTRST; 733 734 ixgbe_bypass_mutex_enter(sc); 735 hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); 736 ixgbe_bypass_mutex_clear(sc); 737 738 /* Now set up the SYSCTL infrastructure */ 739 740 /* 741 * The log routine is kept separate from the other 742 * children so a general display command like: 743 * `sysctl dev.ix.0.bypass` will not show the log. 744 */ 745 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 746 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 747 OID_AUTO, "bypass_log", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 748 sc, 0, ixgbe_bp_log, "I", "Bypass Log"); 749 750 /* All other setting are hung from the 'bypass' node */ 751 bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 752 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 753 OID_AUTO, "bypass", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Bypass"); 754 755 bp_list = SYSCTL_CHILDREN(bp_node); 756 757 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 758 OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD, 759 sc, 0, ixgbe_bp_version, "I", "Bypass Version"); 760 761 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 762 OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW, 763 sc, 0, ixgbe_bp_set_state, "I", "Bypass State"); 764 765 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 766 OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW, 767 sc, 0, ixgbe_bp_timeout, "I", "Bypass Timeout"); 768 769 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 770 OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW, 771 sc, 0, ixgbe_bp_main_on, "I", "Bypass Main On"); 772 773 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 774 OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW, 775 sc, 0, ixgbe_bp_main_off, "I", "Bypass Main Off"); 776 777 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 778 OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW, 779 sc, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On"); 780 781 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 782 OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW, 783 sc, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off"); 784 785 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 786 OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW, 787 sc, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog"); 788 789 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 790 OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR, 791 sc, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset"); 792 793 sc->feat_en |= IXGBE_FEATURE_BYPASS; 794 } /* ixgbe_bypass_init */ 795 796