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 }