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 }