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