xref: /freebsd/sys/dev/ixgbe/if_bypass.c (revision 20b91f0aa52c8415e0bc1a06b8b4b5e2cac47bd2)
18eb6488eSEric Joyner /******************************************************************************
28eb6488eSEric Joyner 
38eb6488eSEric Joyner   Copyright (c) 2001-2017, Intel Corporation
48eb6488eSEric Joyner   All rights reserved.
58eb6488eSEric Joyner 
68eb6488eSEric Joyner   Redistribution and use in source and binary forms, with or without
78eb6488eSEric Joyner   modification, are permitted provided that the following conditions are met:
88eb6488eSEric Joyner 
98eb6488eSEric Joyner    1. Redistributions of source code must retain the above copyright notice,
108eb6488eSEric Joyner       this list of conditions and the following disclaimer.
118eb6488eSEric Joyner 
128eb6488eSEric Joyner    2. Redistributions in binary form must reproduce the above copyright
138eb6488eSEric Joyner       notice, this list of conditions and the following disclaimer in the
148eb6488eSEric Joyner       documentation and/or other materials provided with the distribution.
158eb6488eSEric Joyner 
168eb6488eSEric Joyner    3. Neither the name of the Intel Corporation nor the names of its
178eb6488eSEric Joyner       contributors may be used to endorse or promote products derived from
188eb6488eSEric Joyner       this software without specific prior written permission.
198eb6488eSEric Joyner 
208eb6488eSEric Joyner   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
218eb6488eSEric Joyner   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228eb6488eSEric Joyner   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238eb6488eSEric Joyner   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
248eb6488eSEric Joyner   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258eb6488eSEric Joyner   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268eb6488eSEric Joyner   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278eb6488eSEric Joyner   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288eb6488eSEric Joyner   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298eb6488eSEric Joyner   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308eb6488eSEric Joyner   POSSIBILITY OF SUCH DAMAGE.
318eb6488eSEric Joyner 
328eb6488eSEric Joyner ******************************************************************************/
338eb6488eSEric Joyner /*$FreeBSD$*/
348eb6488eSEric Joyner 
358eb6488eSEric Joyner 
368eb6488eSEric Joyner #include "ixgbe.h"
378eb6488eSEric Joyner 
388eb6488eSEric Joyner /************************************************************************
398eb6488eSEric Joyner  * ixgbe_bypass_mutex_enter
408eb6488eSEric Joyner  *
418eb6488eSEric Joyner  *   Mutex support for the bypass feature. Using a dual lock
428eb6488eSEric Joyner  *   to facilitate a privileged access to the watchdog update
438eb6488eSEric Joyner  *   over other threads.
448eb6488eSEric Joyner  ************************************************************************/
458eb6488eSEric Joyner static void
468eb6488eSEric Joyner ixgbe_bypass_mutex_enter(struct adapter *adapter)
478eb6488eSEric Joyner {
488eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.low, 0, 1) == 0)
498eb6488eSEric Joyner 		usec_delay(3000);
508eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0)
518eb6488eSEric Joyner 		usec_delay(3000);
528eb6488eSEric Joyner 	return;
538eb6488eSEric Joyner } /* ixgbe_bypass_mutex_enter */
548eb6488eSEric Joyner 
558eb6488eSEric Joyner /************************************************************************
568eb6488eSEric Joyner  * ixgbe_bypass_mutex_clear
578eb6488eSEric Joyner  ************************************************************************/
588eb6488eSEric Joyner static void
598eb6488eSEric Joyner ixgbe_bypass_mutex_clear(struct adapter *adapter)
608eb6488eSEric Joyner {
618eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0)
628eb6488eSEric Joyner 		usec_delay(6000);
638eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.low, 1, 0) == 0)
648eb6488eSEric Joyner 		usec_delay(6000);
658eb6488eSEric Joyner 	return;
668eb6488eSEric Joyner } /* ixgbe_bypass_mutex_clear */
678eb6488eSEric Joyner 
688eb6488eSEric Joyner /************************************************************************
698eb6488eSEric Joyner  * ixgbe_bypass_wd_mutex_enter
708eb6488eSEric Joyner  *
718eb6488eSEric Joyner  *   Watchdog entry is allowed to simply grab the high priority
728eb6488eSEric Joyner  ************************************************************************/
738eb6488eSEric Joyner static void
748eb6488eSEric Joyner ixgbe_bypass_wd_mutex_enter(struct adapter *adapter)
758eb6488eSEric Joyner {
768eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0)
778eb6488eSEric Joyner 		usec_delay(3000);
788eb6488eSEric Joyner 	return;
798eb6488eSEric Joyner } /* ixgbe_bypass_wd_mutex_enter */
808eb6488eSEric Joyner 
818eb6488eSEric Joyner /************************************************************************
828eb6488eSEric Joyner  * ixgbe_bypass_wd_mutex_clear
838eb6488eSEric Joyner  ************************************************************************/
848eb6488eSEric Joyner static void
858eb6488eSEric Joyner ixgbe_bypass_wd_mutex_clear(struct adapter *adapter)
868eb6488eSEric Joyner {
878eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0)
888eb6488eSEric Joyner 		usec_delay(6000);
898eb6488eSEric Joyner 	return;
908eb6488eSEric Joyner } /* ixgbe_bypass_wd_mutex_clear */
918eb6488eSEric Joyner 
928eb6488eSEric Joyner /************************************************************************
938eb6488eSEric Joyner  * ixgbe_get_bypass_time
948eb6488eSEric Joyner  ************************************************************************/
958eb6488eSEric Joyner static void
968eb6488eSEric Joyner ixgbe_get_bypass_time(u32 *year, u32 *sec)
978eb6488eSEric Joyner {
988eb6488eSEric Joyner 	struct timespec current;
998eb6488eSEric Joyner 
1008eb6488eSEric Joyner 	*year = 1970;           /* time starts at 01/01/1970 */
1018eb6488eSEric Joyner 	nanotime(&current);
1028eb6488eSEric Joyner 	*sec = current.tv_sec;
1038eb6488eSEric Joyner 
1048eb6488eSEric Joyner 	while(*sec > SEC_THIS_YEAR(*year)) {
1058eb6488eSEric Joyner 		*sec -= SEC_THIS_YEAR(*year);
1068eb6488eSEric Joyner 		(*year)++;
1078eb6488eSEric Joyner 	}
1088eb6488eSEric Joyner } /* ixgbe_get_bypass_time */
1098eb6488eSEric Joyner 
1108eb6488eSEric Joyner /************************************************************************
1118eb6488eSEric Joyner  * ixgbe_bp_version
1128eb6488eSEric Joyner  *
1138eb6488eSEric Joyner  *   Display the feature version
1148eb6488eSEric Joyner  ************************************************************************/
1158eb6488eSEric Joyner static int
1168eb6488eSEric Joyner ixgbe_bp_version(SYSCTL_HANDLER_ARGS)
1178eb6488eSEric Joyner {
1188eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
1198eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
1208eb6488eSEric Joyner 	int             error = 0;
1218eb6488eSEric Joyner 	static int      version = 0;
1228eb6488eSEric Joyner 	u32             cmd;
1238eb6488eSEric Joyner 
1248eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
1258eb6488eSEric Joyner 	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
1268eb6488eSEric Joyner 	cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) &
1278eb6488eSEric Joyner 	    BYPASS_CTL2_OFFSET_M;
1288eb6488eSEric Joyner 	if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0))
1298eb6488eSEric Joyner 		goto err;
1308eb6488eSEric Joyner 	msec_delay(100);
1318eb6488eSEric Joyner 	cmd &= ~BYPASS_WE;
1328eb6488eSEric Joyner 	if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0))
1338eb6488eSEric Joyner 		goto err;
1348eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
1358eb6488eSEric Joyner 	version &= BYPASS_CTL2_DATA_M;
1368eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &version, 0, req);
1378eb6488eSEric Joyner 	return (error);
1388eb6488eSEric Joyner err:
1398eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
1408eb6488eSEric Joyner 	return (error);
1418eb6488eSEric Joyner 
1428eb6488eSEric Joyner } /* ixgbe_bp_version */
1438eb6488eSEric Joyner 
1448eb6488eSEric Joyner /************************************************************************
1458eb6488eSEric Joyner  * ixgbe_bp_set_state
1468eb6488eSEric Joyner  *
1478eb6488eSEric Joyner  *   Show/Set the Bypass State:
1488eb6488eSEric Joyner  *	1 = NORMAL
1498eb6488eSEric Joyner  *	2 = BYPASS
1508eb6488eSEric Joyner  *	3 = ISOLATE
1518eb6488eSEric Joyner  *
1528eb6488eSEric Joyner  *	With no argument the state is displayed,
1538eb6488eSEric Joyner  *	passing a value will set it.
1548eb6488eSEric Joyner  ************************************************************************/
1558eb6488eSEric Joyner static int
1568eb6488eSEric Joyner ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS)
1578eb6488eSEric Joyner {
1588eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
1598eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
1608eb6488eSEric Joyner 	int             error = 0;
1618eb6488eSEric Joyner 	static int      state = 0;
1628eb6488eSEric Joyner 
1638eb6488eSEric Joyner 	/* Get the current state */
1648eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
1658eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw,
1668eb6488eSEric Joyner 	    BYPASS_PAGE_CTL0, &state);
1678eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
168c19c7afeSEric Joyner 	if (error != 0)
1698eb6488eSEric Joyner 		return (error);
1708eb6488eSEric Joyner 	state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3;
1718eb6488eSEric Joyner 
1728eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &state, 0, req);
173c19c7afeSEric Joyner 	if ((error != 0) || (req->newptr == NULL))
1748eb6488eSEric Joyner 		return (error);
1758eb6488eSEric Joyner 
1768eb6488eSEric Joyner 	/* Sanity check new state */
1778eb6488eSEric Joyner 	switch (state) {
1788eb6488eSEric Joyner 	case BYPASS_NORM:
1798eb6488eSEric Joyner 	case BYPASS_BYPASS:
1808eb6488eSEric Joyner 	case BYPASS_ISOLATE:
1818eb6488eSEric Joyner 		break;
1828eb6488eSEric Joyner 	default:
1838eb6488eSEric Joyner 		return (EINVAL);
1848eb6488eSEric Joyner 	}
1858eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
1868eb6488eSEric Joyner 	if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
1878eb6488eSEric Joyner 	    BYPASS_MODE_OFF_M, state) != 0))
1888eb6488eSEric Joyner 		goto out;
1898eb6488eSEric Joyner 	/* Set AUTO back on so FW can receive events */
1908eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
1918eb6488eSEric Joyner 	    BYPASS_MODE_OFF_M, BYPASS_AUTO);
1928eb6488eSEric Joyner out:
1938eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
1948eb6488eSEric Joyner 	usec_delay(6000);
1958eb6488eSEric Joyner 	return (error);
1968eb6488eSEric Joyner } /* ixgbe_bp_set_state */
1978eb6488eSEric Joyner 
1988eb6488eSEric Joyner /************************************************************************
1998eb6488eSEric Joyner  * The following routines control the operational
2008eb6488eSEric Joyner  * "rules" of the feature, what behavior will occur
2018eb6488eSEric Joyner  * when particular events occur.
2028eb6488eSEric Joyner  * 	Values are:
2038eb6488eSEric Joyner  *		0 - no change for the event (NOP)
2048eb6488eSEric Joyner  *		1 - go to Normal operation
2058eb6488eSEric Joyner  *		2 - go to Bypass operation
2068eb6488eSEric Joyner  *		3 - go to Isolate operation
2078eb6488eSEric Joyner  * Calling the entry with no argument just displays
2088eb6488eSEric Joyner  * the current rule setting.
2098eb6488eSEric Joyner  ************************************************************************/
2108eb6488eSEric Joyner 
2118eb6488eSEric Joyner /************************************************************************
2128eb6488eSEric Joyner  * ixgbe_bp_timeout
2138eb6488eSEric Joyner  *
2148eb6488eSEric Joyner  * This is to set the Rule for the watchdog,
2158eb6488eSEric Joyner  * not the actual watchdog timeout value.
2168eb6488eSEric Joyner  ************************************************************************/
2178eb6488eSEric Joyner static int
2188eb6488eSEric Joyner ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)
2198eb6488eSEric Joyner {
2208eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
2218eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
2228eb6488eSEric Joyner 	int             error = 0;
2238eb6488eSEric Joyner 	static int      timeout = 0;
2248eb6488eSEric Joyner 
2258eb6488eSEric Joyner 	/* Get the current value */
2268eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
2278eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout);
2288eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
2298eb6488eSEric Joyner 	if (error)
2308eb6488eSEric Joyner 		return (error);
2318eb6488eSEric Joyner 	timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3;
2328eb6488eSEric Joyner 
2338eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &timeout, 0, req);
2348eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
2358eb6488eSEric Joyner 		return (error);
2368eb6488eSEric Joyner 
2378eb6488eSEric Joyner 	/* Sanity check on the setting */
2388eb6488eSEric Joyner 	switch (timeout) {
2398eb6488eSEric Joyner 	case BYPASS_NOP:
2408eb6488eSEric Joyner 	case BYPASS_NORM:
2418eb6488eSEric Joyner 	case BYPASS_BYPASS:
2428eb6488eSEric Joyner 	case BYPASS_ISOLATE:
2438eb6488eSEric Joyner 		break;
2448eb6488eSEric Joyner 	default:
2458eb6488eSEric Joyner 		return (EINVAL);
2468eb6488eSEric Joyner 	}
2478eb6488eSEric Joyner 
2488eb6488eSEric Joyner 	/* Set the new state */
2498eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
2508eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
2518eb6488eSEric Joyner 	    BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT);
2528eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
2538eb6488eSEric Joyner 	usec_delay(6000);
2548eb6488eSEric Joyner 	return (error);
2558eb6488eSEric Joyner } /* ixgbe_bp_timeout */
2568eb6488eSEric Joyner 
2578eb6488eSEric Joyner /************************************************************************
2588eb6488eSEric Joyner  * ixgbe_bp_main_on
2598eb6488eSEric Joyner  ************************************************************************/
2608eb6488eSEric Joyner static int
2618eb6488eSEric Joyner ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)
2628eb6488eSEric Joyner {
2638eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
2648eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
2658eb6488eSEric Joyner 	int             error = 0;
2668eb6488eSEric Joyner 	static int      main_on = 0;
2678eb6488eSEric Joyner 
2688eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
2698eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on);
2708eb6488eSEric Joyner 	main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3;
2718eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
2728eb6488eSEric Joyner 	if (error)
2738eb6488eSEric Joyner 		return (error);
2748eb6488eSEric Joyner 
2758eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &main_on, 0, req);
2768eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
2778eb6488eSEric Joyner 		return (error);
2788eb6488eSEric Joyner 
2798eb6488eSEric Joyner 	/* Sanity check on the setting */
2808eb6488eSEric Joyner 	switch (main_on) {
2818eb6488eSEric Joyner 	case BYPASS_NOP:
2828eb6488eSEric Joyner 	case BYPASS_NORM:
2838eb6488eSEric Joyner 	case BYPASS_BYPASS:
2848eb6488eSEric Joyner 	case BYPASS_ISOLATE:
2858eb6488eSEric Joyner 		break;
2868eb6488eSEric Joyner 	default:
2878eb6488eSEric Joyner 		return (EINVAL);
2888eb6488eSEric Joyner 	}
2898eb6488eSEric Joyner 
2908eb6488eSEric Joyner 	/* Set the new state */
2918eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
2928eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
2938eb6488eSEric Joyner 	    BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT);
2948eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
2958eb6488eSEric Joyner 	usec_delay(6000);
2968eb6488eSEric Joyner 	return (error);
2978eb6488eSEric Joyner } /* ixgbe_bp_main_on */
2988eb6488eSEric Joyner 
2998eb6488eSEric Joyner /************************************************************************
3008eb6488eSEric Joyner  * ixgbe_bp_main_off
3018eb6488eSEric Joyner  ************************************************************************/
3028eb6488eSEric Joyner static int
3038eb6488eSEric Joyner ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)
3048eb6488eSEric Joyner {
3058eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
3068eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3078eb6488eSEric Joyner 	int             error = 0;
3088eb6488eSEric Joyner 	static int      main_off = 0;
3098eb6488eSEric Joyner 
3108eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
3118eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off);
3128eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
3138eb6488eSEric Joyner 	if (error)
3148eb6488eSEric Joyner 		return (error);
3158eb6488eSEric Joyner 	main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3;
3168eb6488eSEric Joyner 
3178eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &main_off, 0, req);
3188eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
3198eb6488eSEric Joyner 		return (error);
3208eb6488eSEric Joyner 
3218eb6488eSEric Joyner 	/* Sanity check on the setting */
3228eb6488eSEric Joyner 	switch (main_off) {
3238eb6488eSEric Joyner 	case BYPASS_NOP:
3248eb6488eSEric Joyner 	case BYPASS_NORM:
3258eb6488eSEric Joyner 	case BYPASS_BYPASS:
3268eb6488eSEric Joyner 	case BYPASS_ISOLATE:
3278eb6488eSEric Joyner 		break;
3288eb6488eSEric Joyner 	default:
3298eb6488eSEric Joyner 		return (EINVAL);
3308eb6488eSEric Joyner 	}
3318eb6488eSEric Joyner 
3328eb6488eSEric Joyner 	/* Set the new state */
3338eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
3348eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
3358eb6488eSEric Joyner 	    BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT);
3368eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
3378eb6488eSEric Joyner 	usec_delay(6000);
3388eb6488eSEric Joyner 	return (error);
3398eb6488eSEric Joyner } /* ixgbe_bp_main_off */
3408eb6488eSEric Joyner 
3418eb6488eSEric Joyner /************************************************************************
3428eb6488eSEric Joyner  * ixgbe_bp_aux_on
3438eb6488eSEric Joyner  ************************************************************************/
3448eb6488eSEric Joyner static int
3458eb6488eSEric Joyner ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)
3468eb6488eSEric Joyner {
3478eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
3488eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3498eb6488eSEric Joyner 	int             error = 0;
3508eb6488eSEric Joyner 	static int      aux_on = 0;
3518eb6488eSEric Joyner 
3528eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
3538eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on);
3548eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
3558eb6488eSEric Joyner 	if (error)
3568eb6488eSEric Joyner 		return (error);
3578eb6488eSEric Joyner 	aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3;
3588eb6488eSEric Joyner 
3598eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &aux_on, 0, req);
3608eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
3618eb6488eSEric Joyner 		return (error);
3628eb6488eSEric Joyner 
3638eb6488eSEric Joyner 	/* Sanity check on the setting */
3648eb6488eSEric Joyner 	switch (aux_on) {
3658eb6488eSEric Joyner 	case BYPASS_NOP:
3668eb6488eSEric Joyner 	case BYPASS_NORM:
3678eb6488eSEric Joyner 	case BYPASS_BYPASS:
3688eb6488eSEric Joyner 	case BYPASS_ISOLATE:
3698eb6488eSEric Joyner 		break;
3708eb6488eSEric Joyner 	default:
3718eb6488eSEric Joyner 		return (EINVAL);
3728eb6488eSEric Joyner 	}
3738eb6488eSEric Joyner 
3748eb6488eSEric Joyner 	/* Set the new state */
3758eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
3768eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
3778eb6488eSEric Joyner 	    BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT);
3788eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
3798eb6488eSEric Joyner 	usec_delay(6000);
3808eb6488eSEric Joyner 	return (error);
3818eb6488eSEric Joyner } /* ixgbe_bp_aux_on */
3828eb6488eSEric Joyner 
3838eb6488eSEric Joyner /************************************************************************
3848eb6488eSEric Joyner  * ixgbe_bp_aux_off
3858eb6488eSEric Joyner  ************************************************************************/
3868eb6488eSEric Joyner static int
3878eb6488eSEric Joyner ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)
3888eb6488eSEric Joyner {
3898eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
3908eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3918eb6488eSEric Joyner 	int             error = 0;
3928eb6488eSEric Joyner 	static int      aux_off = 0;
3938eb6488eSEric Joyner 
3948eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
3958eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off);
3968eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
3978eb6488eSEric Joyner 	if (error)
3988eb6488eSEric Joyner 		return (error);
3998eb6488eSEric Joyner 	aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3;
4008eb6488eSEric Joyner 
4018eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &aux_off, 0, req);
4028eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
4038eb6488eSEric Joyner 		return (error);
4048eb6488eSEric Joyner 
4058eb6488eSEric Joyner 	/* Sanity check on the setting */
4068eb6488eSEric Joyner 	switch (aux_off) {
4078eb6488eSEric Joyner 	case BYPASS_NOP:
4088eb6488eSEric Joyner 	case BYPASS_NORM:
4098eb6488eSEric Joyner 	case BYPASS_BYPASS:
4108eb6488eSEric Joyner 	case BYPASS_ISOLATE:
4118eb6488eSEric Joyner 		break;
4128eb6488eSEric Joyner 	default:
4138eb6488eSEric Joyner 		return (EINVAL);
4148eb6488eSEric Joyner 	}
4158eb6488eSEric Joyner 
4168eb6488eSEric Joyner 	/* Set the new state */
4178eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
4188eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
4198eb6488eSEric Joyner 	    BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT);
4208eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
4218eb6488eSEric Joyner 	usec_delay(6000);
4228eb6488eSEric Joyner 	return (error);
4238eb6488eSEric Joyner } /* ixgbe_bp_aux_off */
4248eb6488eSEric Joyner 
4258eb6488eSEric Joyner /************************************************************************
4268eb6488eSEric Joyner  * ixgbe_bp_wd_set - Set the Watchdog timer value
4278eb6488eSEric Joyner  *
4288eb6488eSEric Joyner  *   Valid settings are:
4298eb6488eSEric Joyner  *	- 0 will disable the watchdog
4308eb6488eSEric Joyner  *	- 1, 2, 3, 4, 8, 16, 32
4318eb6488eSEric Joyner  *	- anything else is invalid and will be ignored
4328eb6488eSEric Joyner  ************************************************************************/
4338eb6488eSEric Joyner static int
4348eb6488eSEric Joyner ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)
4358eb6488eSEric Joyner {
4368eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
4378eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4388eb6488eSEric Joyner 	int             error, tmp;
4398eb6488eSEric Joyner 	static int      timeout = 0;
440c19c7afeSEric Joyner 	u32             mask, arg;
4418eb6488eSEric Joyner 
4428eb6488eSEric Joyner 	/* Get the current hardware value */
4438eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
4448eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp);
4458eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
4468eb6488eSEric Joyner 	if (error)
4478eb6488eSEric Joyner 		return (error);
4488eb6488eSEric Joyner 	/*
4498eb6488eSEric Joyner 	 * If armed keep the displayed value,
4508eb6488eSEric Joyner 	 * else change the display to zero.
4518eb6488eSEric Joyner 	 */
4528eb6488eSEric Joyner 	if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0)
4538eb6488eSEric Joyner 		timeout = 0;
4548eb6488eSEric Joyner 
4558eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &timeout, 0, req);
4568eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
4578eb6488eSEric Joyner 		return (error);
4588eb6488eSEric Joyner 
459c19c7afeSEric Joyner 	arg = 0x1 << BYPASS_WDT_ENABLE_SHIFT;
460c19c7afeSEric Joyner 	mask = BYPASS_WDT_ENABLE_M | BYPASS_WDT_VALUE_M;
4618eb6488eSEric Joyner 	switch (timeout) {
4628eb6488eSEric Joyner 	case 0: /* disables the timer */
463c19c7afeSEric Joyner 		arg = BYPASS_PAGE_CTL0;
464c19c7afeSEric Joyner 		mask = BYPASS_WDT_ENABLE_M;
4658eb6488eSEric Joyner 		break;
4668eb6488eSEric Joyner 	case 1:
467c19c7afeSEric Joyner 		arg |= BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT;
4688eb6488eSEric Joyner 		break;
4698eb6488eSEric Joyner 	case 2:
470c19c7afeSEric Joyner 		arg |= BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT;
4718eb6488eSEric Joyner 		break;
4728eb6488eSEric Joyner 	case 3:
473c19c7afeSEric Joyner 		arg |= BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT;
4748eb6488eSEric Joyner 		break;
4758eb6488eSEric Joyner 	case 4:
476c19c7afeSEric Joyner 		arg |= BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT;
4778eb6488eSEric Joyner 		break;
4788eb6488eSEric Joyner 	case 8:
479c19c7afeSEric Joyner 		arg |= BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT;
4808eb6488eSEric Joyner 		break;
4818eb6488eSEric Joyner 	case 16:
482c19c7afeSEric Joyner 		arg |= BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT;
4838eb6488eSEric Joyner 		break;
4848eb6488eSEric Joyner 	case 32:
485c19c7afeSEric Joyner 		arg |= BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT;
4868eb6488eSEric Joyner 		break;
4878eb6488eSEric Joyner 	default:
4888eb6488eSEric Joyner 		return (EINVAL);
4898eb6488eSEric Joyner 	}
490c19c7afeSEric Joyner 
4918eb6488eSEric Joyner 	/* Set the new watchdog */
4928eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
4938eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg);
4948eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
4958eb6488eSEric Joyner 
4968eb6488eSEric Joyner 	return (error);
4978eb6488eSEric Joyner } /* ixgbe_bp_wd_set */
4988eb6488eSEric Joyner 
4998eb6488eSEric Joyner /************************************************************************
5008eb6488eSEric Joyner  * ixgbe_bp_wd_reset - Reset the Watchdog timer
5018eb6488eSEric Joyner  *
5028eb6488eSEric Joyner  *    To activate this it must be called with any argument.
5038eb6488eSEric Joyner  ************************************************************************/
5048eb6488eSEric Joyner static int
5058eb6488eSEric Joyner ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)
5068eb6488eSEric Joyner {
5078eb6488eSEric Joyner 	struct adapter  *adapter = (struct adapter *) arg1;
5088eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
5098eb6488eSEric Joyner 	u32             sec, year;
5108eb6488eSEric Joyner 	int             cmd, count = 0, error = 0;
5118eb6488eSEric Joyner 	int             reset_wd = 0;
5128eb6488eSEric Joyner 
5138eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &reset_wd, 0, req);
5148eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
5158eb6488eSEric Joyner 		return (error);
5168eb6488eSEric Joyner 
5178eb6488eSEric Joyner 	cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
5188eb6488eSEric Joyner 
5198eb6488eSEric Joyner 	/* Resync the FW time while writing to CTL1 anyway */
5208eb6488eSEric Joyner 	ixgbe_get_bypass_time(&year, &sec);
5218eb6488eSEric Joyner 
5228eb6488eSEric Joyner 	cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
5238eb6488eSEric Joyner 	cmd |= BYPASS_CTL1_OFFTRST;
5248eb6488eSEric Joyner 
5258eb6488eSEric Joyner 	ixgbe_bypass_wd_mutex_enter(adapter);
5268eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd);
5278eb6488eSEric Joyner 
5288eb6488eSEric Joyner 	/* Read until it matches what we wrote, or we time out */
5298eb6488eSEric Joyner 	do {
5308eb6488eSEric Joyner 		if (count++ > 10) {
5318eb6488eSEric Joyner 			error = IXGBE_BYPASS_FW_WRITE_FAILURE;
5328eb6488eSEric Joyner 			break;
5338eb6488eSEric Joyner 		}
534c19c7afeSEric Joyner 		error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd);
535c19c7afeSEric Joyner 		if (error != 0) {
5368eb6488eSEric Joyner 			error = IXGBE_ERR_INVALID_ARGUMENT;
5378eb6488eSEric Joyner 			break;
5388eb6488eSEric Joyner 		}
5398eb6488eSEric Joyner 	} while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd));
5408eb6488eSEric Joyner 
5418eb6488eSEric Joyner 	reset_wd = 0;
5428eb6488eSEric Joyner 	ixgbe_bypass_wd_mutex_clear(adapter);
5438eb6488eSEric Joyner 	return (error);
5448eb6488eSEric Joyner } /* ixgbe_bp_wd_reset */
5458eb6488eSEric Joyner 
5468eb6488eSEric Joyner /************************************************************************
5478eb6488eSEric Joyner  * ixgbe_bp_log - Display the bypass log
5488eb6488eSEric Joyner  *
5498eb6488eSEric Joyner  *   You must pass a non-zero arg to sysctl
5508eb6488eSEric Joyner  ************************************************************************/
5518eb6488eSEric Joyner static int
5528eb6488eSEric Joyner ixgbe_bp_log(SYSCTL_HANDLER_ARGS)
5538eb6488eSEric Joyner {
5548eb6488eSEric Joyner 	struct adapter             *adapter = (struct adapter *) arg1;
5558eb6488eSEric Joyner 	struct ixgbe_hw            *hw = &adapter->hw;
5568eb6488eSEric Joyner 	u32                        cmd, base, head;
5578eb6488eSEric Joyner 	u32                        log_off, count = 0;
5588eb6488eSEric Joyner 	static int                 status = 0;
5598eb6488eSEric Joyner 	u8                         data;
5608eb6488eSEric Joyner 	struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS];
5618eb6488eSEric Joyner 	int                        i, error = 0;
5628eb6488eSEric Joyner 
5638eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &status, 0, req);
5648eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
5658eb6488eSEric Joyner 		return (error);
5668eb6488eSEric Joyner 
5678eb6488eSEric Joyner 	/* Keep the log display single-threaded */
5688eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.log, 0, 1) == 0)
5698eb6488eSEric Joyner 		usec_delay(3000);
5708eb6488eSEric Joyner 
5718eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
5728eb6488eSEric Joyner 
5738eb6488eSEric Joyner 	/* Find Current head of the log eeprom offset */
5748eb6488eSEric Joyner 	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
5758eb6488eSEric Joyner 	cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
5768eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, cmd, &status);
5778eb6488eSEric Joyner 	if (error)
5788eb6488eSEric Joyner 		goto unlock_err;
5798eb6488eSEric Joyner 
5808eb6488eSEric Joyner 	/* wait for the write to stick */
5818eb6488eSEric Joyner 	msec_delay(100);
5828eb6488eSEric Joyner 
5838eb6488eSEric Joyner 	/* Now read the results */
5848eb6488eSEric Joyner 	cmd &= ~BYPASS_WE;
5858eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, cmd, &status);
5868eb6488eSEric Joyner 	if (error)
5878eb6488eSEric Joyner 		goto unlock_err;
5888eb6488eSEric Joyner 
5898eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
5908eb6488eSEric Joyner 
5918eb6488eSEric Joyner 	base = status & BYPASS_CTL2_DATA_M;
5928eb6488eSEric Joyner 	head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT;
5938eb6488eSEric Joyner 
5948eb6488eSEric Joyner 	/* address of the first log */
5958eb6488eSEric Joyner 	log_off = base + (head * 5);
5968eb6488eSEric Joyner 
5978eb6488eSEric Joyner 	/* extract all the log entries */
5988eb6488eSEric Joyner 	while (count < BYPASS_MAX_LOGS) {
5998eb6488eSEric Joyner 		eeprom[count].logs = 0;
6008eb6488eSEric Joyner 		eeprom[count].actions = 0;
6018eb6488eSEric Joyner 
6028eb6488eSEric Joyner 		/* Log 5 bytes store in on u32 and a u8 */
6038eb6488eSEric Joyner 		for (i = 0; i < 4; i++) {
6048eb6488eSEric Joyner 			ixgbe_bypass_mutex_enter(adapter);
6058eb6488eSEric Joyner 			error = hw->mac.ops.bypass_rd_eep(hw, log_off + i,
6068eb6488eSEric Joyner 			    &data);
6078eb6488eSEric Joyner 			ixgbe_bypass_mutex_clear(adapter);
6088eb6488eSEric Joyner 			if (error)
609c19c7afeSEric Joyner 				return (EINVAL);
6108eb6488eSEric Joyner 			eeprom[count].logs += data << (8 * i);
6118eb6488eSEric Joyner 		}
6128eb6488eSEric Joyner 
6138eb6488eSEric Joyner 		ixgbe_bypass_mutex_enter(adapter);
6148eb6488eSEric Joyner 		error = hw->mac.ops.bypass_rd_eep(hw,
6158eb6488eSEric Joyner 		    log_off + i, &eeprom[count].actions);
6168eb6488eSEric Joyner 		ixgbe_bypass_mutex_clear(adapter);
6178eb6488eSEric Joyner 		if (error)
618c19c7afeSEric Joyner 			return (EINVAL);
6198eb6488eSEric Joyner 
6208eb6488eSEric Joyner 		/* Quit if not a unread log */
6218eb6488eSEric Joyner 		if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M))
6228eb6488eSEric Joyner 			break;
6238eb6488eSEric Joyner 		/*
6248eb6488eSEric Joyner 		 * Log looks good so store the address where it's
6258eb6488eSEric Joyner 		 * Unread Log bit is so we can clear it after safely
6268eb6488eSEric Joyner 		 * pulling out all of the log data.
6278eb6488eSEric Joyner 		 */
6288eb6488eSEric Joyner 		eeprom[count].clear_off = log_off;
6298eb6488eSEric Joyner 
6308eb6488eSEric Joyner 		count++;
6318eb6488eSEric Joyner 		head = head ? head - 1 : BYPASS_MAX_LOGS;
6328eb6488eSEric Joyner 		log_off = base + (head * 5);
6338eb6488eSEric Joyner 	}
6348eb6488eSEric Joyner 
6358eb6488eSEric Joyner 	/* reverse order (oldest first) for output */
6368eb6488eSEric Joyner 	while (count--) {
6378eb6488eSEric Joyner 		int year;
6388eb6488eSEric Joyner 		u32 mon, days, hours, min, sec;
6398eb6488eSEric Joyner 		u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M;
6408eb6488eSEric Joyner 		u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >>
6418eb6488eSEric Joyner 		    BYPASS_LOG_EVENT_SHIFT;
6428eb6488eSEric Joyner 		u8 action =  eeprom[count].actions & BYPASS_LOG_ACTION_M;
6438eb6488eSEric Joyner 		u16 day_mon[2][13] = {
6448eb6488eSEric Joyner 		  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
6458eb6488eSEric Joyner 		  {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
6468eb6488eSEric Joyner 		};
6478eb6488eSEric Joyner 		char *event_str[] = {"unknown", "main on", "aux on",
6488eb6488eSEric Joyner 		    "main off", "aux off", "WDT", "user" };
6498eb6488eSEric Joyner 		char *action_str[] = {"ignore", "normal", "bypass", "isolate",};
6508eb6488eSEric Joyner 
6518eb6488eSEric Joyner 		/* verify vaild data  1 - 6 */
6528eb6488eSEric Joyner 		if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR)
6538eb6488eSEric Joyner 			event = 0;
6548eb6488eSEric Joyner 
6558eb6488eSEric Joyner 		/*
6568eb6488eSEric Joyner 		 * time is in sec's this year, so convert to something
6578eb6488eSEric Joyner 		 * printable.
6588eb6488eSEric Joyner 		 */
6598eb6488eSEric Joyner 		ixgbe_get_bypass_time(&year, &sec);
6608eb6488eSEric Joyner 		days = time / SEC_PER_DAY;
6618eb6488eSEric Joyner 		for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--)
6628eb6488eSEric Joyner 			continue;
6638eb6488eSEric Joyner 		mon = i + 1;    /* display month as 1-12 */
6648eb6488eSEric Joyner 		time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY);
6658eb6488eSEric Joyner 		days = (time / SEC_PER_DAY) + 1;  /* first day is 1 */
6668eb6488eSEric Joyner 		time %= SEC_PER_DAY;
6678eb6488eSEric Joyner 		hours = time / (60 * 60);
6688eb6488eSEric Joyner 		time %= (60 * 60);
6698eb6488eSEric Joyner 		min = time / 60;
6708eb6488eSEric Joyner 		sec = time % 60;
6718eb6488eSEric Joyner 		device_printf(adapter->dev,
6728eb6488eSEric Joyner 		    "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n",
6738eb6488eSEric Joyner 		    mon, days, hours, min, sec, event_str[event],
6748eb6488eSEric Joyner 		    action_str[action]);
6758eb6488eSEric Joyner 		cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW;
6768eb6488eSEric Joyner 		cmd |= ((eeprom[count].clear_off + 3)
6778eb6488eSEric Joyner 		    << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
6788eb6488eSEric Joyner 		cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24);
6798eb6488eSEric Joyner 
6808eb6488eSEric Joyner 		ixgbe_bypass_mutex_enter(adapter);
6818eb6488eSEric Joyner 
6828eb6488eSEric Joyner 		error = hw->mac.ops.bypass_rw(hw, cmd, &status);
6838eb6488eSEric Joyner 
6848eb6488eSEric Joyner 		/* wait for the write to stick */
6858eb6488eSEric Joyner 		msec_delay(100);
6868eb6488eSEric Joyner 
6878eb6488eSEric Joyner 		ixgbe_bypass_mutex_clear(adapter);
6888eb6488eSEric Joyner 
6898eb6488eSEric Joyner 		if (error)
690c19c7afeSEric Joyner 			return (EINVAL);
6918eb6488eSEric Joyner 	}
6928eb6488eSEric Joyner 
6938eb6488eSEric Joyner 	status = 0; /* reset */
6948eb6488eSEric Joyner 	/* Another log command can now run */
6958eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0)
6968eb6488eSEric Joyner 		usec_delay(3000);
6978eb6488eSEric Joyner 	return (error);
6988eb6488eSEric Joyner 
6998eb6488eSEric Joyner unlock_err:
7008eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
7018eb6488eSEric Joyner 	status = 0; /* reset */
7028eb6488eSEric Joyner 	while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0)
7038eb6488eSEric Joyner 		usec_delay(3000);
704c19c7afeSEric Joyner 	return (EINVAL);
7058eb6488eSEric Joyner } /* ixgbe_bp_log */
7068eb6488eSEric Joyner 
7078eb6488eSEric Joyner /************************************************************************
7088eb6488eSEric Joyner  * ixgbe_bypass_init - Set up infrastructure for the bypass feature
7098eb6488eSEric Joyner  *
7108eb6488eSEric Joyner  *   Do time and sysctl initialization here.  This feature is
7118eb6488eSEric Joyner  *   only enabled for the first port of a bypass adapter.
7128eb6488eSEric Joyner  ************************************************************************/
7138eb6488eSEric Joyner void
7148eb6488eSEric Joyner ixgbe_bypass_init(struct adapter *adapter)
7158eb6488eSEric Joyner {
7168eb6488eSEric Joyner 	struct ixgbe_hw        *hw = &adapter->hw;
7178eb6488eSEric Joyner 	device_t               dev = adapter->dev;
7188eb6488eSEric Joyner 	struct sysctl_oid      *bp_node;
7198eb6488eSEric Joyner 	struct sysctl_oid_list *bp_list;
7208eb6488eSEric Joyner 	u32                    mask, value, sec, year;
7218eb6488eSEric Joyner 
7228eb6488eSEric Joyner 	if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS))
7238eb6488eSEric Joyner 		return;
7248eb6488eSEric Joyner 
7258eb6488eSEric Joyner 	/* First set up time for the hardware */
7268eb6488eSEric Joyner 	ixgbe_get_bypass_time(&year, &sec);
7278eb6488eSEric Joyner 
7288eb6488eSEric Joyner 	mask = BYPASS_CTL1_TIME_M
7298eb6488eSEric Joyner 	     | BYPASS_CTL1_VALID_M
7308eb6488eSEric Joyner 	     | BYPASS_CTL1_OFFTRST_M;
7318eb6488eSEric Joyner 
7328eb6488eSEric Joyner 	value = (sec & BYPASS_CTL1_TIME_M)
7338eb6488eSEric Joyner 	      | BYPASS_CTL1_VALID
7348eb6488eSEric Joyner 	      | BYPASS_CTL1_OFFTRST;
7358eb6488eSEric Joyner 
7368eb6488eSEric Joyner 	ixgbe_bypass_mutex_enter(adapter);
7378eb6488eSEric Joyner 	hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
7388eb6488eSEric Joyner 	ixgbe_bypass_mutex_clear(adapter);
7398eb6488eSEric Joyner 
7408eb6488eSEric Joyner 	/* Now set up the SYSCTL infrastructure */
7418eb6488eSEric Joyner 
7428eb6488eSEric Joyner 	/*
7438eb6488eSEric Joyner 	 * The log routine is kept separate from the other
7448eb6488eSEric Joyner 	 * children so a general display command like:
7458eb6488eSEric Joyner 	 * `sysctl dev.ix.0.bypass` will not show the log.
7468eb6488eSEric Joyner 	 */
7478eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
7488eb6488eSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
749*20b91f0aSPawel Biernacki 	    OID_AUTO, "bypass_log",
750*20b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7518eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_log, "I", "Bypass Log");
7528eb6488eSEric Joyner 
7538eb6488eSEric Joyner 	/* All other setting are hung from the 'bypass' node */
7548eb6488eSEric Joyner 	bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
7558eb6488eSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
756*20b91f0aSPawel Biernacki 	    OID_AUTO, "bypass", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Bypass");
7578eb6488eSEric Joyner 
7588eb6488eSEric Joyner 	bp_list = SYSCTL_CHILDREN(bp_node);
7598eb6488eSEric Joyner 
7608eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
761*20b91f0aSPawel Biernacki 	    OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
7628eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_version, "I", "Bypass Version");
7638eb6488eSEric Joyner 
7648eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
765*20b91f0aSPawel Biernacki 	    OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7668eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_set_state, "I", "Bypass State");
7678eb6488eSEric Joyner 
7688eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
769*20b91f0aSPawel Biernacki 	    OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7708eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_timeout, "I", "Bypass Timeout");
7718eb6488eSEric Joyner 
7728eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
773*20b91f0aSPawel Biernacki 	    OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7748eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_main_on, "I", "Bypass Main On");
7758eb6488eSEric Joyner 
7768eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
777*20b91f0aSPawel Biernacki 	    OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7788eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_main_off, "I", "Bypass Main Off");
7798eb6488eSEric Joyner 
7808eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
781*20b91f0aSPawel Biernacki 	    OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7828eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On");
7838eb6488eSEric Joyner 
7848eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
785*20b91f0aSPawel Biernacki 	    OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7868eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off");
7878eb6488eSEric Joyner 
7888eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
789*20b91f0aSPawel Biernacki 	    OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7908eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog");
7918eb6488eSEric Joyner 
7928eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
793*20b91f0aSPawel Biernacki 	    OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
7948eb6488eSEric Joyner 	    adapter, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset");
7958eb6488eSEric Joyner 
7968eb6488eSEric Joyner 	adapter->feat_en |= IXGBE_FEATURE_BYPASS;
7978eb6488eSEric Joyner } /* ixgbe_bypass_init */
7988eb6488eSEric Joyner 
799