]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/ixgbe/if_bypass.c
ixgbe(4): Update to 3.2.11-k
[FreeBSD/stable/10.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)
169                 return (error);
170         state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3;
171
172         error = sysctl_handle_int(oidp, &state, 0, req);
173         if ((error) || (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 = BYPASS_PAGE_CTL0;
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         mask = BYPASS_WDT_ENABLE_M;
460         switch (timeout) {
461                 case 0: /* disables the timer */
462                         break;
463                 case 1:
464                         arg = BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT;
465                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
466                         mask |= BYPASS_WDT_VALUE_M;
467                         break;
468                 case 2:
469                         arg = BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT;
470                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
471                         mask |= BYPASS_WDT_VALUE_M;
472                         break;
473                 case 3:
474                         arg = BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT;
475                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
476                         mask |= BYPASS_WDT_VALUE_M;
477                         break;
478                 case 4:
479                         arg = BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT;
480                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
481                         mask |= BYPASS_WDT_VALUE_M;
482                         break;
483                 case 8:
484                         arg = BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT;
485                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
486                         mask |= BYPASS_WDT_VALUE_M;
487                         break;
488                 case 16:
489                         arg = BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT;
490                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
491                         mask |= BYPASS_WDT_VALUE_M;
492                         break;
493                 case 32:
494                         arg = BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT;
495                         arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
496                         mask |= BYPASS_WDT_VALUE_M;
497                         break;
498                 default:
499                         return (EINVAL);
500         }
501         /* Set the new watchdog */
502         ixgbe_bypass_mutex_enter(adapter);
503         error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg);
504         ixgbe_bypass_mutex_clear(adapter);
505
506         return (error);
507 } /* ixgbe_bp_wd_set */
508
509 /************************************************************************
510  * ixgbe_bp_wd_reset - Reset the Watchdog timer
511  *
512  *    To activate this it must be called with any argument.
513  ************************************************************************/
514 static int
515 ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)
516 {
517         struct adapter  *adapter = (struct adapter *) arg1;
518         struct ixgbe_hw *hw = &adapter->hw;
519         u32             sec, year;
520         int             cmd, count = 0, error = 0;
521         int             reset_wd = 0;
522
523         error = sysctl_handle_int(oidp, &reset_wd, 0, req);
524         if ((error) || (req->newptr == NULL))
525                 return (error);
526
527         cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
528
529         /* Resync the FW time while writing to CTL1 anyway */
530         ixgbe_get_bypass_time(&year, &sec);
531
532         cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
533         cmd |= BYPASS_CTL1_OFFTRST;
534
535         ixgbe_bypass_wd_mutex_enter(adapter);
536         error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd);
537
538         /* Read until it matches what we wrote, or we time out */
539         do {
540                 if (count++ > 10) {
541                         error = IXGBE_BYPASS_FW_WRITE_FAILURE;
542                         break;
543                 }
544                 if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) {
545                         error = IXGBE_ERR_INVALID_ARGUMENT;
546                         break;
547                 }
548         } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd));
549
550         reset_wd = 0;
551         ixgbe_bypass_wd_mutex_clear(adapter);
552         return (error);
553 } /* ixgbe_bp_wd_reset */
554
555 /************************************************************************
556  * ixgbe_bp_log - Display the bypass log
557  *
558  *   You must pass a non-zero arg to sysctl
559  ************************************************************************/
560 static int
561 ixgbe_bp_log(SYSCTL_HANDLER_ARGS)
562 {
563         struct adapter             *adapter = (struct adapter *) arg1;
564         struct ixgbe_hw            *hw = &adapter->hw;
565         u32                        cmd, base, head;
566         u32                        log_off, count = 0;
567         static int                 status = 0;
568         u8                         data;
569         struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS];
570         int                        i, error = 0;
571
572         error = sysctl_handle_int(oidp, &status, 0, req);
573         if ((error) || (req->newptr == NULL))
574                 return (error);
575
576         /* Keep the log display single-threaded */
577         while (atomic_cmpset_int(&adapter->bypass.log, 0, 1) == 0)
578                 usec_delay(3000);
579
580         ixgbe_bypass_mutex_enter(adapter);
581
582         /* Find Current head of the log eeprom offset */
583         cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
584         cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
585         error = hw->mac.ops.bypass_rw(hw, cmd, &status);
586         if (error)
587                 goto unlock_err;
588
589         /* wait for the write to stick */
590         msec_delay(100);
591
592         /* Now read the results */
593         cmd &= ~BYPASS_WE;
594         error = hw->mac.ops.bypass_rw(hw, cmd, &status);
595         if (error)
596                 goto unlock_err;
597
598         ixgbe_bypass_mutex_clear(adapter);
599
600         base = status & BYPASS_CTL2_DATA_M;
601         head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT;
602
603         /* address of the first log */
604         log_off = base + (head * 5);
605
606         /* extract all the log entries */
607         while (count < BYPASS_MAX_LOGS) {
608                 eeprom[count].logs = 0;
609                 eeprom[count].actions = 0;
610
611                 /* Log 5 bytes store in on u32 and a u8 */
612                 for (i = 0; i < 4; i++) {
613                         ixgbe_bypass_mutex_enter(adapter);
614                         error = hw->mac.ops.bypass_rd_eep(hw, log_off + i,
615                             &data);
616                         ixgbe_bypass_mutex_clear(adapter);
617                         if (error)
618                                 return (-EINVAL);
619                         eeprom[count].logs += data << (8 * i);
620                 }
621
622                 ixgbe_bypass_mutex_enter(adapter);
623                 error = hw->mac.ops.bypass_rd_eep(hw,
624                     log_off + i, &eeprom[count].actions);
625                 ixgbe_bypass_mutex_clear(adapter);
626                 if (error)
627                         return (-EINVAL);
628
629                 /* Quit if not a unread log */
630                 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M))
631                         break;
632                 /*
633                  * Log looks good so store the address where it's
634                  * Unread Log bit is so we can clear it after safely
635                  * pulling out all of the log data.
636                  */
637                 eeprom[count].clear_off = log_off;
638
639                 count++;
640                 head = head ? head - 1 : BYPASS_MAX_LOGS;
641                 log_off = base + (head * 5);
642         }
643
644         /* reverse order (oldest first) for output */
645         while (count--) {
646                 int year;
647                 u32 mon, days, hours, min, sec;
648                 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M;
649                 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >>
650                     BYPASS_LOG_EVENT_SHIFT;
651                 u8 action =  eeprom[count].actions & BYPASS_LOG_ACTION_M;
652                 u16 day_mon[2][13] = {
653                   {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
654                   {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
655                 };
656                 char *event_str[] = {"unknown", "main on", "aux on",
657                     "main off", "aux off", "WDT", "user" };
658                 char *action_str[] = {"ignore", "normal", "bypass", "isolate",};
659
660                 /* verify vaild data  1 - 6 */
661                 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR)
662                         event = 0;
663
664                 /*
665                  * time is in sec's this year, so convert to something
666                  * printable.
667                  */
668                 ixgbe_get_bypass_time(&year, &sec);
669                 days = time / SEC_PER_DAY;
670                 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--)
671                         continue;
672                 mon = i + 1;    /* display month as 1-12 */
673                 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY);
674                 days = (time / SEC_PER_DAY) + 1;  /* first day is 1 */
675                 time %= SEC_PER_DAY;
676                 hours = time / (60 * 60);
677                 time %= (60 * 60);
678                 min = time / 60;
679                 sec = time % 60;
680                 device_printf(adapter->dev,
681                     "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n",
682                     mon, days, hours, min, sec, event_str[event],
683                     action_str[action]);
684                 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW;
685                 cmd |= ((eeprom[count].clear_off + 3)
686                     << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
687                 cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24);
688
689                 ixgbe_bypass_mutex_enter(adapter);
690
691                 error = hw->mac.ops.bypass_rw(hw, cmd, &status);
692
693                 /* wait for the write to stick */
694                 msec_delay(100);
695
696                 ixgbe_bypass_mutex_clear(adapter);
697
698                 if (error)
699                         return (-EINVAL);
700         }
701
702         status = 0; /* reset */
703         /* Another log command can now run */
704         while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0)
705                 usec_delay(3000);
706         return(error);
707
708 unlock_err:
709         ixgbe_bypass_mutex_clear(adapter);
710         status = 0; /* reset */
711         while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0)
712                 usec_delay(3000);
713         return (-EINVAL);
714 } /* ixgbe_bp_log */
715
716 /************************************************************************
717  * ixgbe_bypass_init - Set up infrastructure for the bypass feature
718  *
719  *   Do time and sysctl initialization here.  This feature is
720  *   only enabled for the first port of a bypass adapter.
721  ************************************************************************/
722 void
723 ixgbe_bypass_init(struct adapter *adapter)
724 {
725         struct ixgbe_hw        *hw = &adapter->hw;
726         device_t               dev = adapter->dev;
727         struct sysctl_oid      *bp_node;
728         struct sysctl_oid_list *bp_list;
729         u32                    mask, value, sec, year;
730
731         if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS))
732                 return;
733
734         /* First set up time for the hardware */
735         ixgbe_get_bypass_time(&year, &sec);
736
737         mask = BYPASS_CTL1_TIME_M
738              | BYPASS_CTL1_VALID_M
739              | BYPASS_CTL1_OFFTRST_M;
740
741         value = (sec & BYPASS_CTL1_TIME_M)
742               | BYPASS_CTL1_VALID
743               | BYPASS_CTL1_OFFTRST;
744
745         ixgbe_bypass_mutex_enter(adapter);
746         hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
747         ixgbe_bypass_mutex_clear(adapter);
748
749         /* Now set up the SYSCTL infrastructure */
750
751         /*
752          * The log routine is kept separate from the other
753          * children so a general display command like:
754          * `sysctl dev.ix.0.bypass` will not show the log.
755          */
756         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
757             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
758             OID_AUTO, "bypass_log", CTLTYPE_INT | CTLFLAG_RW,
759             adapter, 0, ixgbe_bp_log, "I", "Bypass Log");
760
761         /* All other setting are hung from the 'bypass' node */
762         bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
763             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
764             OID_AUTO, "bypass", CTLFLAG_RD, NULL, "Bypass");
765
766         bp_list = SYSCTL_CHILDREN(bp_node);
767
768         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
769             OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD,
770             adapter, 0, ixgbe_bp_version, "I", "Bypass Version");
771
772         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
773             OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW,
774             adapter, 0, ixgbe_bp_set_state, "I", "Bypass State");
775
776         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
777             OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW,
778             adapter, 0, ixgbe_bp_timeout, "I", "Bypass Timeout");
779
780         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
781             OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW,
782             adapter, 0, ixgbe_bp_main_on, "I", "Bypass Main On");
783
784         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
785             OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW,
786             adapter, 0, ixgbe_bp_main_off, "I", "Bypass Main Off");
787
788         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
789             OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW,
790             adapter, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On");
791
792         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
793             OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW,
794             adapter, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off");
795
796         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
797             OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW,
798             adapter, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog");
799
800         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
801             OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR,
802             adapter, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset");
803
804         adapter->feat_en |= IXGBE_FEATURE_BYPASS;
805
806         return;
807 } /* ixgbe_bypass_init */
808