1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008-2013 Solarflare Communications Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/sysmacros.h>
  29 #include <sys/ddi.h>
  30 #include <sys/sunddi.h>
  31 #include <sys/cyclic.h>
  32 
  33 #include "sfxge.h"
  34 
  35 #include "efx.h"
  36 
  37 /* Monitor DMA attributes */
  38 static ddi_device_acc_attr_t sfxge_mon_devacc = {
  39 
  40         DDI_DEVICE_ATTR_V0,     /* devacc_attr_version */
  41         DDI_NEVERSWAP_ACC,      /* devacc_attr_endian_flags */
  42         DDI_STRICTORDER_ACC     /* devacc_attr_dataorder */
  43 };
  44 
  45 static ddi_dma_attr_t sfxge_mon_dma_attr = {
  46         DMA_ATTR_V0,            /* dma_attr_version     */
  47         0,                      /* dma_attr_addr_lo     */
  48         0xffffffffffffffffull,  /* dma_attr_addr_hi     */
  49         0xffffffffffffffffull,  /* dma_attr_count_max   */
  50         0x1000,                 /* dma_attr_align       */
  51         0xffffffff,             /* dma_attr_burstsizes  */
  52         1,                      /* dma_attr_minxfer     */
  53         0xffffffffffffffffull,  /* dma_attr_maxxfer     */
  54         0xffffffffffffffffull,  /* dma_attr_seg         */
  55         1,                      /* dma_attr_sgllen      */
  56         1,                      /* dma_attr_granular    */
  57         0                       /* dma_attr_flags       */
  58 };
  59 
  60 
  61 static int
  62 sfxge_mon_kstat_update(kstat_t *ksp, int rw)
  63 {
  64         sfxge_t *sp = ksp->ks_private;
  65         sfxge_mon_t *smp = &(sp->s_mon);
  66         efsys_mem_t *esmp = &(smp->sm_mem);
  67         efx_nic_t *enp = sp->s_enp;
  68         kstat_named_t *knp;
  69         int rc, sn;
  70 
  71         if (rw != KSTAT_READ) {
  72                 rc = EACCES;
  73                 goto fail1;
  74         }
  75 
  76         ASSERT(mutex_owned(&(smp->sm_lock)));
  77 
  78         if (smp->sm_state != SFXGE_MON_STARTED)
  79                 goto done;
  80 
  81         /* Synchronize the DMA memory for reading */
  82         (void) ddi_dma_sync(smp->sm_mem.esm_dma_handle,
  83             0,
  84             EFX_MON_STATS_SIZE,
  85             DDI_DMA_SYNC_FORKERNEL);
  86 
  87         if ((rc = efx_mon_stats_update(enp, esmp, smp->sm_statbuf)) != 0)
  88                 goto fail2;
  89 
  90         knp = smp->sm_stat;
  91         for (sn = 0; sn < EFX_MON_NSTATS; sn++) {
  92                 knp->value.ui64 = smp->sm_statbuf[sn].emsv_value;
  93                 knp++;
  94         }
  95 
  96         knp->value.ui32 = sp->s_num_restarts;
  97         knp++;
  98         knp->value.ui32 = sp->s_num_restarts_hw_err;
  99         knp++;
 100 
 101 done:
 102         return (0);
 103 
 104 fail2:
 105         DTRACE_PROBE(fail2);
 106 fail1:
 107         DTRACE_PROBE1(fail1, int, rc);
 108 
 109         return (rc);
 110 }
 111 
 112 static int
 113 sfxge_mon_kstat_init(sfxge_t *sp)
 114 {
 115         sfxge_mon_t *smp = &(sp->s_mon);
 116         dev_info_t *dip = sp->s_dip;
 117         efx_nic_t *enp = sp->s_enp;
 118         kstat_t *ksp;
 119         kstat_named_t *knp;
 120         char name[MAXNAMELEN];
 121         unsigned int id;
 122         int rc;
 123 
 124         if ((smp->sm_statbuf = kmem_zalloc(sizeof (uint32_t) * EFX_MON_NSTATS,
 125             KM_NOSLEEP)) == NULL) {
 126                 rc = ENOMEM;
 127                 goto fail1;
 128         }
 129 
 130         (void) snprintf(name, MAXNAMELEN - 1, "%s_%s", ddi_driver_name(dip),
 131             efx_mon_name(enp));
 132 
 133         /* Create the set */
 134         if ((ksp = kstat_create((char *)ddi_driver_name(dip),
 135             ddi_get_instance(dip), name, "mon", KSTAT_TYPE_NAMED,
 136             EFX_MON_NSTATS+2, 0)) == NULL) {
 137                 rc = ENOMEM;
 138                 goto fail2;
 139         }
 140 
 141         smp->sm_ksp = ksp;
 142 
 143         ksp->ks_update = sfxge_mon_kstat_update;
 144         ksp->ks_private = sp;
 145         ksp->ks_lock = &(smp->sm_lock);
 146 
 147         /* Initialise the named stats */
 148         smp->sm_stat = knp = ksp->ks_data;
 149         for (id = 0; id < EFX_MON_NSTATS; id++) {
 150                 kstat_named_init(knp, (char *)efx_mon_stat_name(enp, id),
 151                     KSTAT_DATA_UINT64);
 152                 knp++;
 153         }
 154         kstat_named_init(knp, "num_restarts", KSTAT_DATA_UINT32);
 155         knp++;
 156         kstat_named_init(knp, "num_restarts_hw_err", KSTAT_DATA_UINT32);
 157         knp++;
 158 
 159         kstat_install(ksp);
 160 
 161         return (0);
 162 
 163 fail2:
 164         DTRACE_PROBE(fail2);
 165         kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
 166 fail1:
 167         DTRACE_PROBE1(fail1, int, rc);
 168 
 169         return (rc);
 170 }
 171 
 172 static void
 173 sfxge_mon_kstat_fini(sfxge_t *sp)
 174 {
 175         sfxge_mon_t *smp = &(sp->s_mon);
 176 
 177         /* Destroy the set */
 178         kstat_delete(smp->sm_ksp);
 179         smp->sm_ksp = NULL;
 180         smp->sm_stat = NULL;
 181 
 182         kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
 183 }
 184 
 185 int
 186 sfxge_mon_init(sfxge_t *sp)
 187 {
 188         sfxge_mon_t *smp = &(sp->s_mon);
 189         efx_nic_t *enp = sp->s_enp;
 190         efsys_mem_t *esmp = &(smp->sm_mem);
 191         sfxge_dma_buffer_attr_t dma_attr;
 192         const efx_nic_cfg_t *encp;
 193         int rc;
 194 
 195         SFXGE_OBJ_CHECK(smp, sfxge_mon_t);
 196 
 197         ASSERT3U(smp->sm_state, ==, SFXGE_MON_UNINITIALIZED);
 198 
 199         smp->sm_sp = sp;
 200 
 201         mutex_init(&(smp->sm_lock), NULL, MUTEX_DRIVER, NULL);
 202 
 203         dma_attr.sdba_dip        = sp->s_dip;
 204         dma_attr.sdba_dattrp     = &sfxge_mon_dma_attr;
 205         dma_attr.sdba_callback   = DDI_DMA_SLEEP;
 206         dma_attr.sdba_length     = EFX_MON_STATS_SIZE;
 207         dma_attr.sdba_memflags   = DDI_DMA_CONSISTENT;
 208         dma_attr.sdba_devaccp    = &sfxge_mon_devacc;
 209         dma_attr.sdba_bindflags  = DDI_DMA_READ | DDI_DMA_CONSISTENT;
 210         dma_attr.sdba_maxcookies = 1;
 211         dma_attr.sdba_zeroinit   = B_TRUE;
 212 
 213         if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
 214                 goto fail1;
 215 
 216         encp = efx_nic_cfg_get(enp);
 217         smp->sm_type = encp->enc_mon_type;
 218 
 219         DTRACE_PROBE1(mon, efx_mon_type_t, smp->sm_type);
 220 
 221         smp->sm_state = SFXGE_MON_INITIALIZED;
 222 
 223         /* Initialize the statistics */
 224         if ((rc = sfxge_mon_kstat_init(sp)) != 0)
 225                 goto fail2;
 226 
 227         return (0);
 228 
 229 fail2:
 230         DTRACE_PROBE(fail2);
 231 
 232         /* Tear down DMA setup */
 233         sfxge_dma_buffer_destroy(esmp);
 234 
 235 fail1:
 236         DTRACE_PROBE1(fail1, int, rc);
 237         mutex_destroy(&(smp->sm_lock));
 238 
 239         smp->sm_sp = NULL;
 240 
 241         SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
 242 
 243         return (rc);
 244 }
 245 
 246 int
 247 sfxge_mon_start(sfxge_t *sp)
 248 {
 249         sfxge_mon_t *smp = &(sp->s_mon);
 250         int rc;
 251 
 252         mutex_enter(&(smp->sm_lock));
 253         ASSERT3U(smp->sm_state, ==, SFXGE_MON_INITIALIZED);
 254 
 255         /* Initialize the MON module */
 256         if ((rc = efx_mon_init(sp->s_enp)) != 0)
 257                 goto fail1;
 258 
 259         smp->sm_state = SFXGE_MON_STARTED;
 260 
 261         mutex_exit(&(smp->sm_lock));
 262 
 263         return (0);
 264 
 265 fail1:
 266         DTRACE_PROBE1(fail1, int, rc);
 267 
 268         mutex_exit(&(smp->sm_lock));
 269 
 270         return (rc);
 271 }
 272 
 273 void
 274 sfxge_mon_stop(sfxge_t *sp)
 275 {
 276         sfxge_mon_t *smp = &(sp->s_mon);
 277 
 278         mutex_enter(&(smp->sm_lock));
 279 
 280         ASSERT3U(smp->sm_state, ==, SFXGE_MON_STARTED);
 281         smp->sm_state = SFXGE_MON_INITIALIZED;
 282 
 283         /* Tear down the MON module */
 284         efx_mon_fini(sp->s_enp);
 285 
 286         mutex_exit(&(smp->sm_lock));
 287 }
 288 
 289 void
 290 sfxge_mon_fini(sfxge_t *sp)
 291 {
 292         sfxge_mon_t *smp = &(sp->s_mon);
 293         efsys_mem_t *esmp = &(smp->sm_mem);
 294 
 295         ASSERT3U(smp->sm_state, ==, SFXGE_MON_INITIALIZED);
 296 
 297         /* Tear down the statistics */
 298         sfxge_mon_kstat_fini(sp);
 299 
 300         smp->sm_state = SFXGE_MON_UNINITIALIZED;
 301         mutex_destroy(&(smp->sm_lock));
 302 
 303         smp->sm_sp = NULL;
 304         smp->sm_type = EFX_MON_INVALID;
 305 
 306         /* Tear down DMA setup */
 307         sfxge_dma_buffer_destroy(esmp);
 308 
 309         SFXGE_OBJ_CHECK(smp, sfxge_mon_t);
 310 }