1 /*
   2  * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  * 1. Redistributions of source code must retain the above copyright
   8  *    notice, this list of conditions and the following disclaimer.
   9  * 2. Redistributions in binary form must reproduce the above copyright
  10  *    notice, this list of conditions and the following disclaimer in the
  11  *    documentation and/or other materials provided with the distribution.
  12  *
  13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
  14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23  * SUCH DAMAGE.
  24  */
  25 #include "efsys.h"
  26 #include "efx.h"
  27 #include "efx_impl.h"
  28 
  29 #if EFSYS_OPT_MON_SIENA
  30 
  31         __checkReturn   int
  32 siena_mon_reset(
  33         __in            efx_nic_t *enp)
  34 {
  35         _NOTE(ARGUNUSED(enp))
  36         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
  37 
  38         return (0);
  39 }
  40 
  41         __checkReturn   int
  42 siena_mon_reconfigure(
  43         __in            efx_nic_t *enp)
  44 {
  45         _NOTE(ARGUNUSED(enp))
  46         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
  47 
  48         return (0);
  49 }
  50 
  51 #if EFSYS_OPT_MON_STATS
  52 
  53 #define SIENA_MON_WRONG_PORT (uint16_t)0xffff
  54 
  55 static __cs uint16_t __siena_mon_port0_map[] = {
  56         EFX_MON_STAT_INT_TEMP,          /* MC_CMD_SENSOR_CONTROLLER_TEMP */
  57         EFX_MON_STAT_EXT_TEMP,          /* MC_CMD_SENSOR_PHY_COMMON_TEMP */
  58         EFX_MON_STAT_INT_COOLING,       /* MC_CMD_SENSOR_CONTROLLER_COOLING */
  59         EFX_MON_STAT_EXT_TEMP,          /* MC_CMD_SENSOR_PHY0_TEMP */
  60         EFX_MON_STAT_EXT_COOLING,       /* MC_CMD_SENSOR_PHY0_COOLING */
  61         SIENA_MON_WRONG_PORT,           /* MC_CMD_SENSOR_PHY1_TEMP */
  62         SIENA_MON_WRONG_PORT,           /* MC_CMD_SENSOR_PHY1_COOLING */
  63         EFX_MON_STAT_1V,                /* MC_CMD_SENSOR_IN_1V0 */
  64         EFX_MON_STAT_1_2V,              /* MC_CMD_SENSOR_IN_1V2 */
  65         EFX_MON_STAT_1_8V,              /* MC_CMD_SENSOR_IN_1V8 */
  66         EFX_MON_STAT_2_5V,              /* MC_CMD_SENSOR_IN_2V5 */
  67         EFX_MON_STAT_3_3V,              /* MC_CMD_SENSOR_IN_3V3 */
  68         EFX_MON_STAT_12V,               /* MC_CMD_SENSOR_IN_12V0 */
  69         EFX_MON_STAT_1_2VA,             /* MC_CMD_SENSOR_IN_1V2A */
  70         EFX_MON_STAT_VREF,              /* MC_CMD_SENSOR_IN_VREF */
  71 };
  72 
  73 static __cs uint16_t __siena_mon_port1_map[] = {
  74         EFX_MON_STAT_INT_TEMP,          /* MC_CMD_SENSOR_CONTROLLER_TEMP */
  75         EFX_MON_STAT_EXT_TEMP,          /* MC_CMD_SENSOR_PHY_COMMON_TEMP */
  76         EFX_MON_STAT_INT_COOLING,       /* MC_CMD_SENSOR_CONTROLLER_COOLING */
  77         SIENA_MON_WRONG_PORT,           /* MC_CMD_SENSOR_PHY0_TEMP */
  78         SIENA_MON_WRONG_PORT,           /* MC_CMD_SENSOR_PHY0_COOLING */
  79         EFX_MON_STAT_EXT_TEMP,          /* MC_CMD_SENSOR_PHY1_TEMP */
  80         EFX_MON_STAT_EXT_COOLING,       /* MC_CMD_SENSOR_PHY1_COOLING */
  81         EFX_MON_STAT_1V,                /* MC_CMD_SENSOR_IN_1V0 */
  82         EFX_MON_STAT_1_2V,              /* MC_CMD_SENSOR_IN_1V2 */
  83         EFX_MON_STAT_1_8V,              /* MC_CMD_SENSOR_IN_1V8 */
  84         EFX_MON_STAT_2_5V,              /* MC_CMD_SENSOR_IN_2V5 */
  85         EFX_MON_STAT_3_3V,              /* MC_CMD_SENSOR_IN_3V3 */
  86         EFX_MON_STAT_12V,               /* MC_CMD_SENSOR_IN_12V0 */
  87         EFX_MON_STAT_1_2VA,             /* MC_CMD_SENSOR_IN_1V2A */
  88         EFX_MON_STAT_VREF,              /* MC_CMD_SENSOR_IN_VREF */
  89 };
  90 
  91 #define SIENA_STATIC_SENSOR_ASSERT(_field)                              \
  92         EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field                \
  93                             == EFX_MON_STAT_STATE_ ## _field)
  94 
  95                                         void
  96 siena_mon_decode_stats(
  97         __in                            efx_nic_t *enp,
  98         __in                            uint32_t dmask,
  99         __in_opt                        efsys_mem_t *esmp,
 100         __out_opt                       uint32_t *vmaskp,
 101         __out_ecount_opt(EFX_MON_NSTATS)        efx_mon_stat_value_t *value)
 102 {
 103         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
 104         uint16_t *sensor_map;
 105         uint16_t mc_sensor;
 106         size_t mc_sensor_max;
 107         uint32_t vmask = 0;
 108         uint32_t idx = 0;
 109 
 110         /* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
 111         SIENA_STATIC_SENSOR_ASSERT(OK);
 112         SIENA_STATIC_SENSOR_ASSERT(WARNING);
 113         SIENA_STATIC_SENSOR_ASSERT(FATAL);
 114         SIENA_STATIC_SENSOR_ASSERT(BROKEN);
 115 
 116         EFX_STATIC_ASSERT(sizeof (__siena_mon_port1_map)
 117                             == sizeof (__siena_mon_port0_map));
 118         mc_sensor_max = EFX_ARRAY_SIZE(__siena_mon_port0_map);
 119         sensor_map = (emip->emi_port == 1)
 120                 ? __siena_mon_port0_map
 121                 : __siena_mon_port1_map;
 122 
 123         /*
 124          * dmask may legitimately contain sensors not understood by the driver
 125          */
 126         for (mc_sensor = 0; mc_sensor < mc_sensor_max; ++mc_sensor) {
 127                 uint16_t efx_sensor = sensor_map[mc_sensor];
 128 
 129                 if (~dmask & (1 << mc_sensor))
 130                         continue;
 131                 idx++;
 132 
 133                 if (efx_sensor == SIENA_MON_WRONG_PORT)
 134                         continue;
 135                 EFSYS_ASSERT(efx_sensor < EFX_MON_NSTATS);
 136 
 137                 vmask |= (1 << efx_sensor);
 138                 if (value != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
 139                         efx_mon_stat_value_t *emsvp = value + efx_sensor;
 140                         efx_dword_t dword;
 141                         EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
 142                         emsvp->emsv_value =
 143                             (uint16_t)EFX_DWORD_FIELD(
 144                                 dword,
 145                                 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
 146                         emsvp->emsv_state =
 147                             (uint16_t)EFX_DWORD_FIELD(
 148                                 dword,
 149                                 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
 150                 }
 151         }
 152 
 153         if (vmaskp != NULL)
 154                 *vmaskp = vmask;
 155 }
 156 
 157         __checkReturn                   int
 158 siena_mon_ev(
 159         __in                            efx_nic_t *enp,
 160         __in                            efx_qword_t *eqp,
 161         __out                           efx_mon_stat_t *idp,
 162         __out                           efx_mon_stat_value_t *valuep)
 163 {
 164         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
 165         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 166         uint16_t ev_monitor;
 167         uint16_t ev_state;
 168         uint16_t ev_value;
 169         uint16_t *sensor_map;
 170         efx_mon_stat_t id;
 171         int rc;
 172 
 173         sensor_map = (emip->emi_port == 1)
 174                 ? __siena_mon_port0_map
 175                 : __siena_mon_port1_map;
 176 
 177         ev_monitor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
 178         ev_state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
 179         ev_value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
 180 
 181         /* Hardware must support this statistic */
 182         EFSYS_ASSERT((1 << ev_monitor) & encp->enc_siena_mon_stat_mask);
 183 
 184         /* But we don't have to understand it */
 185         if (ev_monitor >= EFX_ARRAY_SIZE(__siena_mon_port0_map)) {
 186                 rc = ENOTSUP;
 187                 goto fail1;
 188         }
 189 
 190         id = sensor_map[ev_monitor];
 191         if (id == SIENA_MON_WRONG_PORT)
 192                 return (ENODEV);
 193         EFSYS_ASSERT(id < EFX_MON_NSTATS);
 194 
 195         *idp = id;
 196         valuep->emsv_value = ev_value;
 197         valuep->emsv_state = ev_state;
 198 
 199         return (0);
 200 
 201 fail1:
 202         EFSYS_PROBE1(fail1, int, rc);
 203 
 204         return (rc);
 205 }
 206 
 207         __checkReturn                   int
 208 siena_mon_stats_update(
 209         __in                            efx_nic_t *enp,
 210         __in                            efsys_mem_t *esmp,
 211         __out_ecount(EFX_MON_NSTATS)    efx_mon_stat_value_t *values)
 212 {
 213         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 214         uint32_t dmask = encp->enc_siena_mon_stat_mask;
 215         uint32_t vmask;
 216         uint8_t payload[MC_CMD_READ_SENSORS_IN_LEN];
 217         efx_mcdi_req_t req;
 218         int rc;
 219 
 220         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 221 
 222         req.emr_cmd = MC_CMD_READ_SENSORS;
 223         req.emr_in_buf = payload;
 224         req.emr_in_length = sizeof (payload);
 225         EFX_STATIC_ASSERT(MC_CMD_READ_SENSORS_OUT_LEN == 0);
 226         req.emr_out_buf = NULL;
 227         req.emr_out_length = 0;
 228 
 229         MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_LO,
 230                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
 231         MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_HI,
 232                             EFSYS_MEM_ADDR(esmp) >> 32);
 233 
 234         efx_mcdi_execute(enp, &req);
 235 
 236         if (req.emr_rc != 0) {
 237                 rc = req.emr_rc;
 238                 goto fail1;
 239         }
 240 
 241         siena_mon_decode_stats(enp, dmask, esmp, &vmask, values);
 242         EFSYS_ASSERT(vmask == encp->enc_mon_stat_mask);
 243 
 244         return (0);
 245 
 246 fail1:
 247         EFSYS_PROBE1(fail1, int, rc);
 248 
 249         return (rc);
 250 }
 251 
 252 #endif  /* EFSYS_OPT_MON_STATS */
 253 
 254 #endif  /* EFSYS_OPT_MON_SIENA */