1 /*
2 * Copyright (c) 2008-2016 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
sfxge_mon_kstat_update(kstat_t * ksp,int rw)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
sfxge_mon_kstat_init(sfxge_t * sp)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
sfxge_mon_kstat_fini(sfxge_t * sp)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
sfxge_mon_init(sfxge_t * sp)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
sfxge_mon_start(sfxge_t * sp)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
sfxge_mon_stop(sfxge_t * sp)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
sfxge_mon_fini(sfxge_t * sp)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 }
332