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