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 }