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 adapter *adapter) 47 { 48 while (atomic_cmpset_int(&adapter->bypass.low, 0, 1) == 0) 49 usec_delay(3000); 50 while (atomic_cmpset_int(&adapter->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 adapter *adapter) 60 { 61 while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0) 62 usec_delay(6000); 63 while (atomic_cmpset_int(&adapter->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 adapter *adapter) 75 { 76 while (atomic_cmpset_int(&adapter->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 adapter *adapter) 86 { 87 while (atomic_cmpset_int(&adapter->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 adapter *adapter = (struct adapter *) arg1; 119 struct ixgbe_hw *hw = &adapter->hw; 120 int error = 0; 121 static int version = 0; 122 u32 cmd; 123 124 ixgbe_bypass_mutex_enter(adapter); 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(adapter); 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(adapter); 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 adapter *adapter = (struct adapter *) arg1; 159 struct ixgbe_hw *hw = &adapter->hw; 160 int error = 0; 161 static int state = 0; 162 163 /* Get the current state */ 164 ixgbe_bypass_mutex_enter(adapter); 165 error = hw->mac.ops.bypass_rw(hw, 166 BYPASS_PAGE_CTL0, &state); 167 ixgbe_bypass_mutex_clear(adapter); 168 if (error) 169 return (error); 170 state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3; 171 172 error = sysctl_handle_int(oidp, &state, 0, req); 173 if ((error) || (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(adapter); 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(adapter); 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 adapter *adapter = (struct adapter *) arg1; 221 struct ixgbe_hw *hw = &adapter->hw; 222 int error = 0; 223 static int timeout = 0; 224 225 /* Get the current value */ 226 ixgbe_bypass_mutex_enter(adapter); 227 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout); 228 ixgbe_bypass_mutex_clear(adapter); 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(adapter); 250 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 251 BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT); 252 ixgbe_bypass_mutex_clear(adapter); 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 adapter *adapter = (struct adapter *) arg1; 264 struct ixgbe_hw *hw = &adapter->hw; 265 int error = 0; 266 static int main_on = 0; 267 268 ixgbe_bypass_mutex_enter(adapter); 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(adapter); 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(adapter); 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(adapter); 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 adapter *adapter = (struct adapter *) arg1; 306 struct ixgbe_hw *hw = &adapter->hw; 307 int error = 0; 308 static int main_off = 0; 309 310 ixgbe_bypass_mutex_enter(adapter); 311 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off); 312 ixgbe_bypass_mutex_clear(adapter); 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(adapter); 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(adapter); 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 adapter *adapter = (struct adapter *) arg1; 348 struct ixgbe_hw *hw = &adapter->hw; 349 int error = 0; 350 static int aux_on = 0; 351 352 ixgbe_bypass_mutex_enter(adapter); 353 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on); 354 ixgbe_bypass_mutex_clear(adapter); 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(adapter); 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(adapter); 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 adapter *adapter = (struct adapter *) arg1; 390 struct ixgbe_hw *hw = &adapter->hw; 391 int error = 0; 392 static int aux_off = 0; 393 394 ixgbe_bypass_mutex_enter(adapter); 395 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off); 396 ixgbe_bypass_mutex_clear(adapter); 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(adapter); 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(adapter); 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 adapter *adapter = (struct adapter *) arg1; 437 struct ixgbe_hw *hw = &adapter->hw; 438 int error, tmp; 439 static int timeout = 0; 440 u32 mask, arg = BYPASS_PAGE_CTL0; 441 442 /* Get the current hardware value */ 443 ixgbe_bypass_mutex_enter(adapter); 444 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp); 445 ixgbe_bypass_mutex_clear(adapter); 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 mask = BYPASS_WDT_ENABLE_M; 460 switch (timeout) { 461 case 0: /* disables the timer */ 462 break; 463 case 1: 464 arg = BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT; 465 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 466 mask |= BYPASS_WDT_VALUE_M; 467 break; 468 case 2: 469 arg = BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT; 470 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 471 mask |= BYPASS_WDT_VALUE_M; 472 break; 473 case 3: 474 arg = BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT; 475 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 476 mask |= BYPASS_WDT_VALUE_M; 477 break; 478 case 4: 479 arg = BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT; 480 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 481 mask |= BYPASS_WDT_VALUE_M; 482 break; 483 case 8: 484 arg = BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT; 485 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 486 mask |= BYPASS_WDT_VALUE_M; 487 break; 488 case 16: 489 arg = BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT; 490 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 491 mask |= BYPASS_WDT_VALUE_M; 492 break; 493 case 32: 494 arg = BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT; 495 arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 496 mask |= BYPASS_WDT_VALUE_M; 497 break; 498 default: 499 return (EINVAL); 500 } 501 /* Set the new watchdog */ 502 ixgbe_bypass_mutex_enter(adapter); 503 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg); 504 ixgbe_bypass_mutex_clear(adapter); 505 506 return (error); 507 } /* ixgbe_bp_wd_set */ 508 509 /************************************************************************ 510 * ixgbe_bp_wd_reset - Reset the Watchdog timer 511 * 512 * To activate this it must be called with any argument. 513 ************************************************************************/ 514 static int 515 ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS) 516 { 517 struct adapter *adapter = (struct adapter *) arg1; 518 struct ixgbe_hw *hw = &adapter->hw; 519 u32 sec, year; 520 int cmd, count = 0, error = 0; 521 int reset_wd = 0; 522 523 error = sysctl_handle_int(oidp, &reset_wd, 0, req); 524 if ((error) || (req->newptr == NULL)) 525 return (error); 526 527 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET; 528 529 /* Resync the FW time while writing to CTL1 anyway */ 530 ixgbe_get_bypass_time(&year, &sec); 531 532 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID; 533 cmd |= BYPASS_CTL1_OFFTRST; 534 535 ixgbe_bypass_wd_mutex_enter(adapter); 536 error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd); 537 538 /* Read until it matches what we wrote, or we time out */ 539 do { 540 if (count++ > 10) { 541 error = IXGBE_BYPASS_FW_WRITE_FAILURE; 542 break; 543 } 544 if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) { 545 error = IXGBE_ERR_INVALID_ARGUMENT; 546 break; 547 } 548 } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd)); 549 550 reset_wd = 0; 551 ixgbe_bypass_wd_mutex_clear(adapter); 552 return (error); 553 } /* ixgbe_bp_wd_reset */ 554 555 /************************************************************************ 556 * ixgbe_bp_log - Display the bypass log 557 * 558 * You must pass a non-zero arg to sysctl 559 ************************************************************************/ 560 static int 561 ixgbe_bp_log(SYSCTL_HANDLER_ARGS) 562 { 563 struct adapter *adapter = (struct adapter *) arg1; 564 struct ixgbe_hw *hw = &adapter->hw; 565 u32 cmd, base, head; 566 u32 log_off, count = 0; 567 static int status = 0; 568 u8 data; 569 struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS]; 570 int i, error = 0; 571 572 error = sysctl_handle_int(oidp, &status, 0, req); 573 if ((error) || (req->newptr == NULL)) 574 return (error); 575 576 /* Keep the log display single-threaded */ 577 while (atomic_cmpset_int(&adapter->bypass.log, 0, 1) == 0) 578 usec_delay(3000); 579 580 ixgbe_bypass_mutex_enter(adapter); 581 582 /* Find Current head of the log eeprom offset */ 583 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 584 cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 585 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 586 if (error) 587 goto unlock_err; 588 589 /* wait for the write to stick */ 590 msec_delay(100); 591 592 /* Now read the results */ 593 cmd &= ~BYPASS_WE; 594 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 595 if (error) 596 goto unlock_err; 597 598 ixgbe_bypass_mutex_clear(adapter); 599 600 base = status & BYPASS_CTL2_DATA_M; 601 head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; 602 603 /* address of the first log */ 604 log_off = base + (head * 5); 605 606 /* extract all the log entries */ 607 while (count < BYPASS_MAX_LOGS) { 608 eeprom[count].logs = 0; 609 eeprom[count].actions = 0; 610 611 /* Log 5 bytes store in on u32 and a u8 */ 612 for (i = 0; i < 4; i++) { 613 ixgbe_bypass_mutex_enter(adapter); 614 error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, 615 &data); 616 ixgbe_bypass_mutex_clear(adapter); 617 if (error) 618 return (-EINVAL); 619 eeprom[count].logs += data << (8 * i); 620 } 621 622 ixgbe_bypass_mutex_enter(adapter); 623 error = hw->mac.ops.bypass_rd_eep(hw, 624 log_off + i, &eeprom[count].actions); 625 ixgbe_bypass_mutex_clear(adapter); 626 if (error) 627 return (-EINVAL); 628 629 /* Quit if not a unread log */ 630 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) 631 break; 632 /* 633 * Log looks good so store the address where it's 634 * Unread Log bit is so we can clear it after safely 635 * pulling out all of the log data. 636 */ 637 eeprom[count].clear_off = log_off; 638 639 count++; 640 head = head ? head - 1 : BYPASS_MAX_LOGS; 641 log_off = base + (head * 5); 642 } 643 644 /* reverse order (oldest first) for output */ 645 while (count--) { 646 int year; 647 u32 mon, days, hours, min, sec; 648 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; 649 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> 650 BYPASS_LOG_EVENT_SHIFT; 651 u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; 652 u16 day_mon[2][13] = { 653 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 654 {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 655 }; 656 char *event_str[] = {"unknown", "main on", "aux on", 657 "main off", "aux off", "WDT", "user" }; 658 char *action_str[] = {"ignore", "normal", "bypass", "isolate",}; 659 660 /* verify vaild data 1 - 6 */ 661 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) 662 event = 0; 663 664 /* 665 * time is in sec's this year, so convert to something 666 * printable. 667 */ 668 ixgbe_get_bypass_time(&year, &sec); 669 days = time / SEC_PER_DAY; 670 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) 671 continue; 672 mon = i + 1; /* display month as 1-12 */ 673 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); 674 days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ 675 time %= SEC_PER_DAY; 676 hours = time / (60 * 60); 677 time %= (60 * 60); 678 min = time / 60; 679 sec = time % 60; 680 device_printf(adapter->dev, 681 "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", 682 mon, days, hours, min, sec, event_str[event], 683 action_str[action]); 684 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; 685 cmd |= ((eeprom[count].clear_off + 3) 686 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 687 cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); 688 689 ixgbe_bypass_mutex_enter(adapter); 690 691 error = hw->mac.ops.bypass_rw(hw, cmd, &status); 692 693 /* wait for the write to stick */ 694 msec_delay(100); 695 696 ixgbe_bypass_mutex_clear(adapter); 697 698 if (error) 699 return (-EINVAL); 700 } 701 702 status = 0; /* reset */ 703 /* Another log command can now run */ 704 while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0) 705 usec_delay(3000); 706 return(error); 707 708 unlock_err: 709 ixgbe_bypass_mutex_clear(adapter); 710 status = 0; /* reset */ 711 while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0) 712 usec_delay(3000); 713 return (-EINVAL); 714 } /* ixgbe_bp_log */ 715 716 /************************************************************************ 717 * ixgbe_bypass_init - Set up infrastructure for the bypass feature 718 * 719 * Do time and sysctl initialization here. This feature is 720 * only enabled for the first port of a bypass adapter. 721 ************************************************************************/ 722 void 723 ixgbe_bypass_init(struct adapter *adapter) 724 { 725 struct ixgbe_hw *hw = &adapter->hw; 726 device_t dev = adapter->dev; 727 struct sysctl_oid *bp_node; 728 struct sysctl_oid_list *bp_list; 729 u32 mask, value, sec, year; 730 731 if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS)) 732 return; 733 734 /* First set up time for the hardware */ 735 ixgbe_get_bypass_time(&year, &sec); 736 737 mask = BYPASS_CTL1_TIME_M 738 | BYPASS_CTL1_VALID_M 739 | BYPASS_CTL1_OFFTRST_M; 740 741 value = (sec & BYPASS_CTL1_TIME_M) 742 | BYPASS_CTL1_VALID 743 | BYPASS_CTL1_OFFTRST; 744 745 ixgbe_bypass_mutex_enter(adapter); 746 hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); 747 ixgbe_bypass_mutex_clear(adapter); 748 749 /* Now set up the SYSCTL infrastructure */ 750 751 /* 752 * The log routine is kept separate from the other 753 * children so a general display command like: 754 * `sysctl dev.ix.0.bypass` will not show the log. 755 */ 756 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 757 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 758 OID_AUTO, "bypass_log", CTLTYPE_INT | CTLFLAG_RW, 759 adapter, 0, ixgbe_bp_log, "I", "Bypass Log"); 760 761 /* All other setting are hung from the 'bypass' node */ 762 bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 763 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 764 OID_AUTO, "bypass", CTLFLAG_RD, NULL, "Bypass"); 765 766 bp_list = SYSCTL_CHILDREN(bp_node); 767 768 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 769 OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD, 770 adapter, 0, ixgbe_bp_version, "I", "Bypass Version"); 771 772 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 773 OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW, 774 adapter, 0, ixgbe_bp_set_state, "I", "Bypass State"); 775 776 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 777 OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW, 778 adapter, 0, ixgbe_bp_timeout, "I", "Bypass Timeout"); 779 780 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 781 OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW, 782 adapter, 0, ixgbe_bp_main_on, "I", "Bypass Main On"); 783 784 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 785 OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW, 786 adapter, 0, ixgbe_bp_main_off, "I", "Bypass Main Off"); 787 788 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 789 OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW, 790 adapter, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On"); 791 792 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 793 OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW, 794 adapter, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off"); 795 796 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 797 OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW, 798 adapter, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog"); 799 800 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 801 OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR, 802 adapter, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset"); 803 804 adapter->feat_en |= IXGBE_FEATURE_BYPASS; 805 806 return; 807 } /* ixgbe_bypass_init */ 808 809