1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008-2013 Solarflare Communications Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/sysmacros.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/cyclic.h>
32
33 #include "sfxge.h"
34
35 #include "efx.h"
36
37 /* Monitor DMA attributes */
38 static ddi_device_acc_attr_t sfxge_mon_devacc = {
39
40 DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
41 DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
42 DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
43 };
44
45 static ddi_dma_attr_t sfxge_mon_dma_attr = {
46 DMA_ATTR_V0, /* dma_attr_version */
47 0, /* dma_attr_addr_lo */
48 0xffffffffffffffffull, /* dma_attr_addr_hi */
49 0xffffffffffffffffull, /* dma_attr_count_max */
50 0x1000, /* dma_attr_align */
51 0xffffffff, /* dma_attr_burstsizes */
52 1, /* dma_attr_minxfer */
53 0xffffffffffffffffull, /* dma_attr_maxxfer */
54 0xffffffffffffffffull, /* dma_attr_seg */
55 1, /* dma_attr_sgllen */
56 1, /* dma_attr_granular */
57 0 /* dma_attr_flags */
58 };
59
60
61 static int
62 sfxge_mon_kstat_update(kstat_t *ksp, int rw)
63 {
64 sfxge_t *sp = ksp->ks_private;
65 sfxge_mon_t *smp = &(sp->s_mon);
66 efsys_mem_t *esmp = &(smp->sm_mem);
67 efx_nic_t *enp = sp->s_enp;
68 kstat_named_t *knp;
69 int rc, sn;
70
71 if (rw != KSTAT_READ) {
72 rc = EACCES;
73 goto fail1;
74 }
75
76 ASSERT(mutex_owned(&(smp->sm_lock)));
77
78 if (smp->sm_state != SFXGE_MON_STARTED)
79 goto done;
80
81 /* Synchronize the DMA memory for reading */
82 (void) ddi_dma_sync(smp->sm_mem.esm_dma_handle,
83 0,
84 EFX_MON_STATS_SIZE,
85 DDI_DMA_SYNC_FORKERNEL);
86
87 if ((rc = efx_mon_stats_update(enp, esmp, smp->sm_statbuf)) != 0)
88 goto fail2;
89
90 knp = smp->sm_stat;
91 for (sn = 0; sn < EFX_MON_NSTATS; sn++) {
92 knp->value.ui64 = smp->sm_statbuf[sn].emsv_value;
93 knp++;
94 }
95
96 knp->value.ui32 = sp->s_num_restarts;
97 knp++;
98 knp->value.ui32 = sp->s_num_restarts_hw_err;
99 knp++;
100
101 done:
102 return (0);
103
104 fail2:
105 DTRACE_PROBE(fail2);
106 fail1:
107 DTRACE_PROBE1(fail1, int, rc);
108
109 return (rc);
110 }
111
112 static int
113 sfxge_mon_kstat_init(sfxge_t *sp)
114 {
115 sfxge_mon_t *smp = &(sp->s_mon);
116 dev_info_t *dip = sp->s_dip;
117 efx_nic_t *enp = sp->s_enp;
118 kstat_t *ksp;
119 kstat_named_t *knp;
120 char name[MAXNAMELEN];
121 unsigned int id;
122 int rc;
123
124 if ((smp->sm_statbuf = kmem_zalloc(sizeof (uint32_t) * EFX_MON_NSTATS,
125 KM_NOSLEEP)) == NULL) {
126 rc = ENOMEM;
127 goto fail1;
128 }
129
130 (void) snprintf(name, MAXNAMELEN - 1, "%s_%s", ddi_driver_name(dip),
131 efx_mon_name(enp));
132
133 /* Create the set */
134 if ((ksp = kstat_create((char *)ddi_driver_name(dip),
135 ddi_get_instance(dip), name, "mon", KSTAT_TYPE_NAMED,
136 EFX_MON_NSTATS+2, 0)) == NULL) {
137 rc = ENOMEM;
138 goto fail2;
139 }
140
141 smp->sm_ksp = ksp;
142
143 ksp->ks_update = sfxge_mon_kstat_update;
144 ksp->ks_private = sp;
145 ksp->ks_lock = &(smp->sm_lock);
146
147 /* Initialise the named stats */
148 smp->sm_stat = knp = ksp->ks_data;
149 for (id = 0; id < EFX_MON_NSTATS; id++) {
150 kstat_named_init(knp, (char *)efx_mon_stat_name(enp, id),
151 KSTAT_DATA_UINT64);
152 knp++;
153 }
154 kstat_named_init(knp, "num_restarts", KSTAT_DATA_UINT32);
155 knp++;
156 kstat_named_init(knp, "num_restarts_hw_err", KSTAT_DATA_UINT32);
157 knp++;
158
159 kstat_install(ksp);
160
161 return (0);
162
163 fail2:
164 DTRACE_PROBE(fail2);
165 kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
166 fail1:
167 DTRACE_PROBE1(fail1, int, rc);
168
169 return (rc);
170 }
171
172 static void
173 sfxge_mon_kstat_fini(sfxge_t *sp)
174 {
175 sfxge_mon_t *smp = &(sp->s_mon);
176
177 /* Destroy the set */
178 kstat_delete(smp->sm_ksp);
179 smp->sm_ksp = NULL;
180 smp->sm_stat = NULL;
181
182 kmem_free(smp->sm_statbuf, sizeof (uint32_t) * EFX_MON_NSTATS);
183 }
184
185 int
186 sfxge_mon_init(sfxge_t *sp)
187 {
188 sfxge_mon_t *smp = &(sp->s_mon);
189 efx_nic_t *enp = sp->s_enp;
190 efsys_mem_t *esmp = &(smp->sm_mem);
191 sfxge_dma_buffer_attr_t dma_attr;
192 const efx_nic_cfg_t *encp;
193 int rc;
194
195 SFXGE_OBJ_CHECK(smp, sfxge_mon_t);
196
197 ASSERT3U(smp->sm_state, ==, SFXGE_MON_UNINITIALIZED);
198
199 smp->sm_sp = sp;
200
201 mutex_init(&(smp->sm_lock), NULL, MUTEX_DRIVER, NULL);
202
203 dma_attr.sdba_dip = sp->s_dip;
204 dma_attr.sdba_dattrp = &sfxge_mon_dma_attr;
205 dma_attr.sdba_callback = DDI_DMA_SLEEP;
206 dma_attr.sdba_length = EFX_MON_STATS_SIZE;
207 dma_attr.sdba_memflags = DDI_DMA_CONSISTENT;
208 dma_attr.sdba_devaccp = &sfxge_mon_devacc;
209 dma_attr.sdba_bindflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
210 dma_attr.sdba_maxcookies = 1;
211 dma_attr.sdba_zeroinit = B_TRUE;
212
213 if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
214 goto fail1;
215
216 encp = efx_nic_cfg_get(enp);
217 smp->sm_type = encp->enc_mon_type;
218
219 DTRACE_PROBE1(mon, efx_mon_type_t, smp->sm_type);
220
221 smp->sm_state = SFXGE_MON_INITIALIZED;
222
223 /* Initialize the statistics */
224 if ((rc = sfxge_mon_kstat_init(sp)) != 0)
225 goto fail2;
226
227 return (0);
228
229 fail2:
230 DTRACE_PROBE(fail2);
231
232 /* Tear down DMA setup */
233 sfxge_dma_buffer_destroy(esmp);
234
235 fail1:
236 DTRACE_PROBE1(fail1, int, rc);
237 mutex_destroy(&(smp->sm_lock));
238
239 smp->sm_sp = NULL;
240
241 SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
242
243 return (rc);
244 }
245
246 int
247 sfxge_mon_start(sfxge_t *sp)
248 {
249 sfxge_mon_t *smp = &(sp->s_mon);
250 int rc;
251
252 mutex_enter(&(smp->sm_lock));
253 ASSERT3U(smp->sm_state, ==, SFXGE_MON_INITIALIZED);
254
255 /* Initialize the MON module */
256 if ((rc = efx_mon_init(sp->s_enp)) != 0)
257 goto fail1;
258
259 smp->sm_state = SFXGE_MON_STARTED;
260
261 mutex_exit(&(smp->sm_lock));
262
263 return (0);
264
265 fail1:
266 DTRACE_PROBE1(fail1, int, rc);
267
268 mutex_exit(&(smp->sm_lock));
269
270 return (rc);
271 }
272
273 void
274 sfxge_mon_stop(sfxge_t *sp)
275 {
276 sfxge_mon_t *smp = &(sp->s_mon);
277
278 mutex_enter(&(smp->sm_lock));
279
280 ASSERT3U(smp->sm_state, ==, SFXGE_MON_STARTED);
281 smp->sm_state = SFXGE_MON_INITIALIZED;
282
283 /* Tear down the MON module */
284 efx_mon_fini(sp->s_enp);
285
286 mutex_exit(&(smp->sm_lock));
287 }
288
289 void
290 sfxge_mon_fini(sfxge_t *sp)
291 {
292 sfxge_mon_t *smp = &(sp->s_mon);
293 efsys_mem_t *esmp = &(smp->sm_mem);
294
295 ASSERT3U(smp->sm_state, ==, SFXGE_MON_INITIALIZED);
296
297 /* Tear down the statistics */
298 sfxge_mon_kstat_fini(sp);
299
300 smp->sm_state = SFXGE_MON_UNINITIALIZED;
301 mutex_destroy(&(smp->sm_lock));
302
303 smp->sm_sp = NULL;
304 smp->sm_type = EFX_MON_INVALID;
305
306 /* Tear down DMA setup */
307 sfxge_dma_buffer_destroy(esmp);
308
309 SFXGE_OBJ_CHECK(smp, sfxge_mon_t);
310 }