xref: /freebsd/sys/dev/ixgbe/if_bypass.c (revision c58d34dd67a419866ee50f152044e49cecbae261)
1*c58d34ddSKevin Bowling /*****************************************************************************
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 
32*c58d34ddSKevin Bowling *****************************************************************************/
338eb6488eSEric Joyner 
348eb6488eSEric Joyner 
358eb6488eSEric Joyner #include "ixgbe.h"
368eb6488eSEric Joyner 
378eb6488eSEric Joyner /************************************************************************
388eb6488eSEric Joyner  * ixgbe_bypass_mutex_enter
398eb6488eSEric Joyner  *
408eb6488eSEric Joyner  *   Mutex support for the bypass feature. Using a dual lock
418eb6488eSEric Joyner  *   to facilitate a privileged access to the watchdog update
428eb6488eSEric Joyner  *   over other threads.
438eb6488eSEric Joyner  ************************************************************************/
448eb6488eSEric Joyner static void
ixgbe_bypass_mutex_enter(struct ixgbe_softc * sc)45b1d5caf3SKevin Bowling ixgbe_bypass_mutex_enter(struct ixgbe_softc *sc)
468eb6488eSEric Joyner {
47b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.low, 0, 1) == 0)
488eb6488eSEric Joyner 		usec_delay(3000);
49b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.high, 0, 1) == 0)
508eb6488eSEric Joyner 		usec_delay(3000);
518eb6488eSEric Joyner 	return;
528eb6488eSEric Joyner } /* ixgbe_bypass_mutex_enter */
538eb6488eSEric Joyner 
548eb6488eSEric Joyner /************************************************************************
558eb6488eSEric Joyner  * ixgbe_bypass_mutex_clear
568eb6488eSEric Joyner  ************************************************************************/
578eb6488eSEric Joyner static void
ixgbe_bypass_mutex_clear(struct ixgbe_softc * sc)58b1d5caf3SKevin Bowling ixgbe_bypass_mutex_clear(struct ixgbe_softc *sc)
598eb6488eSEric Joyner {
60b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.high, 1, 0) == 0)
618eb6488eSEric Joyner 		usec_delay(6000);
62b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.low, 1, 0) == 0)
638eb6488eSEric Joyner 		usec_delay(6000);
648eb6488eSEric Joyner 	return;
658eb6488eSEric Joyner } /* ixgbe_bypass_mutex_clear */
668eb6488eSEric Joyner 
678eb6488eSEric Joyner /************************************************************************
688eb6488eSEric Joyner  * ixgbe_bypass_wd_mutex_enter
698eb6488eSEric Joyner  *
708eb6488eSEric Joyner  *   Watchdog entry is allowed to simply grab the high priority
718eb6488eSEric Joyner  ************************************************************************/
728eb6488eSEric Joyner static void
ixgbe_bypass_wd_mutex_enter(struct ixgbe_softc * sc)73b1d5caf3SKevin Bowling ixgbe_bypass_wd_mutex_enter(struct ixgbe_softc *sc)
748eb6488eSEric Joyner {
75b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.high, 0, 1) == 0)
768eb6488eSEric Joyner 		usec_delay(3000);
778eb6488eSEric Joyner 	return;
788eb6488eSEric Joyner } /* ixgbe_bypass_wd_mutex_enter */
798eb6488eSEric Joyner 
808eb6488eSEric Joyner /************************************************************************
818eb6488eSEric Joyner  * ixgbe_bypass_wd_mutex_clear
828eb6488eSEric Joyner  ************************************************************************/
838eb6488eSEric Joyner static void
ixgbe_bypass_wd_mutex_clear(struct ixgbe_softc * sc)84b1d5caf3SKevin Bowling ixgbe_bypass_wd_mutex_clear(struct ixgbe_softc *sc)
858eb6488eSEric Joyner {
86b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.high, 1, 0) == 0)
878eb6488eSEric Joyner 		usec_delay(6000);
888eb6488eSEric Joyner 	return;
898eb6488eSEric Joyner } /* ixgbe_bypass_wd_mutex_clear */
908eb6488eSEric Joyner 
918eb6488eSEric Joyner /************************************************************************
928eb6488eSEric Joyner  * ixgbe_get_bypass_time
938eb6488eSEric Joyner  ************************************************************************/
948eb6488eSEric Joyner static void
ixgbe_get_bypass_time(u32 * year,u32 * sec)958eb6488eSEric Joyner ixgbe_get_bypass_time(u32 *year, u32 *sec)
968eb6488eSEric Joyner {
978eb6488eSEric Joyner 	struct timespec current;
988eb6488eSEric Joyner 
998eb6488eSEric Joyner 	*year = 1970;           /* time starts at 01/01/1970 */
1008eb6488eSEric Joyner 	nanotime(&current);
1018eb6488eSEric Joyner 	*sec = current.tv_sec;
1028eb6488eSEric Joyner 
1038eb6488eSEric Joyner 	while(*sec > SEC_THIS_YEAR(*year)) {
1048eb6488eSEric Joyner 		*sec -= SEC_THIS_YEAR(*year);
1058eb6488eSEric Joyner 		(*year)++;
1068eb6488eSEric Joyner 	}
1078eb6488eSEric Joyner } /* ixgbe_get_bypass_time */
1088eb6488eSEric Joyner 
1098eb6488eSEric Joyner /************************************************************************
1108eb6488eSEric Joyner  * ixgbe_bp_version
1118eb6488eSEric Joyner  *
1128eb6488eSEric Joyner  *   Display the feature version
1138eb6488eSEric Joyner  ************************************************************************/
1148eb6488eSEric Joyner static int
ixgbe_bp_version(SYSCTL_HANDLER_ARGS)1158eb6488eSEric Joyner ixgbe_bp_version(SYSCTL_HANDLER_ARGS)
1168eb6488eSEric Joyner {
117b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
118b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
1198eb6488eSEric Joyner 	int error = 0;
1208eb6488eSEric Joyner 	static int version = 0;
1218eb6488eSEric Joyner 	u32 cmd;
1228eb6488eSEric Joyner 
123b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
1248eb6488eSEric Joyner 	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
1258eb6488eSEric Joyner 	cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) &
1268eb6488eSEric Joyner 	    BYPASS_CTL2_OFFSET_M;
1278eb6488eSEric Joyner 	if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0))
1288eb6488eSEric Joyner 		goto err;
1298eb6488eSEric Joyner 	msec_delay(100);
1308eb6488eSEric Joyner 	cmd &= ~BYPASS_WE;
1318eb6488eSEric Joyner 	if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0))
1328eb6488eSEric Joyner 		goto err;
133b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
1348eb6488eSEric Joyner 	version &= BYPASS_CTL2_DATA_M;
1358eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &version, 0, req);
1368eb6488eSEric Joyner 	return (error);
1378eb6488eSEric Joyner err:
138b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
1398eb6488eSEric Joyner 	return (error);
1408eb6488eSEric Joyner 
1418eb6488eSEric Joyner } /* ixgbe_bp_version */
1428eb6488eSEric Joyner 
1438eb6488eSEric Joyner /************************************************************************
1448eb6488eSEric Joyner  * ixgbe_bp_set_state
1458eb6488eSEric Joyner  *
1468eb6488eSEric Joyner  *   Show/Set the Bypass State:
1478eb6488eSEric Joyner  *	1 = NORMAL
1488eb6488eSEric Joyner  *	2 = BYPASS
1498eb6488eSEric Joyner  *	3 = ISOLATE
1508eb6488eSEric Joyner  *
1518eb6488eSEric Joyner  *	With no argument the state is displayed,
1528eb6488eSEric Joyner  *	passing a value will set it.
1538eb6488eSEric Joyner  ************************************************************************/
1548eb6488eSEric Joyner static int
ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS)1558eb6488eSEric Joyner ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS)
1568eb6488eSEric Joyner {
157b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
158b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
1598eb6488eSEric Joyner 	int error = 0;
1608eb6488eSEric Joyner 	static int state = 0;
1618eb6488eSEric Joyner 
1628eb6488eSEric Joyner 	/* Get the current state */
163b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
164*c58d34ddSKevin Bowling 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &state);
165b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
166c19c7afeSEric Joyner 	if (error != 0)
1678eb6488eSEric Joyner 		return (error);
1688eb6488eSEric Joyner 	state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3;
1698eb6488eSEric Joyner 
1708eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &state, 0, req);
171c19c7afeSEric Joyner 	if ((error != 0) || (req->newptr == NULL))
1728eb6488eSEric Joyner 		return (error);
1738eb6488eSEric Joyner 
1748eb6488eSEric Joyner 	/* Sanity check new state */
1758eb6488eSEric Joyner 	switch (state) {
1768eb6488eSEric Joyner 	case BYPASS_NORM:
1778eb6488eSEric Joyner 	case BYPASS_BYPASS:
1788eb6488eSEric Joyner 	case BYPASS_ISOLATE:
1798eb6488eSEric Joyner 		break;
1808eb6488eSEric Joyner 	default:
1818eb6488eSEric Joyner 		return (EINVAL);
1828eb6488eSEric Joyner 	}
183b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
1848eb6488eSEric Joyner 	if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
1858eb6488eSEric Joyner 	    BYPASS_MODE_OFF_M, state) != 0))
1868eb6488eSEric Joyner 		goto out;
1878eb6488eSEric Joyner 	/* Set AUTO back on so FW can receive events */
1888eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
1898eb6488eSEric Joyner 	    BYPASS_MODE_OFF_M, BYPASS_AUTO);
1908eb6488eSEric Joyner out:
191b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
1928eb6488eSEric Joyner 	usec_delay(6000);
1938eb6488eSEric Joyner 	return (error);
1948eb6488eSEric Joyner } /* ixgbe_bp_set_state */
1958eb6488eSEric Joyner 
1968eb6488eSEric Joyner /************************************************************************
1978eb6488eSEric Joyner  * The following routines control the operational
1988eb6488eSEric Joyner  * "rules" of the feature, what behavior will occur
1998eb6488eSEric Joyner  * when particular events occur.
2008eb6488eSEric Joyner  * 	Values are:
2018eb6488eSEric Joyner  *		0 - no change for the event (NOP)
2028eb6488eSEric Joyner  *		1 - go to Normal operation
2038eb6488eSEric Joyner  *		2 - go to Bypass operation
2048eb6488eSEric Joyner  *		3 - go to Isolate operation
2058eb6488eSEric Joyner  * Calling the entry with no argument just displays
2068eb6488eSEric Joyner  * the current rule setting.
2078eb6488eSEric Joyner  ************************************************************************/
2088eb6488eSEric Joyner 
2098eb6488eSEric Joyner /************************************************************************
2108eb6488eSEric Joyner  * ixgbe_bp_timeout
2118eb6488eSEric Joyner  *
2128eb6488eSEric Joyner  * This is to set the Rule for the watchdog,
2138eb6488eSEric Joyner  * not the actual watchdog timeout value.
2148eb6488eSEric Joyner  ************************************************************************/
2158eb6488eSEric Joyner static int
ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)2168eb6488eSEric Joyner ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)
2178eb6488eSEric Joyner {
218b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
219b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
2208eb6488eSEric Joyner 	int error = 0;
2218eb6488eSEric Joyner 	static int timeout = 0;
2228eb6488eSEric Joyner 
2238eb6488eSEric Joyner 	/* Get the current value */
224b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
2258eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout);
226b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
2278eb6488eSEric Joyner 	if (error)
2288eb6488eSEric Joyner 		return (error);
2298eb6488eSEric Joyner 	timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3;
2308eb6488eSEric Joyner 
2318eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &timeout, 0, req);
2328eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
2338eb6488eSEric Joyner 		return (error);
2348eb6488eSEric Joyner 
2358eb6488eSEric Joyner 	/* Sanity check on the setting */
2368eb6488eSEric Joyner 	switch (timeout) {
2378eb6488eSEric Joyner 	case BYPASS_NOP:
2388eb6488eSEric Joyner 	case BYPASS_NORM:
2398eb6488eSEric Joyner 	case BYPASS_BYPASS:
2408eb6488eSEric Joyner 	case BYPASS_ISOLATE:
2418eb6488eSEric Joyner 		break;
2428eb6488eSEric Joyner 	default:
2438eb6488eSEric Joyner 		return (EINVAL);
2448eb6488eSEric Joyner 	}
2458eb6488eSEric Joyner 
2468eb6488eSEric Joyner 	/* Set the new state */
247b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
2488eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
2498eb6488eSEric Joyner 	    BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT);
250b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
2518eb6488eSEric Joyner 	usec_delay(6000);
2528eb6488eSEric Joyner 	return (error);
2538eb6488eSEric Joyner } /* ixgbe_bp_timeout */
2548eb6488eSEric Joyner 
2558eb6488eSEric Joyner /************************************************************************
2568eb6488eSEric Joyner  * ixgbe_bp_main_on
2578eb6488eSEric Joyner  ************************************************************************/
2588eb6488eSEric Joyner static int
ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)2598eb6488eSEric Joyner ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)
2608eb6488eSEric Joyner {
261b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
262b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
2638eb6488eSEric Joyner 	int error = 0;
2648eb6488eSEric Joyner 	static int main_on = 0;
2658eb6488eSEric Joyner 
266b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
2678eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on);
2688eb6488eSEric Joyner 	main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3;
269b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
2708eb6488eSEric Joyner 	if (error)
2718eb6488eSEric Joyner 		return (error);
2728eb6488eSEric Joyner 
2738eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &main_on, 0, req);
2748eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
2758eb6488eSEric Joyner 		return (error);
2768eb6488eSEric Joyner 
2778eb6488eSEric Joyner 	/* Sanity check on the setting */
2788eb6488eSEric Joyner 	switch (main_on) {
2798eb6488eSEric Joyner 	case BYPASS_NOP:
2808eb6488eSEric Joyner 	case BYPASS_NORM:
2818eb6488eSEric Joyner 	case BYPASS_BYPASS:
2828eb6488eSEric Joyner 	case BYPASS_ISOLATE:
2838eb6488eSEric Joyner 		break;
2848eb6488eSEric Joyner 	default:
2858eb6488eSEric Joyner 		return (EINVAL);
2868eb6488eSEric Joyner 	}
2878eb6488eSEric Joyner 
2888eb6488eSEric Joyner 	/* Set the new state */
289b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
2908eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
2918eb6488eSEric Joyner 	    BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT);
292b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
2938eb6488eSEric Joyner 	usec_delay(6000);
2948eb6488eSEric Joyner 	return (error);
2958eb6488eSEric Joyner } /* ixgbe_bp_main_on */
2968eb6488eSEric Joyner 
2978eb6488eSEric Joyner /************************************************************************
2988eb6488eSEric Joyner  * ixgbe_bp_main_off
2998eb6488eSEric Joyner  ************************************************************************/
3008eb6488eSEric Joyner static int
ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)3018eb6488eSEric Joyner ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)
3028eb6488eSEric Joyner {
303b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
304b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3058eb6488eSEric Joyner 	int error = 0;
3068eb6488eSEric Joyner 	static int main_off = 0;
3078eb6488eSEric Joyner 
308b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
3098eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off);
310b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
3118eb6488eSEric Joyner 	if (error)
3128eb6488eSEric Joyner 		return (error);
3138eb6488eSEric Joyner 	main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3;
3148eb6488eSEric Joyner 
3158eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &main_off, 0, req);
3168eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
3178eb6488eSEric Joyner 		return (error);
3188eb6488eSEric Joyner 
3198eb6488eSEric Joyner 	/* Sanity check on the setting */
3208eb6488eSEric Joyner 	switch (main_off) {
3218eb6488eSEric Joyner 	case BYPASS_NOP:
3228eb6488eSEric Joyner 	case BYPASS_NORM:
3238eb6488eSEric Joyner 	case BYPASS_BYPASS:
3248eb6488eSEric Joyner 	case BYPASS_ISOLATE:
3258eb6488eSEric Joyner 		break;
3268eb6488eSEric Joyner 	default:
3278eb6488eSEric Joyner 		return (EINVAL);
3288eb6488eSEric Joyner 	}
3298eb6488eSEric Joyner 
3308eb6488eSEric Joyner 	/* Set the new state */
331b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
3328eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
3338eb6488eSEric Joyner 	    BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT);
334b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
3358eb6488eSEric Joyner 	usec_delay(6000);
3368eb6488eSEric Joyner 	return (error);
3378eb6488eSEric Joyner } /* ixgbe_bp_main_off */
3388eb6488eSEric Joyner 
3398eb6488eSEric Joyner /************************************************************************
3408eb6488eSEric Joyner  * ixgbe_bp_aux_on
3418eb6488eSEric Joyner  ************************************************************************/
3428eb6488eSEric Joyner static int
ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)3438eb6488eSEric Joyner ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)
3448eb6488eSEric Joyner {
345b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
346b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3478eb6488eSEric Joyner 	int error = 0;
3488eb6488eSEric Joyner 	static int aux_on = 0;
3498eb6488eSEric Joyner 
350b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
3518eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on);
352b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
3538eb6488eSEric Joyner 	if (error)
3548eb6488eSEric Joyner 		return (error);
3558eb6488eSEric Joyner 	aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3;
3568eb6488eSEric Joyner 
3578eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &aux_on, 0, req);
3588eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
3598eb6488eSEric Joyner 		return (error);
3608eb6488eSEric Joyner 
3618eb6488eSEric Joyner 	/* Sanity check on the setting */
3628eb6488eSEric Joyner 	switch (aux_on) {
3638eb6488eSEric Joyner 	case BYPASS_NOP:
3648eb6488eSEric Joyner 	case BYPASS_NORM:
3658eb6488eSEric Joyner 	case BYPASS_BYPASS:
3668eb6488eSEric Joyner 	case BYPASS_ISOLATE:
3678eb6488eSEric Joyner 		break;
3688eb6488eSEric Joyner 	default:
3698eb6488eSEric Joyner 		return (EINVAL);
3708eb6488eSEric Joyner 	}
3718eb6488eSEric Joyner 
3728eb6488eSEric Joyner 	/* Set the new state */
373b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
3748eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
3758eb6488eSEric Joyner 	    BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT);
376b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
3778eb6488eSEric Joyner 	usec_delay(6000);
3788eb6488eSEric Joyner 	return (error);
3798eb6488eSEric Joyner } /* ixgbe_bp_aux_on */
3808eb6488eSEric Joyner 
3818eb6488eSEric Joyner /************************************************************************
3828eb6488eSEric Joyner  * ixgbe_bp_aux_off
3838eb6488eSEric Joyner  ************************************************************************/
3848eb6488eSEric Joyner static int
ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)3858eb6488eSEric Joyner ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)
3868eb6488eSEric Joyner {
387b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
388b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3898eb6488eSEric Joyner 	int error = 0;
3908eb6488eSEric Joyner 	static int aux_off = 0;
3918eb6488eSEric Joyner 
392b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
3938eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off);
394b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
3958eb6488eSEric Joyner 	if (error)
3968eb6488eSEric Joyner 		return (error);
3978eb6488eSEric Joyner 	aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3;
3988eb6488eSEric Joyner 
3998eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &aux_off, 0, req);
4008eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
4018eb6488eSEric Joyner 		return (error);
4028eb6488eSEric Joyner 
4038eb6488eSEric Joyner 	/* Sanity check on the setting */
4048eb6488eSEric Joyner 	switch (aux_off) {
4058eb6488eSEric Joyner 	case BYPASS_NOP:
4068eb6488eSEric Joyner 	case BYPASS_NORM:
4078eb6488eSEric Joyner 	case BYPASS_BYPASS:
4088eb6488eSEric Joyner 	case BYPASS_ISOLATE:
4098eb6488eSEric Joyner 		break;
4108eb6488eSEric Joyner 	default:
4118eb6488eSEric Joyner 		return (EINVAL);
4128eb6488eSEric Joyner 	}
4138eb6488eSEric Joyner 
4148eb6488eSEric Joyner 	/* Set the new state */
415b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
4168eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
4178eb6488eSEric Joyner 	    BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT);
418b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
4198eb6488eSEric Joyner 	usec_delay(6000);
4208eb6488eSEric Joyner 	return (error);
4218eb6488eSEric Joyner } /* ixgbe_bp_aux_off */
4228eb6488eSEric Joyner 
4238eb6488eSEric Joyner /************************************************************************
4248eb6488eSEric Joyner  * ixgbe_bp_wd_set - Set the Watchdog timer value
4258eb6488eSEric Joyner  *
4268eb6488eSEric Joyner  *   Valid settings are:
4278eb6488eSEric Joyner  *	- 0 will disable the watchdog
4288eb6488eSEric Joyner  *	- 1, 2, 3, 4, 8, 16, 32
4298eb6488eSEric Joyner  *	- anything else is invalid and will be ignored
4308eb6488eSEric Joyner  ************************************************************************/
4318eb6488eSEric Joyner static int
ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)4328eb6488eSEric Joyner ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)
4338eb6488eSEric Joyner {
434b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
435b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
4368eb6488eSEric Joyner 	int error, tmp;
4378eb6488eSEric Joyner 	static int timeout = 0;
438c19c7afeSEric Joyner 	u32 mask, arg;
4398eb6488eSEric Joyner 
4408eb6488eSEric Joyner 	/* Get the current hardware value */
441b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
4428eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp);
443b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
4448eb6488eSEric Joyner 	if (error)
4458eb6488eSEric Joyner 		return (error);
4468eb6488eSEric Joyner 	/*
4478eb6488eSEric Joyner 	 * If armed keep the displayed value,
4488eb6488eSEric Joyner 	 * else change the display to zero.
4498eb6488eSEric Joyner 	 */
4508eb6488eSEric Joyner 	if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0)
4518eb6488eSEric Joyner 		timeout = 0;
4528eb6488eSEric Joyner 
4538eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &timeout, 0, req);
4548eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
4558eb6488eSEric Joyner 		return (error);
4568eb6488eSEric Joyner 
457c19c7afeSEric Joyner 	arg = 0x1 << BYPASS_WDT_ENABLE_SHIFT;
458c19c7afeSEric Joyner 	mask = BYPASS_WDT_ENABLE_M | BYPASS_WDT_VALUE_M;
4598eb6488eSEric Joyner 	switch (timeout) {
4608eb6488eSEric Joyner 	case 0: /* disables the timer */
461c19c7afeSEric Joyner 		arg = BYPASS_PAGE_CTL0;
462c19c7afeSEric Joyner 		mask = BYPASS_WDT_ENABLE_M;
4638eb6488eSEric Joyner 		break;
4648eb6488eSEric Joyner 	case 1:
465c19c7afeSEric Joyner 		arg |= BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT;
4668eb6488eSEric Joyner 		break;
4678eb6488eSEric Joyner 	case 2:
468c19c7afeSEric Joyner 		arg |= BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT;
4698eb6488eSEric Joyner 		break;
4708eb6488eSEric Joyner 	case 3:
471c19c7afeSEric Joyner 		arg |= BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT;
4728eb6488eSEric Joyner 		break;
4738eb6488eSEric Joyner 	case 4:
474c19c7afeSEric Joyner 		arg |= BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT;
4758eb6488eSEric Joyner 		break;
4768eb6488eSEric Joyner 	case 8:
477c19c7afeSEric Joyner 		arg |= BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT;
4788eb6488eSEric Joyner 		break;
4798eb6488eSEric Joyner 	case 16:
480c19c7afeSEric Joyner 		arg |= BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT;
4818eb6488eSEric Joyner 		break;
4828eb6488eSEric Joyner 	case 32:
483c19c7afeSEric Joyner 		arg |= BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT;
4848eb6488eSEric Joyner 		break;
4858eb6488eSEric Joyner 	default:
4868eb6488eSEric Joyner 		return (EINVAL);
4878eb6488eSEric Joyner 	}
488c19c7afeSEric Joyner 
4898eb6488eSEric Joyner 	/* Set the new watchdog */
490b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
4918eb6488eSEric Joyner 	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg);
492b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
4938eb6488eSEric Joyner 
4948eb6488eSEric Joyner 	return (error);
4958eb6488eSEric Joyner } /* ixgbe_bp_wd_set */
4968eb6488eSEric Joyner 
4978eb6488eSEric Joyner /************************************************************************
4988eb6488eSEric Joyner  * ixgbe_bp_wd_reset - Reset the Watchdog timer
4998eb6488eSEric Joyner  *
5008eb6488eSEric Joyner  *    To activate this it must be called with any argument.
5018eb6488eSEric Joyner  ************************************************************************/
5028eb6488eSEric Joyner static int
ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)5038eb6488eSEric Joyner ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)
5048eb6488eSEric Joyner {
505b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
506b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
5078eb6488eSEric Joyner 	u32 sec, year;
5088eb6488eSEric Joyner 	int cmd, count = 0, error = 0;
5098eb6488eSEric Joyner 	int reset_wd = 0;
5108eb6488eSEric Joyner 
5118eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &reset_wd, 0, req);
5128eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
5138eb6488eSEric Joyner 		return (error);
5148eb6488eSEric Joyner 
5158eb6488eSEric Joyner 	cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
5168eb6488eSEric Joyner 
5178eb6488eSEric Joyner 	/* Resync the FW time while writing to CTL1 anyway */
5188eb6488eSEric Joyner 	ixgbe_get_bypass_time(&year, &sec);
5198eb6488eSEric Joyner 
5208eb6488eSEric Joyner 	cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
5218eb6488eSEric Joyner 	cmd |= BYPASS_CTL1_OFFTRST;
5228eb6488eSEric Joyner 
523b1d5caf3SKevin Bowling 	ixgbe_bypass_wd_mutex_enter(sc);
5248eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd);
5258eb6488eSEric Joyner 
5268eb6488eSEric Joyner 	/* Read until it matches what we wrote, or we time out */
5278eb6488eSEric Joyner 	do {
5288eb6488eSEric Joyner 		if (count++ > 10) {
5298eb6488eSEric Joyner 			error = IXGBE_BYPASS_FW_WRITE_FAILURE;
5308eb6488eSEric Joyner 			break;
5318eb6488eSEric Joyner 		}
532c41a0eeeSKevin Bowling 		if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) {
5338eb6488eSEric Joyner 			error = IXGBE_ERR_INVALID_ARGUMENT;
5348eb6488eSEric Joyner 			break;
5358eb6488eSEric Joyner 		}
5368eb6488eSEric Joyner 	} while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd));
5378eb6488eSEric Joyner 
5388eb6488eSEric Joyner 	reset_wd = 0;
539b1d5caf3SKevin Bowling 	ixgbe_bypass_wd_mutex_clear(sc);
5408eb6488eSEric Joyner 	return (error);
5418eb6488eSEric Joyner } /* ixgbe_bp_wd_reset */
5428eb6488eSEric Joyner 
5438eb6488eSEric Joyner /************************************************************************
5448eb6488eSEric Joyner  * ixgbe_bp_log - Display the bypass log
5458eb6488eSEric Joyner  *
5468eb6488eSEric Joyner  *   You must pass a non-zero arg to sysctl
5478eb6488eSEric Joyner  ************************************************************************/
5488eb6488eSEric Joyner static int
ixgbe_bp_log(SYSCTL_HANDLER_ARGS)5498eb6488eSEric Joyner ixgbe_bp_log(SYSCTL_HANDLER_ARGS)
5508eb6488eSEric Joyner {
551b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
552b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
5538eb6488eSEric Joyner 	u32 cmd, base, head;
5548eb6488eSEric Joyner 	u32 log_off, count = 0;
5558eb6488eSEric Joyner 	static int status = 0;
5568eb6488eSEric Joyner 	u8 data;
5578eb6488eSEric Joyner 	struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS];
5588eb6488eSEric Joyner 	int i, error = 0;
5598eb6488eSEric Joyner 
5608eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &status, 0, req);
5618eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
5628eb6488eSEric Joyner 		return (error);
5638eb6488eSEric Joyner 
5648eb6488eSEric Joyner 	/* Keep the log display single-threaded */
565b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.log, 0, 1) == 0)
5668eb6488eSEric Joyner 		usec_delay(3000);
5678eb6488eSEric Joyner 
568b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
5698eb6488eSEric Joyner 
5708eb6488eSEric Joyner 	/* Find Current head of the log eeprom offset */
5718eb6488eSEric Joyner 	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
5728eb6488eSEric Joyner 	cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
5738eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, cmd, &status);
5748eb6488eSEric Joyner 	if (error)
5758eb6488eSEric Joyner 		goto unlock_err;
5768eb6488eSEric Joyner 
5778eb6488eSEric Joyner 	/* wait for the write to stick */
5788eb6488eSEric Joyner 	msec_delay(100);
5798eb6488eSEric Joyner 
5808eb6488eSEric Joyner 	/* Now read the results */
5818eb6488eSEric Joyner 	cmd &= ~BYPASS_WE;
5828eb6488eSEric Joyner 	error = hw->mac.ops.bypass_rw(hw, cmd, &status);
5838eb6488eSEric Joyner 	if (error)
5848eb6488eSEric Joyner 		goto unlock_err;
5858eb6488eSEric Joyner 
586b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
5878eb6488eSEric Joyner 
5888eb6488eSEric Joyner 	base = status & BYPASS_CTL2_DATA_M;
5898eb6488eSEric Joyner 	head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT;
5908eb6488eSEric Joyner 
5918eb6488eSEric Joyner 	/* address of the first log */
5928eb6488eSEric Joyner 	log_off = base + (head * 5);
5938eb6488eSEric Joyner 
5948eb6488eSEric Joyner 	/* extract all the log entries */
5958eb6488eSEric Joyner 	while (count < BYPASS_MAX_LOGS) {
5968eb6488eSEric Joyner 		eeprom[count].logs = 0;
5978eb6488eSEric Joyner 		eeprom[count].actions = 0;
5988eb6488eSEric Joyner 
5998eb6488eSEric Joyner 		/* Log 5 bytes store in on u32 and a u8 */
6008eb6488eSEric Joyner 		for (i = 0; i < 4; i++) {
601b1d5caf3SKevin Bowling 			ixgbe_bypass_mutex_enter(sc);
6028eb6488eSEric Joyner 			error = hw->mac.ops.bypass_rd_eep(hw, log_off + i,
6038eb6488eSEric Joyner 			    &data);
604b1d5caf3SKevin Bowling 			ixgbe_bypass_mutex_clear(sc);
6058eb6488eSEric Joyner 			if (error)
606c19c7afeSEric Joyner 				return (EINVAL);
6078eb6488eSEric Joyner 			eeprom[count].logs += data << (8 * i);
6088eb6488eSEric Joyner 		}
6098eb6488eSEric Joyner 
610b1d5caf3SKevin Bowling 		ixgbe_bypass_mutex_enter(sc);
6118eb6488eSEric Joyner 		error = hw->mac.ops.bypass_rd_eep(hw,
6128eb6488eSEric Joyner 		    log_off + i, &eeprom[count].actions);
613b1d5caf3SKevin Bowling 		ixgbe_bypass_mutex_clear(sc);
6148eb6488eSEric Joyner 		if (error)
615c19c7afeSEric Joyner 			return (EINVAL);
6168eb6488eSEric Joyner 
6178eb6488eSEric Joyner 		/* Quit if not a unread log */
6188eb6488eSEric Joyner 		if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M))
6198eb6488eSEric Joyner 			break;
6208eb6488eSEric Joyner 		/*
6218eb6488eSEric Joyner 		 * Log looks good so store the address where it's
6228eb6488eSEric Joyner 		 * Unread Log bit is so we can clear it after safely
6238eb6488eSEric Joyner 		 * pulling out all of the log data.
6248eb6488eSEric Joyner 		 */
6258eb6488eSEric Joyner 		eeprom[count].clear_off = log_off;
6268eb6488eSEric Joyner 
6278eb6488eSEric Joyner 		count++;
6288eb6488eSEric Joyner 		head = head ? head - 1 : BYPASS_MAX_LOGS;
6298eb6488eSEric Joyner 		log_off = base + (head * 5);
6308eb6488eSEric Joyner 	}
6318eb6488eSEric Joyner 
6328eb6488eSEric Joyner 	/* reverse order (oldest first) for output */
6338eb6488eSEric Joyner 	while (count--) {
6348eb6488eSEric Joyner 		int year;
6358eb6488eSEric Joyner 		u32 mon, days, hours, min, sec;
6368eb6488eSEric Joyner 		u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M;
6378eb6488eSEric Joyner 		u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >>
6388eb6488eSEric Joyner 		    BYPASS_LOG_EVENT_SHIFT;
6398eb6488eSEric Joyner 		u8 action =  eeprom[count].actions & BYPASS_LOG_ACTION_M;
6408eb6488eSEric Joyner 		u16 day_mon[2][13] = {
641*c58d34ddSKevin Bowling 			{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
642*c58d34ddSKevin Bowling 			    334, 365},
643*c58d34ddSKevin Bowling 			{0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305,
644*c58d34ddSKevin Bowling 			    335, 366}
6458eb6488eSEric Joyner 		};
6468eb6488eSEric Joyner 		char *event_str[] = {"unknown", "main on", "aux on",
6478eb6488eSEric Joyner 		    "main off", "aux off", "WDT", "user" };
648*c58d34ddSKevin Bowling 		char *action_str[] =
649*c58d34ddSKevin Bowling 		    {"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;
671b1d5caf3SKevin Bowling 		device_printf(sc->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 
680b1d5caf3SKevin Bowling 		ixgbe_bypass_mutex_enter(sc);
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 
687b1d5caf3SKevin Bowling 		ixgbe_bypass_mutex_clear(sc);
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 */
695b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->bypass.log, 1, 0) == 0)
6968eb6488eSEric Joyner 		usec_delay(3000);
6978eb6488eSEric Joyner 	return (error);
6988eb6488eSEric Joyner 
6998eb6488eSEric Joyner unlock_err:
700b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
7018eb6488eSEric Joyner 	status = 0; /* reset */
702b1d5caf3SKevin Bowling 	while (atomic_cmpset_int(&sc->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
ixgbe_bypass_init(struct ixgbe_softc * sc)714b1d5caf3SKevin Bowling ixgbe_bypass_init(struct ixgbe_softc *sc)
7158eb6488eSEric Joyner {
716b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
717b1d5caf3SKevin Bowling 	device_t dev = sc->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 
722b1d5caf3SKevin Bowling 	if (!(sc->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 
728*c58d34ddSKevin Bowling 	mask = BYPASS_CTL1_TIME_M |
729*c58d34ddSKevin Bowling 	    BYPASS_CTL1_VALID_M |
730*c58d34ddSKevin Bowling 	    BYPASS_CTL1_OFFTRST_M;
7318eb6488eSEric Joyner 
732*c58d34ddSKevin Bowling 	value = (sec & BYPASS_CTL1_TIME_M) |
733*c58d34ddSKevin Bowling 	    BYPASS_CTL1_VALID |
734*c58d34ddSKevin Bowling 	    BYPASS_CTL1_OFFTRST;
7358eb6488eSEric Joyner 
736b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_enter(sc);
7378eb6488eSEric Joyner 	hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
738b1d5caf3SKevin Bowling 	ixgbe_bypass_mutex_clear(sc);
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)),
749c41a0eeeSKevin Bowling 	    OID_AUTO, "bypass_log", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
750b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_log, "I", "Bypass Log");
7518eb6488eSEric Joyner 
7528eb6488eSEric Joyner 	/* All other setting are hung from the 'bypass' node */
7538eb6488eSEric Joyner 	bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
7548eb6488eSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
75520b91f0aSPawel Biernacki 	    OID_AUTO, "bypass", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Bypass");
7568eb6488eSEric Joyner 
7578eb6488eSEric Joyner 	bp_list = SYSCTL_CHILDREN(bp_node);
7588eb6488eSEric Joyner 
7598eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
760c41a0eeeSKevin Bowling 	    OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD,
761b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_version, "I", "Bypass Version");
7628eb6488eSEric Joyner 
7638eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
764c41a0eeeSKevin Bowling 	    OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW,
765b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_set_state, "I", "Bypass State");
7668eb6488eSEric Joyner 
7678eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
768c41a0eeeSKevin Bowling 	    OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW,
769b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_timeout, "I", "Bypass Timeout");
7708eb6488eSEric Joyner 
7718eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
772c41a0eeeSKevin Bowling 	    OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW,
773b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_main_on, "I", "Bypass Main On");
7748eb6488eSEric Joyner 
7758eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
776c41a0eeeSKevin Bowling 	    OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW,
777b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_main_off, "I", "Bypass Main Off");
7788eb6488eSEric Joyner 
7798eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
780c41a0eeeSKevin Bowling 	    OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW,
781b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On");
7828eb6488eSEric Joyner 
7838eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
784c41a0eeeSKevin Bowling 	    OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW,
785b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off");
7868eb6488eSEric Joyner 
7878eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
788c41a0eeeSKevin Bowling 	    OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW,
789b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog");
7908eb6488eSEric Joyner 
7918eb6488eSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
792c41a0eeeSKevin Bowling 	    OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR,
793b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset");
7948eb6488eSEric Joyner 
795b1d5caf3SKevin Bowling 	sc->feat_en |= IXGBE_FEATURE_BYPASS;
7968eb6488eSEric Joyner } /* ixgbe_bypass_init */
7978eb6488eSEric Joyner 
798