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 */
41static 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
48static 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
64static int
65sfxge_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
107done:
108	return (0);
109
110fail2:
111	DTRACE_PROBE(fail2);
112fail1:
113	DTRACE_PROBE1(fail1, int, rc);
114
115	return (rc);
116}
117
118static int
119sfxge_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
185fail2:
186	DTRACE_PROBE(fail2);
187	kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
188fail1:
189	DTRACE_PROBE1(fail1, int, rc);
190
191	return (rc);
192}
193
194static void
195sfxge_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
207int
208sfxge_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
250fail2:
251	DTRACE_PROBE(fail2);
252
253	/* Tear down DMA setup */
254	sfxge_dma_buffer_destroy(esmp);
255
256fail1:
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
267int
268sfxge_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
286fail1:
287	DTRACE_PROBE1(fail1, int, rc);
288
289	mutex_exit(&(smp->sm_lock));
290
291	return (rc);
292}
293
294void
295sfxge_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
310void
311sfxge_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