The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ixgbe/if_bypass.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 ixgbe_softc *sc)
   47 {
   48         while (atomic_cmpset_int(&sc->bypass.low, 0, 1) == 0)
   49                 usec_delay(3000);
   50         while (atomic_cmpset_int(&sc->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 ixgbe_softc *sc)
   60 {
   61         while (atomic_cmpset_int(&sc->bypass.high, 1, 0) == 0)
   62                 usec_delay(6000);
   63         while (atomic_cmpset_int(&sc->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 ixgbe_softc *sc)
   75 {
   76         while (atomic_cmpset_int(&sc->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 ixgbe_softc *sc)
   86 {
   87         while (atomic_cmpset_int(&sc->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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  119         struct ixgbe_hw *hw = &sc->hw;
  120         int             error = 0;
  121         static int      version = 0;
  122         u32             cmd;
  123 
  124         ixgbe_bypass_mutex_enter(sc);
  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(sc);
  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(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  159         struct ixgbe_hw *hw = &sc->hw;
  160         int             error = 0;
  161         static int      state = 0;
  162 
  163         /* Get the current state */
  164         ixgbe_bypass_mutex_enter(sc);
  165         error = hw->mac.ops.bypass_rw(hw,
  166             BYPASS_PAGE_CTL0, &state);
  167         ixgbe_bypass_mutex_clear(sc);
  168         if (error != 0)
  169                 return (error);
  170         state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3;
  171 
  172         error = sysctl_handle_int(oidp, &state, 0, req);
  173         if ((error != 0) || (req->newptr == NULL))
  174                 return (error);
  175 
  176         /* Sanity check new state */
  177         switch (state) {
  178         case BYPASS_NORM:
  179         case BYPASS_BYPASS:
  180         case BYPASS_ISOLATE:
  181                 break;
  182         default:
  183                 return (EINVAL);
  184         }
  185         ixgbe_bypass_mutex_enter(sc);
  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(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  221         struct ixgbe_hw *hw = &sc->hw;
  222         int             error = 0;
  223         static int      timeout = 0;
  224 
  225         /* Get the current value */
  226         ixgbe_bypass_mutex_enter(sc);
  227         error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout);
  228         ixgbe_bypass_mutex_clear(sc);
  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(sc);
  250         error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
  251             BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT);
  252         ixgbe_bypass_mutex_clear(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  264         struct ixgbe_hw *hw = &sc->hw;
  265         int             error = 0;
  266         static int      main_on = 0;
  267 
  268         ixgbe_bypass_mutex_enter(sc);
  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(sc);
  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(sc);
  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(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  306         struct ixgbe_hw *hw = &sc->hw;
  307         int             error = 0;
  308         static int      main_off = 0;
  309 
  310         ixgbe_bypass_mutex_enter(sc);
  311         error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off);
  312         ixgbe_bypass_mutex_clear(sc);
  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(sc);
  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(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  348         struct ixgbe_hw *hw = &sc->hw;
  349         int             error = 0;
  350         static int      aux_on = 0;
  351 
  352         ixgbe_bypass_mutex_enter(sc);
  353         error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on);
  354         ixgbe_bypass_mutex_clear(sc);
  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(sc);
  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(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  390         struct ixgbe_hw *hw = &sc->hw;
  391         int             error = 0;
  392         static int      aux_off = 0;
  393 
  394         ixgbe_bypass_mutex_enter(sc);
  395         error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off);
  396         ixgbe_bypass_mutex_clear(sc);
  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(sc);
  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(sc);
  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 ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  437         struct ixgbe_hw *hw = &sc->hw;
  438         int             error, tmp;
  439         static int      timeout = 0;
  440         u32             mask, arg;
  441 
  442         /* Get the current hardware value */
  443         ixgbe_bypass_mutex_enter(sc);
  444         error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp);
  445         ixgbe_bypass_mutex_clear(sc);
  446         if (error)
  447                 return (error);
  448         /*
  449          * If armed keep the displayed value,
  450          * else change the display to zero.
  451          */
  452         if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0)
  453                 timeout = 0;
  454 
  455         error = sysctl_handle_int(oidp, &timeout, 0, req);
  456         if ((error) || (req->newptr == NULL))
  457                 return (error);
  458 
  459         arg = 0x1 << BYPASS_WDT_ENABLE_SHIFT;
  460         mask = BYPASS_WDT_ENABLE_M | BYPASS_WDT_VALUE_M;
  461         switch (timeout) {
  462         case 0: /* disables the timer */
  463                 arg = BYPASS_PAGE_CTL0;
  464                 mask = BYPASS_WDT_ENABLE_M;
  465                 break;
  466         case 1:
  467                 arg |= BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT;
  468                 break;
  469         case 2:
  470                 arg |= BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT;
  471                 break;
  472         case 3:
  473                 arg |= BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT;
  474                 break;
  475         case 4:
  476                 arg |= BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT;
  477                 break;
  478         case 8:
  479                 arg |= BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT;
  480                 break;
  481         case 16:
  482                 arg |= BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT;
  483                 break;
  484         case 32:
  485                 arg |= BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT;
  486                 break;
  487         default:
  488                 return (EINVAL);
  489         }
  490 
  491         /* Set the new watchdog */
  492         ixgbe_bypass_mutex_enter(sc);
  493         error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg);
  494         ixgbe_bypass_mutex_clear(sc);
  495 
  496         return (error);
  497 } /* ixgbe_bp_wd_set */
  498 
  499 /************************************************************************
  500  * ixgbe_bp_wd_reset - Reset the Watchdog timer
  501  *
  502  *    To activate this it must be called with any argument.
  503  ************************************************************************/
  504 static int
  505 ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)
  506 {
  507         struct ixgbe_softc  *sc = (struct ixgbe_softc *) arg1;
  508         struct ixgbe_hw *hw = &sc->hw;
  509         u32             sec, year;
  510         int             cmd, count = 0, error = 0;
  511         int             reset_wd = 0;
  512 
  513         error = sysctl_handle_int(oidp, &reset_wd, 0, req);
  514         if ((error) || (req->newptr == NULL))
  515                 return (error);
  516 
  517         cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
  518 
  519         /* Resync the FW time while writing to CTL1 anyway */
  520         ixgbe_get_bypass_time(&year, &sec);
  521 
  522         cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
  523         cmd |= BYPASS_CTL1_OFFTRST;
  524 
  525         ixgbe_bypass_wd_mutex_enter(sc);
  526         error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd);
  527 
  528         /* Read until it matches what we wrote, or we time out */
  529         do {
  530                 if (count++ > 10) {
  531                         error = IXGBE_BYPASS_FW_WRITE_FAILURE;
  532                         break;
  533                 }
  534                 error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd);
  535                 if (error != 0) {
  536                         error = IXGBE_ERR_INVALID_ARGUMENT;
  537                         break;
  538                 }
  539         } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd));
  540 
  541         reset_wd = 0;
  542         ixgbe_bypass_wd_mutex_clear(sc);
  543         return (error);
  544 } /* ixgbe_bp_wd_reset */
  545 
  546 /************************************************************************
  547  * ixgbe_bp_log - Display the bypass log
  548  *
  549  *   You must pass a non-zero arg to sysctl
  550  ************************************************************************/
  551 static int
  552 ixgbe_bp_log(SYSCTL_HANDLER_ARGS)
  553 {
  554         struct ixgbe_softc             *sc = (struct ixgbe_softc *) arg1;
  555         struct ixgbe_hw            *hw = &sc->hw;
  556         u32                        cmd, base, head;
  557         u32                        log_off, count = 0;
  558         static int                 status = 0;
  559         u8                         data;
  560         struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS];
  561         int                        i, error = 0;
  562 
  563         error = sysctl_handle_int(oidp, &status, 0, req);
  564         if ((error) || (req->newptr == NULL))
  565                 return (error);
  566 
  567         /* Keep the log display single-threaded */
  568         while (atomic_cmpset_int(&sc->bypass.log, 0, 1) == 0)
  569                 usec_delay(3000);
  570 
  571         ixgbe_bypass_mutex_enter(sc);
  572 
  573         /* Find Current head of the log eeprom offset */
  574         cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
  575         cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
  576         error = hw->mac.ops.bypass_rw(hw, cmd, &status);
  577         if (error)
  578                 goto unlock_err;
  579 
  580         /* wait for the write to stick */
  581         msec_delay(100);
  582 
  583         /* Now read the results */
  584         cmd &= ~BYPASS_WE;
  585         error = hw->mac.ops.bypass_rw(hw, cmd, &status);
  586         if (error)
  587                 goto unlock_err;
  588 
  589         ixgbe_bypass_mutex_clear(sc);
  590 
  591         base = status & BYPASS_CTL2_DATA_M;
  592         head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT;
  593 
  594         /* address of the first log */
  595         log_off = base + (head * 5);
  596 
  597         /* extract all the log entries */
  598         while (count < BYPASS_MAX_LOGS) {
  599                 eeprom[count].logs = 0;
  600                 eeprom[count].actions = 0;
  601 
  602                 /* Log 5 bytes store in on u32 and a u8 */
  603                 for (i = 0; i < 4; i++) {
  604                         ixgbe_bypass_mutex_enter(sc);
  605                         error = hw->mac.ops.bypass_rd_eep(hw, log_off + i,
  606                             &data);
  607                         ixgbe_bypass_mutex_clear(sc);
  608                         if (error)
  609                                 return (EINVAL);
  610                         eeprom[count].logs += data << (8 * i);
  611                 }
  612 
  613                 ixgbe_bypass_mutex_enter(sc);
  614                 error = hw->mac.ops.bypass_rd_eep(hw,
  615                     log_off + i, &eeprom[count].actions);
  616                 ixgbe_bypass_mutex_clear(sc);
  617                 if (error)
  618                         return (EINVAL);
  619 
  620                 /* Quit if not a unread log */
  621                 if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M))
  622                         break;
  623                 /*
  624                  * Log looks good so store the address where it's
  625                  * Unread Log bit is so we can clear it after safely
  626                  * pulling out all of the log data.
  627                  */
  628                 eeprom[count].clear_off = log_off;
  629 
  630                 count++;
  631                 head = head ? head - 1 : BYPASS_MAX_LOGS;
  632                 log_off = base + (head * 5);
  633         }
  634 
  635         /* reverse order (oldest first) for output */
  636         while (count--) {
  637                 int year;
  638                 u32 mon, days, hours, min, sec;
  639                 u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M;
  640                 u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >>
  641                     BYPASS_LOG_EVENT_SHIFT;
  642                 u8 action =  eeprom[count].actions & BYPASS_LOG_ACTION_M;
  643                 u16 day_mon[2][13] = {
  644                   {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
  645                   {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
  646                 };
  647                 char *event_str[] = {"unknown", "main on", "aux on",
  648                     "main off", "aux off", "WDT", "user" };
  649                 char *action_str[] = {"ignore", "normal", "bypass", "isolate",};
  650 
  651                 /* verify vaild data  1 - 6 */
  652                 if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR)
  653                         event = 0;
  654 
  655                 /*
  656                  * time is in sec's this year, so convert to something
  657                  * printable.
  658                  */
  659                 ixgbe_get_bypass_time(&year, &sec);
  660                 days = time / SEC_PER_DAY;
  661                 for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--)
  662                         continue;
  663                 mon = i + 1;    /* display month as 1-12 */
  664                 time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY);
  665                 days = (time / SEC_PER_DAY) + 1;  /* first day is 1 */
  666                 time %= SEC_PER_DAY;
  667                 hours = time / (60 * 60);
  668                 time %= (60 * 60);
  669                 min = time / 60;
  670                 sec = time % 60;
  671                 device_printf(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
  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",
  750             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  751             sc, 0, ixgbe_bp_log, "I", "Bypass Log");
  752 
  753         /* All other setting are hung from the 'bypass' node */
  754         bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
  755             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  756             OID_AUTO, "bypass", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Bypass");
  757 
  758         bp_list = SYSCTL_CHILDREN(bp_node);
  759 
  760         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  761             OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
  762             sc, 0, ixgbe_bp_version, "I", "Bypass Version");
  763 
  764         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  765             OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  766             sc, 0, ixgbe_bp_set_state, "I", "Bypass State");
  767 
  768         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  769             OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  770             sc, 0, ixgbe_bp_timeout, "I", "Bypass Timeout");
  771 
  772         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  773             OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  774             sc, 0, ixgbe_bp_main_on, "I", "Bypass Main On");
  775 
  776         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  777             OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  778             sc, 0, ixgbe_bp_main_off, "I", "Bypass Main Off");
  779 
  780         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  781             OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  782             sc, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On");
  783 
  784         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  785             OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  786             sc, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off");
  787 
  788         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  789             OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  790             sc, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog");
  791 
  792         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
  793             OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
  794             sc, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset");
  795 
  796         sc->feat_en |= IXGBE_FEATURE_BYPASS;
  797 } /* ixgbe_bypass_init */
  798 

Cache object: f1673f54788f0a68a809eeb9f9ce6390


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.