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