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/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/gld.h>
31 #include <sys/stream.h>
32 #include <sys/strsun.h>
33 #include <sys/strsubr.h>
34 #include <sys/dlpi.h>
35 #include <sys/pattr.h>
36 #include <sys/ksynch.h>
37 #include <sys/spl.h>
38
39 #include <inet/nd.h>
40 #include <inet/mi.h>
41
42 #include "sfxge.h"
43
44 #ifdef _USE_GLD_V2
45
46 void
47 sfxge_gld_link_update(sfxge_t *sp)
48 {
49 sfxge_mac_t *smp = &(sp->s_mac);
50 int32_t link;
51
52 switch (smp->sm_link_mode) {
53 case EFX_LINK_UNKNOWN:
54 link = GLD_LINKSTATE_UNKNOWN;
55 break;
56 case EFX_LINK_DOWN:
57 link = GLD_LINKSTATE_DOWN;
58 break;
59 default:
60 link = GLD_LINKSTATE_UP;
61 }
62
63 gld_linkstate(sp->s_gmip, link);
64 }
65
66 void
67 sfxge_gld_mtu_update(sfxge_t *sp)
68 {
69 }
70
71 void
72 sfxge_gld_rx_post(sfxge_t *sp, unsigned int index, mblk_t *mp)
73 {
74 mblk_t **mpp;
75
76 _NOTE(ARGUNUSED(index))
77
78 mutex_enter(&(sp->s_rx_lock));
79 *(sp->s_mpp) = mp;
80
81 mpp = ∓
82 while ((mp = *mpp) != NULL)
83 mpp = &(mp->b_next);
84
85 sp->s_mpp = mpp;
86 mutex_exit(&(sp->s_rx_lock));
87 }
88
89 void
90 sfxge_gld_rx_push(sfxge_t *sp)
91 {
92 mblk_t *mp;
93
94 mutex_enter(&(sp->s_rx_lock));
95 mp = sp->s_mp;
96 sp->s_mp = NULL;
97 sp->s_mpp = &(sp->s_mp);
98 mutex_exit(&(sp->s_rx_lock));
99
100 while (mp != NULL) {
101 mblk_t *next;
102
103 next = mp->b_next;
104 mp->b_next = NULL;
105
106 /* The stack behaves badly with multi-fragment messages */
107 if (mp->b_cont != NULL) {
108 uint16_t flags = DB_CKSUMFLAGS(mp);
109
110 (void) pullupmsg(mp, -1);
111
112 DB_CKSUMFLAGS(mp) = flags;
113 }
114
115 gld_recv(sp->s_gmip, mp);
116
117 mp = next;
118 }
119 }
120
121 static int
122 sfxge_gld_get_stats(gld_mac_info_t *gmip, struct gld_stats *gsp)
123 {
124 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
125 unsigned int speed;
126 sfxge_link_duplex_t duplex;
127 uint64_t val;
128
129 sfxge_mac_stat_get(sp, EFX_MAC_TX_ERRORS, &val);
130 gsp->glds_errxmt = (uint32_t)val;
131
132 sfxge_mac_stat_get(sp, EFX_MAC_RX_ERRORS, &val);
133 gsp->glds_errrcv = (uint32_t)val;
134
135 sfxge_mac_stat_get(sp, EFX_MAC_RX_FCS_ERRORS, &val);
136 gsp->glds_crc = (uint32_t)val;
137
138 sfxge_mac_stat_get(sp, EFX_MAC_RX_DROP_EVENTS, &val);
139 gsp->glds_norcvbuf = (uint32_t)val;
140
141 sfxge_mac_link_speed_get(sp, &speed);
142 gsp->glds_speed = (uint64_t)speed * 1000000ull;
143
144 sfxge_mac_link_duplex_get(sp, &duplex);
145
146 switch (duplex) {
147 case SFXGE_LINK_DUPLEX_UNKNOWN:
148 gsp->glds_duplex = GLD_DUPLEX_UNKNOWN;
149 break;
150
151 case SFXGE_LINK_DUPLEX_HALF:
152 gsp->glds_duplex = GLD_DUPLEX_HALF;
153 break;
154
155 case SFXGE_LINK_DUPLEX_FULL:
156 gsp->glds_duplex = GLD_DUPLEX_FULL;
157 break;
158
159 default:
160 ASSERT(B_FALSE);
161 break;
162 }
163
164 return (GLD_SUCCESS);
165 }
166
167 static int
168 sfxge_gld_reset(gld_mac_info_t *gmip)
169 {
170 /*
171 * The driver already has hardware resets at appropriate times
172 * This is only ever called before gld_start()
173 */
174 return (GLD_SUCCESS);
175 }
176
177 static int
178 sfxge_gld_start(gld_mac_info_t *gmip)
179 {
180 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
181 int rc;
182
183 mutex_enter(&(sp->s_rx_lock));
184 sp->s_mpp = &(sp->s_mp);
185 mutex_exit(&(sp->s_rx_lock));
186
187 if ((rc = sfxge_start(sp, B_FALSE)) != 0)
188 goto fail1;
189
190 return (GLD_SUCCESS);
191
192 fail1:
193 DTRACE_PROBE1(fail1, int, rc);
194
195 mutex_enter(&(sp->s_rx_lock));
196 ASSERT3P(sp->s_mp, ==, NULL);
197 sp->s_mpp = NULL;
198 mutex_exit(&(sp->s_rx_lock));
199
200 return (GLD_FAILURE);
201 }
202
203 static int
204 sfxge_gld_stop(gld_mac_info_t *gmip)
205 {
206 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
207
208 sfxge_stop(sp);
209
210 mutex_enter(&(sp->s_rx_lock));
211 ASSERT3P(sp->s_mp, ==, NULL);
212 sp->s_mpp = NULL;
213 mutex_exit(&(sp->s_rx_lock));
214
215 return (GLD_SUCCESS);
216 }
217
218 static int
219 sfxge_gld_set_promiscuous(gld_mac_info_t *gmip, int flags)
220 {
221 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
222 int rc;
223
224 switch (flags) {
225 case GLD_MAC_PROMISC_NONE:
226 if ((rc = sfxge_mac_promisc_set(sp, SFXGE_PROMISC_OFF)) != 0)
227 goto fail1;
228 break;
229 case GLD_MAC_PROMISC_MULTI:
230 if ((rc = sfxge_mac_promisc_set(sp, SFXGE_PROMISC_ALL_MULTI))
231 != 0)
232 goto fail2;
233 break;
234 default:
235 if ((rc = sfxge_mac_promisc_set(sp, SFXGE_PROMISC_ALL_PHYS))
236 != 0)
237 goto fail3;
238 break;
239 }
240
241 return (GLD_SUCCESS);
242
243 fail3:
244 DTRACE_PROBE(fail3);
245 fail2:
246 DTRACE_PROBE(fail2);
247 fail1:
248 DTRACE_PROBE1(fail1, int, rc);
249 return (GLD_FAILURE);
250 }
251
252 static int
253 sfxge_gld_set_multicast(gld_mac_info_t *gmip, unsigned char *addr, int flag)
254 {
255 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
256 int rc;
257
258 switch (flag) {
259 case GLD_MULTI_ENABLE:
260 if ((rc = sfxge_mac_multicst_add(sp, addr)) != 0)
261 goto fail1;
262 break;
263 case GLD_MULTI_DISABLE:
264 if ((rc = sfxge_mac_multicst_remove(sp, addr)) != 0)
265 goto fail2;
266 break;
267 default:
268 ASSERT(B_FALSE);
269 break;
270 }
271
272 return (GLD_SUCCESS);
273
274 fail2:
275 DTRACE_PROBE(fail2);
276 fail1:
277 DTRACE_PROBE1(fail1, int, rc);
278 return (GLD_FAILURE);
279 }
280
281 static int
282 sfxge_gld_set_mac_addr(gld_mac_info_t *gmip, unsigned char *addr)
283 {
284 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
285 int rc;
286
287 if ((rc = sfxge_mac_unicst_set(sp, addr)) != 0)
288 goto fail1;
289
290 return (GLD_SUCCESS);
291
292 fail1:
293 DTRACE_PROBE1(fail1, int, rc);
294
295 return (GLD_BADARG);
296 }
297
298 int
299 sfxge_gld_send(gld_mac_info_t *gmip, mblk_t *mp)
300 {
301 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
302
303 (void) sfxge_tx_packet_add(sp, mp);
304
305 /*
306 * This gives no TX backpressure, which can cause unbounded TX DPL
307 * size. See bug 18984. This feature is implemented for GLDv3
308 */
309 return (GLD_SUCCESS);
310 }
311
312 int
313 sfxge_gld_ioctl(gld_mac_info_t *gmip, queue_t *wq, mblk_t *mp)
314 {
315 sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
316 struct iocblk *iocp;
317
318 iocp = (struct iocblk *)mp->b_rptr;
319
320 switch (iocp->ioc_cmd) {
321 case ND_GET:
322 case ND_SET:
323 if (!nd_getset(wq, sp->s_ndh, mp))
324 miocnak(wq, mp, 0, EINVAL);
325 else
326 qreply(wq, mp);
327 break;
328
329 default:
330 sfxge_ioctl(sp, wq, mp);
331 break;
332 }
333
334 return (GLD_SUCCESS);
335 }
336
337
338 int
339 sfxge_gld_register(sfxge_t *sp)
340 {
341 gld_mac_info_t *gmip;
342 unsigned int pri;
343 int rc;
344
345 mutex_init(&(sp->s_rx_lock), NULL, MUTEX_DRIVER,
346 DDI_INTR_PRI(sp->s_intr.si_intr_pri));
347
348 if ((rc = sfxge_gld_nd_register(sp)) != 0)
349 goto fail1;
350
351 gmip = gld_mac_alloc(sp->s_dip);
352
353 gmip->gldm_private = (caddr_t)sp;
354
355 gmip->gldm_reset = sfxge_gld_reset;
356 gmip->gldm_start = sfxge_gld_start;
357 gmip->gldm_stop = sfxge_gld_stop;
358 gmip->gldm_set_mac_addr = sfxge_gld_set_mac_addr;
359 gmip->gldm_set_multicast = sfxge_gld_set_multicast;
360 gmip->gldm_set_promiscuous = sfxge_gld_set_promiscuous;
361 gmip->gldm_send = sfxge_gld_send;
362 gmip->gldm_get_stats = sfxge_gld_get_stats;
363 gmip->gldm_ioctl = sfxge_gld_ioctl;
364
365 gmip->gldm_ident = (char *)sfxge_ident;
366 gmip->gldm_type = DL_ETHER;
367 gmip->gldm_minpkt = 0;
368 gmip->gldm_maxpkt = sp->s_mtu;
369 gmip->gldm_addrlen = ETHERADDRL;
370 gmip->gldm_saplen = -2;
371 gmip->gldm_broadcast_addr = sfxge_brdcst;
372
373 gmip->gldm_vendor_addr = kmem_alloc(ETHERADDRL, KM_SLEEP);
374
375 if ((rc = sfxge_mac_unicst_get(sp, SFXGE_UNICST_BIA,
376 gmip->gldm_vendor_addr)) != 0)
377 goto fail2;
378
379 gmip->gldm_devinfo = sp->s_dip;
380 gmip->gldm_ppa = ddi_get_instance(sp->s_dip);
381
382 gmip->gldm_cookie = spltoipl(0);
383
384 gmip->gldm_capabilities =
385 GLD_CAP_LINKSTATE |
386 GLD_CAP_CKSUM_IPHDR |
387 GLD_CAP_CKSUM_FULL_V4 |
388 GLD_CAP_ZEROCOPY;
389
390 if ((rc = gld_register(sp->s_dip, (char *)ddi_driver_name(sp->s_dip),
391 gmip)) != 0)
392 goto fail3;
393
394 sp->s_gmip = gmip;
395 return (0);
396
397 fail3:
398 DTRACE_PROBE(fail3);
399 fail2:
400 DTRACE_PROBE(fail2);
401
402 kmem_free(gmip->gldm_vendor_addr, ETHERADDRL);
403 gld_mac_free(gmip);
404
405 sfxge_gld_nd_unregister(sp);
406
407 fail1:
408 DTRACE_PROBE1(fail1, int, rc);
409 mutex_destroy(&(sp->s_rx_lock));
410
411 return (rc);
412 }
413
414 int
415 sfxge_gld_unregister(sfxge_t *sp)
416 {
417 gld_mac_info_t *gmip = sp->s_gmip;
418 int rc;
419
420 if ((rc = gld_unregister(gmip)) != 0)
421 goto fail1;
422
423 sp->s_gmip = NULL;
424
425 kmem_free(gmip->gldm_vendor_addr, ETHERADDRL);
426 gld_mac_free(gmip);
427
428 sfxge_gld_nd_unregister(sp);
429
430 mutex_destroy(&(sp->s_rx_lock));
431
432 return (0);
433
434 fail1:
435 DTRACE_PROBE1(fail1, int, rc);
436
437 return (rc);
438 }
439 #endif /* _USE_GLD_V2 */