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