1 /*
   2  * Copyright (c) 2012-2015 Solarflare Communications Inc.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include "efx.h"
  32 #include "efx_impl.h"
  33 
  34 #if EFSYS_OPT_HUNTINGTON
  35 
  36 #if EFSYS_OPT_BIST
  37 
  38         __checkReturn           efx_rc_t
  39 hunt_bist_enable_offline(
  40         __in                    efx_nic_t *enp)
  41 {
  42         efx_rc_t rc;
  43 
  44         if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
  45                 goto fail1;
  46 
  47         return (0);
  48 
  49 fail1:
  50         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  51 
  52         return (rc);
  53 }
  54 
  55         __checkReturn           efx_rc_t
  56 hunt_bist_start(
  57         __in                    efx_nic_t *enp,
  58         __in                    efx_bist_type_t type)
  59 {
  60         efx_rc_t rc;
  61 
  62         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
  63                 goto fail1;
  64 
  65         return (0);
  66 
  67 fail1:
  68         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  69 
  70         return (rc);
  71 }
  72 
  73         __checkReturn           efx_rc_t
  74 hunt_bist_poll(
  75         __in                    efx_nic_t *enp,
  76         __in                    efx_bist_type_t type,
  77         __out                   efx_bist_result_t *resultp,
  78         __out_opt __drv_when(count > 0, __notnull)
  79         uint32_t *value_maskp,
  80         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
  81         unsigned long *valuesp,
  82         __in                    size_t count)
  83 {
  84         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
  85         efx_mcdi_req_t req;
  86         uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
  87                             MCDI_CTL_SDU_LEN_MAX)];
  88         uint32_t value_mask = 0;
  89         uint32_t result;
  90         efx_rc_t rc;
  91         _NOTE(ARGUNUSED(type))
  92 
  93         (void) memset(payload, 0, sizeof (payload));
  94         req.emr_cmd = MC_CMD_POLL_BIST;
  95         req.emr_in_buf = payload;
  96         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
  97         req.emr_out_buf = payload;
  98         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
  99 
 100         efx_mcdi_execute(enp, &req);
 101 
 102         if (req.emr_rc != 0) {
 103                 rc = req.emr_rc;
 104                 goto fail1;
 105         }
 106 
 107         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
 108                 rc = EMSGSIZE;
 109                 goto fail2;
 110         }
 111 
 112         if (count > 0)
 113                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
 114 
 115         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
 116 
 117         if (result == MC_CMD_POLL_BIST_FAILED &&
 118             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
 119             count > EFX_BIST_MEM_ECC_FATAL) {
 120                 if (valuesp != NULL) {
 121                         valuesp[EFX_BIST_MEM_TEST] =
 122                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
 123                         valuesp[EFX_BIST_MEM_ADDR] =
 124                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
 125                         valuesp[EFX_BIST_MEM_BUS] =
 126                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
 127                         valuesp[EFX_BIST_MEM_EXPECT] =
 128                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
 129                         valuesp[EFX_BIST_MEM_ACTUAL] =
 130                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
 131                         valuesp[EFX_BIST_MEM_ECC] =
 132                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
 133                         valuesp[EFX_BIST_MEM_ECC_PARITY] =
 134                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
 135                         valuesp[EFX_BIST_MEM_ECC_FATAL] =
 136                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
 137                 }
 138                 value_mask |= (1 << EFX_BIST_MEM_TEST) |
 139                     (1 << EFX_BIST_MEM_ADDR) |
 140                     (1 << EFX_BIST_MEM_BUS) |
 141                     (1 << EFX_BIST_MEM_EXPECT) |
 142                     (1 << EFX_BIST_MEM_ACTUAL) |
 143                     (1 << EFX_BIST_MEM_ECC) |
 144                     (1 << EFX_BIST_MEM_ECC_PARITY) |
 145                     (1 << EFX_BIST_MEM_ECC_FATAL);
 146         } else if (result == MC_CMD_POLL_BIST_FAILED &&
 147             encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
 148             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
 149             count > EFX_BIST_FAULT_CODE) {
 150                 if (valuesp != NULL)
 151                         valuesp[EFX_BIST_FAULT_CODE] =
 152                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
 153                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
 154         }
 155 
 156         if (value_maskp != NULL)
 157                 *value_maskp = value_mask;
 158 
 159         EFSYS_ASSERT(resultp != NULL);
 160         if (result == MC_CMD_POLL_BIST_RUNNING)
 161                 *resultp = EFX_BIST_RESULT_RUNNING;
 162         else if (result == MC_CMD_POLL_BIST_PASSED)
 163                 *resultp = EFX_BIST_RESULT_PASSED;
 164         else
 165                 *resultp = EFX_BIST_RESULT_FAILED;
 166 
 167         return (0);
 168 
 169 fail2:
 170         EFSYS_PROBE(fail2);
 171 fail1:
 172         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 173 
 174         return (rc);
 175 }
 176 
 177                         void
 178 hunt_bist_stop(
 179         __in            efx_nic_t *enp,
 180         __in            efx_bist_type_t type)
 181 {
 182         /* There is no way to stop BIST on Huntinton. */
 183         _NOTE(ARGUNUSED(enp, type))
 184 }
 185 
 186 #endif  /* EFSYS_OPT_BIST */
 187 
 188 #endif  /* EFSYS_OPT_HUNTINGTON */