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