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