1 /*
   2  * Copyright (c) 2008-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 <sys/types.h>
  32 #include <sys/sysmacros.h>
  33 #include <sys/ddi.h>
  34 #include <sys/sunddi.h>
  35 
  36 #include "sfxge.h"
  37 
  38 #include "efx.h"
  39 
  40 /* Monitor DMA attributes */
  41 static ddi_device_acc_attr_t sfxge_mon_devacc = {
  42 
  43         DDI_DEVICE_ATTR_V0,     /* devacc_attr_version */
  44         DDI_NEVERSWAP_ACC,      /* devacc_attr_endian_flags */
  45         DDI_STRICTORDER_ACC     /* devacc_attr_dataorder */
  46 };
  47 
  48 static ddi_dma_attr_t sfxge_mon_dma_attr = {
  49         DMA_ATTR_V0,            /* dma_attr_version     */
  50         0,                      /* dma_attr_addr_lo     */
  51         0xffffffffffffffffull,  /* dma_attr_addr_hi     */
  52         0xffffffffffffffffull,  /* dma_attr_count_max   */
  53         0x1000,                 /* dma_attr_align       */
  54         0xffffffff,             /* dma_attr_burstsizes  */
  55         1,                      /* dma_attr_minxfer     */
  56         0xffffffffffffffffull,  /* dma_attr_maxxfer     */
  57         0xffffffffffffffffull,  /* dma_attr_seg         */
  58         1,                      /* dma_attr_sgllen      */
  59         1,                      /* dma_attr_granular    */
  60         0                       /* dma_attr_flags       */
  61 };
  62 
  63 
  64 static int
  65 sfxge_mon_kstat_update(kstat_t *ksp, int rw)
  66 {
  67         sfxge_t *sp = ksp->ks_private;
  68         sfxge_mon_t *smp = &(sp->s_mon);
  69         efsys_mem_t *esmp = &(smp->sm_mem);
  70         efx_nic_t *enp = sp->s_enp;
  71         kstat_named_t *knp;
  72         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sp->s_enp);
  73         int rc, sn;
  74 
  75         if (rw != KSTAT_READ) {
  76                 rc = EACCES;
  77                 goto fail1;
  78         }
  79 
  80         ASSERT(mutex_owned(&(smp->sm_lock)));
  81 
  82         if (smp->sm_state != SFXGE_MON_STARTED)
  83                 goto done;
  84 
  85         if (smp->sm_polling) {
  86                 rc = efx_mon_stats_update(enp, esmp, smp->sm_statbuf);
  87                 if (rc != 0)
  88                         goto fail2;
  89         }
  90 
  91         knp = smp->sm_stat;
  92         for (sn = 0; sn < EFX_MON_NSTATS; sn++) {
  93                 if (encp->enc_mon_stat_mask[sn / EFX_MON_MASK_ELEMENT_SIZE] &
  94                     (1 << (sn % EFX_MON_MASK_ELEMENT_SIZE)))  {
  95                         knp->value.ui64 = smp->sm_statbuf[sn].emsv_value;
  96                         knp++;
  97                 }
  98         }
  99 
 100         knp->value.ui32 = sp->s_num_restarts;
 101         knp++;
 102         knp->value.ui32 = sp->s_num_restarts_hw_err;
 103         knp++;
 104         knp->value.ui32 = smp->sm_polling;
 105         knp++;
 106 
 107 done:
 108         return (0);
 109 
 110 fail2:
 111         DTRACE_PROBE(fail2);
 112 fail1:
 113         DTRACE_PROBE1(fail1, int, rc);
 114 
 115         return (rc);
 116 }
 117 
 118 static int
 119 sfxge_mon_kstat_init(sfxge_t *sp)
 120 {
 121         sfxge_mon_t *smp = &(sp->s_mon);
 122         dev_info_t *dip = sp->s_dip;
 123         efx_nic_t *enp = sp->s_enp;
 124         kstat_t *ksp;
 125         kstat_named_t *knp;
 126         char name[MAXNAMELEN];
 127         unsigned int id;
 128         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sp->s_enp);
 129         int rc;
 130         int nstat;
 131 
 132         if ((smp->sm_statbuf = kmem_zalloc(sizeof (uint32_t) * EFX_MON_NSTATS,
 133             KM_NOSLEEP)) == NULL) {
 134                 rc = ENOMEM;
 135                 goto fail1;
 136         }
 137 
 138         (void) snprintf(name, MAXNAMELEN - 1, "%s_%s", ddi_driver_name(dip),
 139             efx_mon_name(enp));
 140 
 141 
 142         /* Create the set */
 143         for (id = 0, nstat = 0; id < EFX_MON_NSTATS; id++) {
 144                 if (encp->enc_mon_stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] &
 145                     (1 << (id % EFX_MON_MASK_ELEMENT_SIZE)))  {
 146                         nstat++;
 147                 }
 148         }
 149 
 150         if ((ksp = kstat_create((char *)ddi_driver_name(dip),
 151             ddi_get_instance(dip), name, "mon", KSTAT_TYPE_NAMED,
 152             nstat+3, 0)) == NULL) {
 153                 rc = ENOMEM;
 154                 goto fail2;
 155         }
 156 
 157         smp->sm_ksp = ksp;
 158 
 159         ksp->ks_update = sfxge_mon_kstat_update;
 160         ksp->ks_private = sp;
 161         ksp->ks_lock = &(smp->sm_lock);
 162 
 163         /* Initialise the named stats */
 164         smp->sm_stat = knp = ksp->ks_data;
 165         for (id = 0; id < EFX_MON_NSTATS; id++) {
 166                 if (encp->enc_mon_stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] &
 167                     (1 << (id % EFX_MON_MASK_ELEMENT_SIZE)))  {
 168                         kstat_named_init(knp,
 169                             (char *)efx_mon_stat_name(enp, id),
 170                             KSTAT_DATA_UINT64);
 171                         knp++;
 172                 }
 173         }
 174         kstat_named_init(knp, "num_restarts", KSTAT_DATA_UINT32);
 175         knp++;
 176         kstat_named_init(knp, "num_restarts_hw_err", KSTAT_DATA_UINT32);
 177         knp++;
 178         kstat_named_init(knp, "mon_polling", KSTAT_DATA_UINT32);
 179         knp++;
 180 
 181         kstat_install(ksp);
 182 
 183         return (0);
 184 
 185 fail2:
 186         DTRACE_PROBE(fail2);
 187         kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
 188 fail1:
 189         DTRACE_PROBE1(fail1, int, rc);
 190 
 191         return (rc);
 192 }
 193 
 194 static void
 195 sfxge_mon_kstat_fini(sfxge_t *sp)
 196 {
 197         sfxge_mon_t *smp = &(sp->s_mon);
 198 
 199         /* Destroy the set */
 200         kstat_delete(smp->sm_ksp);
 201         smp->sm_ksp = NULL;
 202         smp->sm_stat = NULL;
 203 
 204         kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
 205 }
 206 
 207 int
 208 sfxge_mon_init(sfxge_t *sp)
 209 {
 210         sfxge_mon_t *smp = &(sp->s_mon);
 211         efx_nic_t *enp = sp->s_enp;
 212         efsys_mem_t *esmp = &(smp->sm_mem);
 213         sfxge_dma_buffer_attr_t dma_attr;
 214         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 215         int rc;
 216 
 217         SFXGE_OBJ_CHECK(smp, sfxge_mon_t);
 218 
 219         ASSERT3U(smp->sm_state, ==, SFXGE_MON_UNINITIALIZED);
 220 
 221         smp->sm_sp = sp;
 222 
 223         mutex_init(&(smp->sm_lock), NULL, MUTEX_DRIVER, NULL);
 224 
 225         dma_attr.sdba_dip        = sp->s_dip;
 226         dma_attr.sdba_dattrp     = &sfxge_mon_dma_attr;
 227         dma_attr.sdba_callback   = DDI_DMA_SLEEP;
 228         dma_attr.sdba_length     = encp->enc_mon_stat_dma_buf_size;
 229         dma_attr.sdba_memflags   = DDI_DMA_CONSISTENT;
 230         dma_attr.sdba_devaccp    = &sfxge_mon_devacc;
 231         dma_attr.sdba_bindflags  = DDI_DMA_READ | DDI_DMA_CONSISTENT;
 232         dma_attr.sdba_maxcookies = 1;
 233         dma_attr.sdba_zeroinit   = B_TRUE;
 234 
 235         if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
 236                 goto fail1;
 237 
 238         smp->sm_type = encp->enc_mon_type;
 239 
 240         DTRACE_PROBE1(mon, efx_mon_type_t, smp->sm_type);
 241 
 242         smp->sm_state = SFXGE_MON_INITIALIZED;
 243 
 244         /* Initialize the statistics */
 245         if ((rc = sfxge_mon_kstat_init(sp)) != 0)
 246                 goto fail2;
 247 
 248         return (0);
 249 
 250 fail2:
 251         DTRACE_PROBE(fail2);
 252 
 253         /* Tear down DMA setup */
 254         sfxge_dma_buffer_destroy(esmp);
 255 
 256 fail1:
 257         DTRACE_PROBE1(fail1, int, rc);
 258         mutex_destroy(&(smp->sm_lock));
 259 
 260         smp->sm_sp = NULL;
 261 
 262         SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
 263 
 264         return (rc);
 265 }
 266 
 267 int
 268 sfxge_mon_start(sfxge_t *sp)
 269 {
 270         sfxge_mon_t *smp = &(sp->s_mon);
 271         int rc;
 272 
 273         mutex_enter(&(smp->sm_lock));
 274         ASSERT3U(smp->sm_state, ==, SFXGE_MON_INITIALIZED);
 275 
 276         /* Initialize the MON module */
 277         if ((rc = efx_mon_init(sp->s_enp)) != 0)
 278                 goto fail1;
 279 
 280         smp->sm_state = SFXGE_MON_STARTED;
 281 
 282         mutex_exit(&(smp->sm_lock));
 283 
 284         return (0);
 285 
 286 fail1:
 287         DTRACE_PROBE1(fail1, int, rc);
 288 
 289         mutex_exit(&(smp->sm_lock));
 290 
 291         return (rc);
 292 }
 293 
 294 void
 295 sfxge_mon_stop(sfxge_t *sp)
 296 {
 297         sfxge_mon_t *smp = &(sp->s_mon);
 298 
 299         mutex_enter(&(smp->sm_lock));
 300 
 301         ASSERT3U(smp->sm_state, ==, SFXGE_MON_STARTED);
 302         smp->sm_state = SFXGE_MON_INITIALIZED;
 303 
 304         /* Tear down the MON module */
 305         efx_mon_fini(sp->s_enp);
 306 
 307         mutex_exit(&(smp->sm_lock));
 308 }
 309 
 310 void
 311 sfxge_mon_fini(sfxge_t *sp)
 312 {
 313         sfxge_mon_t *smp = &(sp->s_mon);
 314         efsys_mem_t *esmp = &(smp->sm_mem);
 315 
 316         ASSERT3U(smp->sm_state, ==, SFXGE_MON_INITIALIZED);
 317 
 318         /* Tear down the statistics */
 319         sfxge_mon_kstat_fini(sp);
 320 
 321         smp->sm_state = SFXGE_MON_UNINITIALIZED;
 322         mutex_destroy(&(smp->sm_lock));
 323 
 324         smp->sm_sp = NULL;
 325         smp->sm_type = EFX_MON_INVALID;
 326 
 327         /* Tear down DMA setup */
 328         sfxge_dma_buffer_destroy(esmp);
 329 
 330         SFXGE_OBJ_CHECK(smp, sfxge_mon_t);
 331 }