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