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
ixgbe_bypass_mutex_enter(struct adapter * adapter)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
ixgbe_bypass_mutex_clear(struct adapter * adapter)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
ixgbe_bypass_wd_mutex_enter(struct adapter * adapter)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
ixgbe_bypass_wd_mutex_clear(struct adapter * adapter)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
ixgbe_get_bypass_time(u32 * year,u32 * sec)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
ixgbe_bp_version(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)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
ixgbe_bp_log(SYSCTL_HANDLER_ARGS)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
ixgbe_bypass_init(struct adapter * adapter)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
809