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