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
ixgbe_bypass_mutex_enter(struct ixgbe_softc * sc)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
ixgbe_bypass_mutex_clear(struct ixgbe_softc * sc)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
ixgbe_bypass_wd_mutex_enter(struct ixgbe_softc * sc)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
ixgbe_bypass_wd_mutex_clear(struct ixgbe_softc * sc)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
ixgbe_get_bypass_time(u32 * year,u32 * sec)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(¤t);
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
ixgbe_bp_version(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS)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, BYPASS_PAGE_CTL0, &state);
165 ixgbe_bypass_mutex_clear(sc);
166 if (error != 0)
167 return (error);
168 state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3;
169
170 error = sysctl_handle_int(oidp, &state, 0, req);
171 if ((error != 0) || (req->newptr == NULL))
172 return (error);
173
174 /* Sanity check new state */
175 switch (state) {
176 case BYPASS_NORM:
177 case BYPASS_BYPASS:
178 case BYPASS_ISOLATE:
179 break;
180 default:
181 return (EINVAL);
182 }
183 ixgbe_bypass_mutex_enter(sc);
184 if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
185 BYPASS_MODE_OFF_M, state) != 0))
186 goto out;
187 /* Set AUTO back on so FW can receive events */
188 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
189 BYPASS_MODE_OFF_M, BYPASS_AUTO);
190 out:
191 ixgbe_bypass_mutex_clear(sc);
192 usec_delay(6000);
193 return (error);
194 } /* ixgbe_bp_set_state */
195
196 /************************************************************************
197 * The following routines control the operational
198 * "rules" of the feature, what behavior will occur
199 * when particular events occur.
200 * Values are:
201 * 0 - no change for the event (NOP)
202 * 1 - go to Normal operation
203 * 2 - go to Bypass operation
204 * 3 - go to Isolate operation
205 * Calling the entry with no argument just displays
206 * the current rule setting.
207 ************************************************************************/
208
209 /************************************************************************
210 * ixgbe_bp_timeout
211 *
212 * This is to set the Rule for the watchdog,
213 * not the actual watchdog timeout value.
214 ************************************************************************/
215 static int
ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)216 ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)
217 {
218 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
219 struct ixgbe_hw *hw = &sc->hw;
220 int error = 0;
221 static int timeout = 0;
222
223 /* Get the current value */
224 ixgbe_bypass_mutex_enter(sc);
225 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout);
226 ixgbe_bypass_mutex_clear(sc);
227 if (error)
228 return (error);
229 timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3;
230
231 error = sysctl_handle_int(oidp, &timeout, 0, req);
232 if ((error) || (req->newptr == NULL))
233 return (error);
234
235 /* Sanity check on the setting */
236 switch (timeout) {
237 case BYPASS_NOP:
238 case BYPASS_NORM:
239 case BYPASS_BYPASS:
240 case BYPASS_ISOLATE:
241 break;
242 default:
243 return (EINVAL);
244 }
245
246 /* Set the new state */
247 ixgbe_bypass_mutex_enter(sc);
248 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
249 BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT);
250 ixgbe_bypass_mutex_clear(sc);
251 usec_delay(6000);
252 return (error);
253 } /* ixgbe_bp_timeout */
254
255 /************************************************************************
256 * ixgbe_bp_main_on
257 ************************************************************************/
258 static int
ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)259 ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)
260 {
261 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
262 struct ixgbe_hw *hw = &sc->hw;
263 int error = 0;
264 static int main_on = 0;
265
266 ixgbe_bypass_mutex_enter(sc);
267 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on);
268 main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3;
269 ixgbe_bypass_mutex_clear(sc);
270 if (error)
271 return (error);
272
273 error = sysctl_handle_int(oidp, &main_on, 0, req);
274 if ((error) || (req->newptr == NULL))
275 return (error);
276
277 /* Sanity check on the setting */
278 switch (main_on) {
279 case BYPASS_NOP:
280 case BYPASS_NORM:
281 case BYPASS_BYPASS:
282 case BYPASS_ISOLATE:
283 break;
284 default:
285 return (EINVAL);
286 }
287
288 /* Set the new state */
289 ixgbe_bypass_mutex_enter(sc);
290 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
291 BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT);
292 ixgbe_bypass_mutex_clear(sc);
293 usec_delay(6000);
294 return (error);
295 } /* ixgbe_bp_main_on */
296
297 /************************************************************************
298 * ixgbe_bp_main_off
299 ************************************************************************/
300 static int
ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)301 ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)
302 {
303 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
304 struct ixgbe_hw *hw = &sc->hw;
305 int error = 0;
306 static int main_off = 0;
307
308 ixgbe_bypass_mutex_enter(sc);
309 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off);
310 ixgbe_bypass_mutex_clear(sc);
311 if (error)
312 return (error);
313 main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3;
314
315 error = sysctl_handle_int(oidp, &main_off, 0, req);
316 if ((error) || (req->newptr == NULL))
317 return (error);
318
319 /* Sanity check on the setting */
320 switch (main_off) {
321 case BYPASS_NOP:
322 case BYPASS_NORM:
323 case BYPASS_BYPASS:
324 case BYPASS_ISOLATE:
325 break;
326 default:
327 return (EINVAL);
328 }
329
330 /* Set the new state */
331 ixgbe_bypass_mutex_enter(sc);
332 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
333 BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT);
334 ixgbe_bypass_mutex_clear(sc);
335 usec_delay(6000);
336 return (error);
337 } /* ixgbe_bp_main_off */
338
339 /************************************************************************
340 * ixgbe_bp_aux_on
341 ************************************************************************/
342 static int
ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)343 ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)
344 {
345 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
346 struct ixgbe_hw *hw = &sc->hw;
347 int error = 0;
348 static int aux_on = 0;
349
350 ixgbe_bypass_mutex_enter(sc);
351 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on);
352 ixgbe_bypass_mutex_clear(sc);
353 if (error)
354 return (error);
355 aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3;
356
357 error = sysctl_handle_int(oidp, &aux_on, 0, req);
358 if ((error) || (req->newptr == NULL))
359 return (error);
360
361 /* Sanity check on the setting */
362 switch (aux_on) {
363 case BYPASS_NOP:
364 case BYPASS_NORM:
365 case BYPASS_BYPASS:
366 case BYPASS_ISOLATE:
367 break;
368 default:
369 return (EINVAL);
370 }
371
372 /* Set the new state */
373 ixgbe_bypass_mutex_enter(sc);
374 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
375 BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT);
376 ixgbe_bypass_mutex_clear(sc);
377 usec_delay(6000);
378 return (error);
379 } /* ixgbe_bp_aux_on */
380
381 /************************************************************************
382 * ixgbe_bp_aux_off
383 ************************************************************************/
384 static int
ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)385 ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)
386 {
387 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
388 struct ixgbe_hw *hw = &sc->hw;
389 int error = 0;
390 static int aux_off = 0;
391
392 ixgbe_bypass_mutex_enter(sc);
393 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off);
394 ixgbe_bypass_mutex_clear(sc);
395 if (error)
396 return (error);
397 aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3;
398
399 error = sysctl_handle_int(oidp, &aux_off, 0, req);
400 if ((error) || (req->newptr == NULL))
401 return (error);
402
403 /* Sanity check on the setting */
404 switch (aux_off) {
405 case BYPASS_NOP:
406 case BYPASS_NORM:
407 case BYPASS_BYPASS:
408 case BYPASS_ISOLATE:
409 break;
410 default:
411 return (EINVAL);
412 }
413
414 /* Set the new state */
415 ixgbe_bypass_mutex_enter(sc);
416 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
417 BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT);
418 ixgbe_bypass_mutex_clear(sc);
419 usec_delay(6000);
420 return (error);
421 } /* ixgbe_bp_aux_off */
422
423 /************************************************************************
424 * ixgbe_bp_wd_set - Set the Watchdog timer value
425 *
426 * Valid settings are:
427 * - 0 will disable the watchdog
428 * - 1, 2, 3, 4, 8, 16, 32
429 * - anything else is invalid and will be ignored
430 ************************************************************************/
431 static int
ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)432 ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)
433 {
434 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
435 struct ixgbe_hw *hw = &sc->hw;
436 int error, tmp;
437 static int timeout = 0;
438 u32 mask, arg;
439
440 /* Get the current hardware value */
441 ixgbe_bypass_mutex_enter(sc);
442 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp);
443 ixgbe_bypass_mutex_clear(sc);
444 if (error)
445 return (error);
446 /*
447 * If armed keep the displayed value,
448 * else change the display to zero.
449 */
450 if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0)
451 timeout = 0;
452
453 error = sysctl_handle_int(oidp, &timeout, 0, req);
454 if ((error) || (req->newptr == NULL))
455 return (error);
456
457 arg = 0x1 << BYPASS_WDT_ENABLE_SHIFT;
458 mask = BYPASS_WDT_ENABLE_M | BYPASS_WDT_VALUE_M;
459 switch (timeout) {
460 case 0: /* disables the timer */
461 arg = BYPASS_PAGE_CTL0;
462 mask = BYPASS_WDT_ENABLE_M;
463 break;
464 case 1:
465 arg |= BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT;
466 break;
467 case 2:
468 arg |= BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT;
469 break;
470 case 3:
471 arg |= BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT;
472 break;
473 case 4:
474 arg |= BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT;
475 break;
476 case 8:
477 arg |= BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT;
478 break;
479 case 16:
480 arg |= BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT;
481 break;
482 case 32:
483 arg |= BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT;
484 break;
485 default:
486 return (EINVAL);
487 }
488
489 /* Set the new watchdog */
490 ixgbe_bypass_mutex_enter(sc);
491 error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg);
492 ixgbe_bypass_mutex_clear(sc);
493
494 return (error);
495 } /* ixgbe_bp_wd_set */
496
497 /************************************************************************
498 * ixgbe_bp_wd_reset - Reset the Watchdog timer
499 *
500 * To activate this it must be called with any argument.
501 ************************************************************************/
502 static int
ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)503 ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)
504 {
505 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
506 struct ixgbe_hw *hw = &sc->hw;
507 u32 sec, year;
508 int cmd, count = 0, error = 0;
509 int reset_wd = 0;
510
511 error = sysctl_handle_int(oidp, &reset_wd, 0, req);
512 if ((error) || (req->newptr == NULL))
513 return (error);
514
515 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
516
517 /* Resync the FW time while writing to CTL1 anyway */
518 ixgbe_get_bypass_time(&year, &sec);
519
520 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
521 cmd |= BYPASS_CTL1_OFFTRST;
522
523 ixgbe_bypass_wd_mutex_enter(sc);
524 error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd);
525
526 /* Read until it matches what we wrote, or we time out */
527 do {
528 if (count++ > 10) {
529 error = IXGBE_BYPASS_FW_WRITE_FAILURE;
530 break;
531 }
532 if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) {
533 error = IXGBE_ERR_INVALID_ARGUMENT;
534 break;
535 }
536 } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd));
537
538 reset_wd = 0;
539 ixgbe_bypass_wd_mutex_clear(sc);
540 return (error);
541 } /* ixgbe_bp_wd_reset */
542
543 /************************************************************************
544 * ixgbe_bp_log - Display the bypass log
545 *
546 * You must pass a non-zero arg to sysctl
547 ************************************************************************/
548 static int
ixgbe_bp_log(SYSCTL_HANDLER_ARGS)549 ixgbe_bp_log(SYSCTL_HANDLER_ARGS)
550 {
551 struct ixgbe_softc *sc = (struct ixgbe_softc *) arg1;
552 struct ixgbe_hw *hw = &sc->hw;
553 u32 cmd, base, head;
554 u32 log_off, count = 0;
555 static int status = 0;
556 u8 data;
557 struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS];
558 int i, error = 0;
559
560 error = sysctl_handle_int(oidp, &status, 0, req);
561 if ((error) || (req->newptr == NULL))
562 return (error);
563
564 /* Keep the log display single-threaded */
565 while (atomic_cmpset_int(&sc->bypass.log, 0, 1) == 0)
566 usec_delay(3000);
567
568 ixgbe_bypass_mutex_enter(sc);
569
570 /* Find Current head of the log eeprom offset */
571 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
572 cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
573 error = hw->mac.ops.bypass_rw(hw, cmd, &status);
574 if (error)
575 goto unlock_err;
576
577 /* wait for the write to stick */
578 msec_delay(100);
579
580 /* Now read the results */
581 cmd &= ~BYPASS_WE;
582 error = hw->mac.ops.bypass_rw(hw, cmd, &status);
583 if (error)
584 goto unlock_err;
585
586 ixgbe_bypass_mutex_clear(sc);
587
588 base = status & BYPASS_CTL2_DATA_M;
589 head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT;
590
591 /* address of the first log */
592 log_off = base + (head * 5);
593
594 /* extract all the log entries */
595 while (count < BYPASS_MAX_LOGS) {
596 eeprom[count].logs = 0;
597 eeprom[count].actions = 0;
598
599 /* Log 5 bytes store in on u32 and a u8 */
600 for (i = 0; i < 4; i++) {
601 ixgbe_bypass_mutex_enter(sc);
602 error = hw->mac.ops.bypass_rd_eep(hw, log_off + i,
603 &data);
604 ixgbe_bypass_mutex_clear(sc);
605 if (error)
606 return (EINVAL);
607 eeprom[count].logs += data << (8 * i);
608 }
609
610 ixgbe_bypass_mutex_enter(sc);
611 error = hw->mac.ops.bypass_rd_eep(hw,
612 log_off + i, &eeprom[count].actions);
613 ixgbe_bypass_mutex_clear(sc);
614 if (error)
615 return (EINVAL);
616
617 /* Quit if not a unread log */
618 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M))
619 break;
620 /*
621 * Log looks good so store the address where it's
622 * Unread Log bit is so we can clear it after safely
623 * pulling out all of the log data.
624 */
625 eeprom[count].clear_off = log_off;
626
627 count++;
628 head = head ? head - 1 : BYPASS_MAX_LOGS;
629 log_off = base + (head * 5);
630 }
631
632 /* reverse order (oldest first) for output */
633 while (count--) {
634 int year;
635 u32 mon, days, hours, min, sec;
636 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M;
637 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >>
638 BYPASS_LOG_EVENT_SHIFT;
639 u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M;
640 u16 day_mon[2][13] = {
641 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
642 334, 365},
643 {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305,
644 335, 366}
645 };
646 char *event_str[] = {"unknown", "main on", "aux on",
647 "main off", "aux off", "WDT", "user" };
648 char *action_str[] =
649 {"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(sc->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(sc);
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(sc);
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(&sc->bypass.log, 1, 0) == 0)
696 usec_delay(3000);
697 return (error);
698
699 unlock_err:
700 ixgbe_bypass_mutex_clear(sc);
701 status = 0; /* reset */
702 while (atomic_cmpset_int(&sc->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
ixgbe_bypass_init(struct ixgbe_softc * sc)714 ixgbe_bypass_init(struct ixgbe_softc *sc)
715 {
716 struct ixgbe_hw *hw = &sc->hw;
717 device_t dev = sc->dev;
718 struct sysctl_oid *bp_node;
719 struct sysctl_oid_list *bp_list;
720 u32 mask, value, sec, year;
721
722 if (!(sc->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(sc);
737 hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
738 ixgbe_bypass_mutex_clear(sc);
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 | CTLFLAG_MPSAFE,
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,
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,
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,
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,
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,
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,
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,
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,
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,
793 sc, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset");
794
795 sc->feat_en |= IXGBE_FEATURE_BYPASS;
796 } /* ixgbe_bypass_init */
797
798