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 /*
28 * All efx_mac_*() must be after efx_port_init()
29 * LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
30 * to serialise against sfxge_restart()
31 */
32
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37
38 #include "sfxge.h"
39 #include "efx.h"
40
41 #define SFXGE_MAC_POLL_PERIOD_MS 1000
42
43 static void sfxge_mac_link_update_locked(sfxge_t *sp, efx_link_mode_t mode);
44
45
46 /* MAC DMA attributes */
47 static ddi_device_acc_attr_t sfxge_mac_devacc = {
48
49 DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
50 DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
51 DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
52 };
53
54 static ddi_dma_attr_t sfxge_mac_dma_attr = {
55 DMA_ATTR_V0, /* dma_attr_version */
56 0, /* dma_attr_addr_lo */
57 0xffffffffffffffffull, /* dma_attr_addr_hi */
58 0xffffffffffffffffull, /* dma_attr_count_max */
59 0x1000, /* dma_attr_align */
60 0xffffffff, /* dma_attr_burstsizes */
61 1, /* dma_attr_minxfer */
62 0xffffffffffffffffull, /* dma_attr_maxxfer */
63 0xffffffffffffffffull, /* dma_attr_seg */
64 1, /* dma_attr_sgllen */
65 1, /* dma_attr_granular */
66 0 /* dma_attr_flags */
67 };
68
69
70 static void
71 _sfxge_mac_stat_update(sfxge_mac_t *smp, int tries, int delay_usec)
72 {
73 sfxge_t *sp = smp->sm_sp;
74 efsys_mem_t *esmp = &(smp->sm_mem);
75 int rc, i;
76
77 ASSERT(mutex_owned(&(smp->sm_lock)));
78 ASSERT3U(smp->sm_state, !=, SFXGE_MAC_UNINITIALIZED);
79
80 /* if no stats pending then they are already freshly updated */
81 if (smp->sm_mac_stats_timer_reqd && !smp->sm_mac_stats_pend)
82 return;
83
84 for (i = 0; i < tries; i++) {
85 /* Synchronize the DMA memory for reading */
86 (void) ddi_dma_sync(smp->sm_mem.esm_dma_handle,
87 0,
88 EFX_MAC_STATS_SIZE,
89 DDI_DMA_SYNC_FORKERNEL);
90
91 /* Try to update the cached counters */
92 if ((rc = efx_mac_stats_update(sp->s_enp, esmp, smp->sm_stat,
93 NULL)) != EAGAIN)
94 goto done;
95
96 drv_usecwait(delay_usec);
97 }
98
99 DTRACE_PROBE(mac_stat_timeout);
100 cmn_err(CE_NOTE, SFXGE_CMN_ERR "[%s%d] MAC stats timeout",
101 ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
102 return;
103
104 done:
105 smp->sm_mac_stats_pend = B_FALSE;
106 smp->sm_lbolt = ddi_get_lbolt();
107 }
108
109 static void
110 sfxge_mac_stat_update_quick(sfxge_mac_t *smp)
111 {
112 /*
113 * Update the statistics from the most recent DMA. This might race
114 * with an inflight dma, so retry once. Otherwise get mac stat
115 * values from the last mac_poll() or MC periodic stats.
116 */
117 _sfxge_mac_stat_update(smp, 2, 50);
118 }
119
120 static void
121 sfxge_mac_stat_update_wait(sfxge_mac_t *smp)
122 {
123 /* Wait a max of 20 * 500us = 10ms */
124 _sfxge_mac_stat_update(smp, 20, 500);
125 }
126
127 static int
128 sfxge_mac_kstat_update(kstat_t *ksp, int rw)
129 {
130 sfxge_mac_t *smp = ksp->ks_private;
131 kstat_named_t *knp;
132 int rc;
133
134 if (rw != KSTAT_READ) {
135 rc = EACCES;
136 goto fail1;
137 }
138
139 ASSERT(mutex_owned(&(smp->sm_lock)));
140
141 if (smp->sm_state != SFXGE_MAC_STARTED)
142 goto done;
143
144 sfxge_mac_stat_update_quick(smp);
145
146 knp = smp->sm_stat;
147 knp += EFX_MAC_NSTATS;
148
149 knp->value.ui64 = (smp->sm_link_up) ? 1 : 0;
150 knp++;
151
152 knp->value.ui64 = smp->sm_link_speed;
153 knp++;
154
155 knp->value.ui64 = smp->sm_link_duplex;
156 knp++;
157
158 done:
159 return (0);
160
161 fail1:
162 DTRACE_PROBE1(fail1, int, rc);
163
164 return (rc);
165 }
166
167 static int
168 sfxge_mac_kstat_init(sfxge_t *sp)
169 {
170 sfxge_mac_t *smp = &(sp->s_mac);
171 dev_info_t *dip = sp->s_dip;
172 char name[MAXNAMELEN];
173 kstat_t *ksp;
174 kstat_named_t *knp;
175 unsigned int id;
176 int rc;
177
178 /* Create the set */
179 (void) snprintf(name, MAXNAMELEN - 1, "%s_mac", ddi_driver_name(dip));
180
181 if ((ksp = kstat_create((char *)ddi_driver_name(dip),
182 ddi_get_instance(dip), name, "mac", KSTAT_TYPE_NAMED,
183 EFX_MAC_NSTATS + 4, 0)) == NULL) {
184 rc = ENOMEM;
185 goto fail1;
186 }
187
188 smp->sm_ksp = ksp;
189
190 ksp->ks_update = sfxge_mac_kstat_update;
191 ksp->ks_private = smp;
192 ksp->ks_lock = &(smp->sm_lock);
193
194 /* Initialise the named stats */
195 smp->sm_stat = knp = ksp->ks_data;
196 for (id = 0; id < EFX_MAC_NSTATS; id++) {
197 kstat_named_init(knp, (char *)efx_mac_stat_name(sp->s_enp, id),
198 KSTAT_DATA_UINT64);
199 knp++;
200 }
201
202 kstat_named_init(knp++, "link_up", KSTAT_DATA_UINT64);
203 kstat_named_init(knp++, "link_speed", KSTAT_DATA_UINT64);
204 kstat_named_init(knp++, "link_duplex", KSTAT_DATA_UINT64);
205
206 kstat_install(ksp);
207
208 return (0);
209
210 fail1:
211 DTRACE_PROBE1(fail1, int, rc);
212
213 return (rc);
214 }
215
216 static void
217 sfxge_mac_kstat_fini(sfxge_t *sp)
218 {
219 sfxge_mac_t *smp = &(sp->s_mac);
220
221 /* Destroy the set */
222 kstat_delete(smp->sm_ksp);
223 smp->sm_ksp = NULL;
224 smp->sm_stat = NULL;
225 }
226
227 void
228 sfxge_mac_stat_get(sfxge_t *sp, unsigned int id, uint64_t *valp)
229 {
230 sfxge_mac_t *smp = &(sp->s_mac);
231
232 /* Make sure the cached counter values are recent */
233 mutex_enter(&(smp->sm_lock));
234
235 if (smp->sm_state != SFXGE_MAC_STARTED)
236 goto done;
237
238 sfxge_mac_stat_update_quick(smp);
239
240 *valp = smp->sm_stat[id].value.ui64;
241
242 done:
243 mutex_exit(&(smp->sm_lock));
244 }
245
246 static void
247 sfxge_mac_poll(void *arg)
248 {
249 sfxge_t *sp = arg;
250 efx_nic_t *enp = sp->s_enp;
251 sfxge_mac_t *smp = &(sp->s_mac);
252 efsys_mem_t *esmp = &(smp->sm_mem);
253 efx_link_mode_t mode;
254 clock_t timeout;
255
256 mutex_enter(&(smp->sm_lock));
257 while (smp->sm_state == SFXGE_MAC_STARTED) {
258
259 /* clears smp->sm_mac_stats_pend if appropriate */
260 if (smp->sm_mac_stats_pend)
261 sfxge_mac_stat_update_wait(smp);
262
263 /* This may sleep waiting for MCDI completion */
264 mode = EFX_LINK_UNKNOWN;
265 if (efx_port_poll(enp, &mode) == 0)
266 sfxge_mac_link_update_locked(sp, mode);
267
268 if ((smp->sm_link_poll_reqd == B_FALSE) &&
269 (smp->sm_mac_stats_timer_reqd == B_FALSE))
270 goto done;
271
272 /* Zero the memory */
273 (void) memset(esmp->esm_base, 0, EFX_MAC_STATS_SIZE);
274
275 /* Trigger upload the MAC statistics counters */
276 if (smp->sm_link_up &&
277 efx_mac_stats_upload(sp->s_enp, esmp) == 0)
278 smp->sm_mac_stats_pend = B_TRUE;
279
280 /* Wait for timeout or end of polling */
281 timeout = ddi_get_lbolt() + drv_usectohz(1000 *
282 SFXGE_MAC_POLL_PERIOD_MS);
283 while (smp->sm_state == SFXGE_MAC_STARTED) {
284 if (cv_timedwait(&(smp->sm_link_poll_kv),
285 &(smp->sm_lock), timeout) < 0) {
286 /* Timeout - poll if polling still enabled */
287 break;
288 }
289 }
290 }
291 done:
292 mutex_exit(&(smp->sm_lock));
293
294 }
295
296 static void
297 sfxge_mac_poll_start(sfxge_t *sp)
298 {
299 sfxge_mac_t *smp = &(sp->s_mac);
300
301 ASSERT(mutex_owned(&(smp->sm_lock)));
302 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
303
304 /* Schedule a poll */
305 (void) ddi_taskq_dispatch(smp->sm_tqp, sfxge_mac_poll, sp, DDI_SLEEP);
306 }
307
308 static void
309 sfxge_mac_poll_stop(sfxge_t *sp)
310 {
311 sfxge_mac_t *smp = &(sp->s_mac);
312
313 ASSERT(mutex_owned(&(smp->sm_lock)));
314 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
315
316 cv_broadcast(&(smp->sm_link_poll_kv));
317
318 /* Wait for link polling to cease */
319 mutex_exit(&(smp->sm_lock));
320 ddi_taskq_wait(smp->sm_tqp);
321 mutex_enter(&(smp->sm_lock));
322
323 /* Wait for any pending DMAed stats to complete */
324 sfxge_mac_stat_update_wait(smp);
325 }
326
327 int
328 sfxge_mac_init(sfxge_t *sp)
329 {
330 sfxge_mac_t *smp = &(sp->s_mac);
331 efsys_mem_t *esmp = &(smp->sm_mem);
332 dev_info_t *dip = sp->s_dip;
333 sfxge_dma_buffer_attr_t dma_attr;
334 const efx_nic_cfg_t *encp;
335 unsigned char *bytes;
336 char buf[8]; /* sufficient for "true" or "false" plus NULL */
337 char name[MAXNAMELEN];
338 int *ints;
339 unsigned int n;
340 int err, rc;
341
342 SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
343
344 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_UNINITIALIZED);
345
346 smp->sm_sp = sp;
347 encp = efx_nic_cfg_get(sp->s_enp);
348 smp->sm_link_poll_reqd = (~encp->enc_features &
349 EFX_FEATURE_LINK_EVENTS);
350 smp->sm_mac_stats_timer_reqd = (~encp->enc_features &
351 EFX_FEATURE_PERIODIC_MAC_STATS);
352
353 mutex_init(&(smp->sm_lock), NULL, MUTEX_DRIVER,
354 DDI_INTR_PRI(sp->s_intr.si_intr_pri));
355 cv_init(&(smp->sm_link_poll_kv), NULL, CV_DRIVER, NULL);
356
357 /* Create link poll taskq */
358 (void) snprintf(name, MAXNAMELEN - 1, "%s_mac_tq",
359 ddi_driver_name(dip));
360 smp->sm_tqp = ddi_taskq_create(dip, name, 1, TASKQ_DEFAULTPRI,
361 DDI_SLEEP);
362 if (smp->sm_tqp == NULL) {
363 rc = ENOMEM;
364 goto fail1;
365 }
366
367 if ((rc = sfxge_phy_init(sp)) != 0)
368 goto fail2;
369
370 dma_attr.sdba_dip = dip;
371 dma_attr.sdba_dattrp = &sfxge_mac_dma_attr;
372 dma_attr.sdba_callback = DDI_DMA_SLEEP;
373 dma_attr.sdba_length = EFX_MAC_STATS_SIZE;
374 dma_attr.sdba_memflags = DDI_DMA_CONSISTENT;
375 dma_attr.sdba_devaccp = &sfxge_mac_devacc;
376 dma_attr.sdba_bindflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
377 dma_attr.sdba_maxcookies = 1;
378 dma_attr.sdba_zeroinit = B_TRUE;
379
380 if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
381 goto fail3;
382
383 /*
384 * Set the initial group hash to allow reception of only broadcast
385 * packets.
386 */
387 smp->sm_bucket[0xff] = 1;
388
389 /* Set the initial flow control values */
390 smp->sm_fcntl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
391
392 /*
393 * Determine the 'burnt-in' MAC address:
394 *
395 * A: if the "mac-address" property is set on our device node use that.
396 * B: otherwise, if the system property "local-mac-address?" is set to
397 * "false" then we use the system MAC address.
398 * C: otherwise, if the "local-mac-address" property is set on our
399 * device node use that.
400 * D: otherwise, use the value from NVRAM.
401 */
402
403 /* A */
404 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
405 "mac-address", &bytes, &n);
406 switch (err) {
407 case DDI_PROP_SUCCESS:
408 if (n == ETHERADDRL) {
409 bcopy(bytes, smp->sm_bia, ETHERADDRL);
410 goto done;
411 }
412
413 ddi_prop_free(bytes);
414 break;
415
416 default:
417 break;
418 }
419
420 /* B */
421 n = sizeof (buf);
422 bzero(buf, n--);
423 (void) ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
424 "local-mac-address?", buf, (int *)&n);
425
426 if (strcmp(buf, "false") == 0) {
427 struct ether_addr addr;
428
429 if (localetheraddr(NULL, &addr) != 0) {
430 bcopy((uint8_t *)&addr, smp->sm_bia, ETHERADDRL);
431 goto done;
432 }
433 }
434
435 /*
436 * C
437 *
438 * NOTE: "local-mac_address" maybe coded as an integer or byte array.
439 */
440 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
441 "local-mac-address", &ints, &n);
442 switch (err) {
443 case DDI_PROP_SUCCESS:
444 if (n == ETHERADDRL) {
445 while (n-- != 0)
446 smp->sm_bia[n] = ints[n] & 0xff;
447
448 goto done;
449 }
450
451 ddi_prop_free(ints);
452 break;
453
454 default:
455 break;
456 }
457
458 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
459 "local-mac-address", &bytes, &n);
460 switch (err) {
461 case DDI_PROP_SUCCESS:
462 if (n == ETHERADDRL) {
463 bcopy(bytes, smp->sm_bia, ETHERADDRL);
464 goto done;
465 }
466
467 ddi_prop_free(bytes);
468 break;
469
470 default:
471 break;
472 }
473
474 /* D */
475 bcopy(encp->enc_mac_addr, smp->sm_bia, ETHERADDRL);
476
477 done:
478 /* Initialize the statistics */
479 if ((rc = sfxge_mac_kstat_init(sp)) != 0)
480 goto fail4;
481
482 if ((rc = sfxge_phy_kstat_init(sp)) != 0)
483 goto fail5;
484
485 smp->sm_state = SFXGE_MAC_INITIALIZED;
486
487 return (0);
488
489 fail5:
490 DTRACE_PROBE(fail5);
491
492 sfxge_mac_kstat_fini(sp);
493 fail4:
494 DTRACE_PROBE(fail4);
495
496 /* Tear down DMA setup */
497 sfxge_dma_buffer_destroy(esmp);
498 fail3:
499 DTRACE_PROBE(fail3);
500
501 sfxge_phy_fini(sp);
502 fail2:
503 DTRACE_PROBE(fail2);
504
505 /* Destroy the link poll taskq */
506 ddi_taskq_destroy(smp->sm_tqp);
507 smp->sm_tqp = NULL;
508
509 fail1:
510 DTRACE_PROBE1(fail1, int, rc);
511
512 cv_destroy(&(smp->sm_link_poll_kv));
513
514 mutex_destroy(&(smp->sm_lock));
515
516 smp->sm_sp = NULL;
517
518 SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
519
520 return (rc);
521 }
522
523 int
524 sfxge_mac_start(sfxge_t *sp, boolean_t restart)
525 {
526 sfxge_mac_t *smp = &(sp->s_mac);
527 efsys_mem_t *esmp = &(smp->sm_mem);
528 efx_nic_t *enp = sp->s_enp;
529 size_t pdu;
530 int rc;
531
532 mutex_enter(&(smp->sm_lock));
533
534 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
535
536 if ((rc = efx_port_init(enp)) != 0)
537 goto fail1;
538
539 /*
540 * Set up the advertised capabilities that may have been asked for
541 * before the call to efx_port_init().
542 */
543 if ((rc = sfxge_phy_cap_apply(sp, !restart)) != 0)
544 goto fail2;
545
546 /* Set the SDU */
547 pdu = EFX_MAC_PDU(sp->s_mtu);
548 if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
549 goto fail3;
550
551 if ((rc = efx_mac_fcntl_set(enp, smp->sm_fcntl, B_TRUE)) != 0)
552 goto fail4;
553
554 /* Set the unicast address */
555 if ((rc = efx_mac_addr_set(enp, (smp->sm_laa_valid) ?
556 smp->sm_laa : smp->sm_bia)) != 0)
557 goto fail5;
558
559 /* Set the unicast filter */
560 if ((rc = efx_mac_filter_set(enp,
561 (smp->sm_promisc == SFXGE_PROMISC_ALL_PHYS), B_TRUE)) != 0) {
562 goto fail6;
563 };
564
565 /* Set the group hash */
566 if (smp->sm_promisc >= SFXGE_PROMISC_ALL_MULTI) {
567 unsigned int bucket[EFX_MAC_HASH_BITS];
568 unsigned int index;
569
570 for (index = 0; index < EFX_MAC_HASH_BITS; index++)
571 bucket[index] = 1;
572
573 if ((rc = efx_mac_hash_set(enp, bucket)) != 0)
574 goto fail7;
575 } else {
576 if ((rc = efx_mac_hash_set(enp, smp->sm_bucket)) != 0)
577 goto fail8;
578 }
579
580 if (!smp->sm_mac_stats_timer_reqd) {
581 if ((rc = efx_mac_stats_periodic(enp, esmp,
582 SFXGE_MAC_POLL_PERIOD_MS, B_FALSE)) != 0)
583 goto fail9;
584 }
585
586 if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
587 goto fail10;
588
589 smp->sm_state = SFXGE_MAC_STARTED;
590
591 #ifdef _USE_MAC_PRIV_PROP
592 sfxge_gld_priv_prop_rename(sp);
593 #endif
594
595 /*
596 * Start link state polling. For hardware that reports link change
597 * events we still poll once to update the initial link state.
598 */
599 sfxge_mac_poll_start(sp);
600
601 mutex_exit(&(smp->sm_lock));
602 return (0);
603
604 fail10:
605 DTRACE_PROBE(fail10);
606 (void) efx_mac_stats_periodic(enp, esmp, 0, B_FALSE);
607 fail9:
608 DTRACE_PROBE(fail9);
609 fail8:
610 DTRACE_PROBE(fail8);
611 fail7:
612 DTRACE_PROBE(fail7);
613 fail6:
614 DTRACE_PROBE(fail6);
615 fail5:
616 DTRACE_PROBE(fail5);
617 fail4:
618 DTRACE_PROBE(fail4);
619 fail3:
620 DTRACE_PROBE(fail3);
621 fail2:
622 DTRACE_PROBE(fail2);
623 efx_port_fini(enp);
624 fail1:
625 DTRACE_PROBE1(fail1, int, rc);
626
627 mutex_exit(&(smp->sm_lock));
628
629 return (rc);
630 }
631
632
633 static void
634 sfxge_mac_link_update_locked(sfxge_t *sp, efx_link_mode_t mode)
635 {
636 sfxge_mac_t *smp = &(sp->s_mac);
637 const char *change, *duplex;
638 char info[sizeof (": now 10000Mbps FULL duplex")];
639
640 ASSERT(mutex_owned(&(smp->sm_lock)));
641 if (smp->sm_state != SFXGE_MAC_STARTED)
642 return;
643
644 if (smp->sm_link_mode == mode)
645 return;
646
647 smp->sm_link_mode = mode;
648 smp->sm_link_up = B_TRUE;
649
650 switch (smp->sm_link_mode) {
651 case EFX_LINK_UNKNOWN:
652 case EFX_LINK_DOWN:
653 smp->sm_link_speed = 0;
654 smp->sm_link_duplex = SFXGE_LINK_DUPLEX_UNKNOWN;
655 smp->sm_link_up = B_FALSE;
656 break;
657
658 case EFX_LINK_10HDX:
659 case EFX_LINK_10FDX:
660 smp->sm_link_speed = 10;
661 smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_10HDX) ?
662 SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
663 break;
664
665 case EFX_LINK_100HDX:
666 case EFX_LINK_100FDX:
667 smp->sm_link_speed = 100;
668 smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_100HDX) ?
669 SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
670 break;
671
672 case EFX_LINK_1000HDX:
673 case EFX_LINK_1000FDX:
674 smp->sm_link_speed = 1000;
675 smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_1000HDX) ?
676 SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
677 break;
678
679 case EFX_LINK_10000FDX:
680 smp->sm_link_speed = 10000;
681 smp->sm_link_duplex = SFXGE_LINK_DUPLEX_FULL;
682 break;
683
684 default:
685 ASSERT(B_FALSE);
686 break;
687 }
688
689 duplex = (smp->sm_link_duplex == SFXGE_LINK_DUPLEX_FULL) ?
690 "full" : "half";
691 change = (smp->sm_link_up) ? "UP" : "DOWN";
692 snprintf(info, sizeof (info), ": now %dMbps %s duplex",
693 smp->sm_link_speed, duplex);
694
695 cmn_err(CE_NOTE, SFXGE_CMN_ERR "[%s%d] Link %s%s",
696 ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip),
697 change, smp->sm_link_up ? info : "");
698
699 /* Push link state update to the OS */
700 sfxge_gld_link_update(sp);
701 }
702
703 void
704 sfxge_mac_link_update(sfxge_t *sp, efx_link_mode_t mode)
705 {
706 sfxge_mac_t *smp = &(sp->s_mac);
707
708 mutex_enter(&(smp->sm_lock));
709 sfxge_mac_link_update_locked(sp, mode);
710 mutex_exit(&(smp->sm_lock));
711 }
712
713 void
714 sfxge_mac_link_check(sfxge_t *sp, boolean_t *upp)
715 {
716 sfxge_mac_t *smp = &(sp->s_mac);
717
718 mutex_enter(&(smp->sm_lock));
719 *upp = smp->sm_link_up;
720 mutex_exit(&(smp->sm_lock));
721 }
722
723 void
724 sfxge_mac_link_speed_get(sfxge_t *sp, unsigned int *speedp)
725 {
726 sfxge_mac_t *smp = &(sp->s_mac);
727
728 mutex_enter(&(smp->sm_lock));
729 *speedp = smp->sm_link_speed;
730 mutex_exit(&(smp->sm_lock));
731 }
732
733 void
734 sfxge_mac_link_duplex_get(sfxge_t *sp, sfxge_link_duplex_t *duplexp)
735 {
736 sfxge_mac_t *smp = &(sp->s_mac);
737
738 mutex_enter(&(smp->sm_lock));
739 *duplexp = smp->sm_link_duplex;
740 mutex_exit(&(smp->sm_lock));
741 }
742
743 void
744 sfxge_mac_fcntl_get(sfxge_t *sp, unsigned int *fcntlp)
745 {
746 sfxge_mac_t *smp = &(sp->s_mac);
747
748 mutex_enter(&(smp->sm_lock));
749 *fcntlp = smp->sm_fcntl;
750 mutex_exit(&(smp->sm_lock));
751 }
752
753 int
754 sfxge_mac_fcntl_set(sfxge_t *sp, unsigned int fcntl)
755 {
756 sfxge_mac_t *smp = &(sp->s_mac);
757 int rc;
758
759 mutex_enter(&(smp->sm_lock));
760
761 if (smp->sm_fcntl == fcntl)
762 goto done;
763
764 smp->sm_fcntl = fcntl;
765
766 if (smp->sm_state != SFXGE_MAC_STARTED)
767 goto done;
768
769 if ((rc = efx_mac_fcntl_set(sp->s_enp, smp->sm_fcntl, B_TRUE)) != 0)
770 goto fail1;
771
772 done:
773 mutex_exit(&(smp->sm_lock));
774
775 return (0);
776
777 fail1:
778 DTRACE_PROBE1(fail1, int, rc);
779
780 mutex_exit(&(smp->sm_lock));
781
782 return (rc);
783 }
784
785 int
786 sfxge_mac_unicst_get(sfxge_t *sp, sfxge_unicst_type_t type, uint8_t *addr)
787 {
788 sfxge_mac_t *smp = &(sp->s_mac);
789 int rc;
790
791 if (type >= SFXGE_UNICST_NTYPES) {
792 rc = EINVAL;
793 goto fail1;
794 }
795
796 mutex_enter(&(smp->sm_lock));
797
798 if (smp->sm_state != SFXGE_MAC_INITIALIZED &&
799 smp->sm_state != SFXGE_MAC_STARTED) {
800 rc = EFAULT;
801 goto fail2;
802 }
803
804 switch (type) {
805 case SFXGE_UNICST_BIA:
806 bcopy(smp->sm_bia, addr, ETHERADDRL);
807 break;
808
809 case SFXGE_UNICST_LAA:
810 if (!(smp->sm_laa_valid)) {
811 rc = ENOENT;
812 goto fail3;
813 }
814
815 bcopy(smp->sm_laa, addr, ETHERADDRL);
816 break;
817
818 default:
819 ASSERT(B_FALSE);
820 break;
821 }
822
823 mutex_exit(&(smp->sm_lock));
824
825 return (0);
826
827
828 fail3:
829 DTRACE_PROBE(fail3);
830 fail2:
831 DTRACE_PROBE(fail2);
832
833 mutex_exit(&(smp->sm_lock));
834
835 fail1:
836 DTRACE_PROBE1(fail1, int, rc);
837
838 return (rc);
839 }
840
841 int
842 sfxge_mac_unicst_set(sfxge_t *sp, uint8_t *addr)
843 {
844 sfxge_mac_t *smp = &(sp->s_mac);
845 efx_nic_t *enp = sp->s_enp;
846 int rc;
847
848 mutex_enter(&(smp->sm_lock));
849
850 bcopy(addr, smp->sm_laa, ETHERADDRL);
851 smp->sm_laa_valid = B_TRUE;
852
853 if (smp->sm_state != SFXGE_MAC_STARTED)
854 goto done;
855
856 if ((rc = efx_mac_addr_set(enp, smp->sm_laa)) != 0)
857 goto fail1;
858
859 done:
860 mutex_exit(&(smp->sm_lock));
861
862 return (0);
863
864 fail1:
865 DTRACE_PROBE1(fail1, int, rc);
866
867 mutex_exit(&(smp->sm_lock));
868
869 return (rc);
870 }
871
872 int
873 sfxge_mac_promisc_set(sfxge_t *sp, sfxge_promisc_type_t promisc)
874 {
875 sfxge_mac_t *smp = &(sp->s_mac);
876 efx_nic_t *enp = sp->s_enp;
877 int rc;
878
879 mutex_enter(&(smp->sm_lock));
880
881 if (smp->sm_promisc == promisc)
882 goto done;
883
884 smp->sm_promisc = promisc;
885
886 if (smp->sm_state != SFXGE_MAC_STARTED)
887 goto done;
888
889 if ((rc = efx_mac_filter_set(enp, (promisc == SFXGE_PROMISC_ALL_PHYS),
890 B_TRUE)) != 0)
891 goto fail1;
892
893 if (promisc >= SFXGE_PROMISC_ALL_MULTI) {
894 unsigned int bucket[EFX_MAC_HASH_BITS];
895 unsigned int index;
896
897 for (index = 0; index < EFX_MAC_HASH_BITS; index++)
898 bucket[index] = 1;
899
900 if ((rc = efx_mac_hash_set(enp, bucket)) != 0)
901 goto fail2;
902 } else {
903 if ((rc = efx_mac_hash_set(enp, smp->sm_bucket)) != 0)
904 goto fail3;
905 }
906
907 done:
908 mutex_exit(&(smp->sm_lock));
909 return (0);
910
911 fail3:
912 DTRACE_PROBE(fail3);
913 fail2:
914 DTRACE_PROBE(fail2);
915 fail1:
916 DTRACE_PROBE1(fail1, int, rc);
917 mutex_exit(&(smp->sm_lock));
918
919 return (rc);
920 }
921
922 int
923 sfxge_mac_multicst_add(sfxge_t *sp, uint8_t *addr)
924 {
925 sfxge_mac_t *smp = &(sp->s_mac);
926 efx_nic_t *enp = sp->s_enp;
927 uint32_t crc;
928 int rc;
929
930 mutex_enter(&(smp->sm_lock));
931
932 CRC32(crc, addr, ETHERADDRL, 0xffffffff, crc32_table);
933 smp->sm_bucket[crc % EFX_MAC_HASH_BITS]++;
934
935 if (smp->sm_state != SFXGE_MAC_STARTED)
936 goto done;
937
938 if (smp->sm_promisc >= SFXGE_PROMISC_ALL_MULTI)
939 goto done;
940
941 if ((rc = efx_mac_hash_set(enp, smp->sm_bucket)) != 0)
942 goto fail1;
943
944 done:
945 mutex_exit(&(smp->sm_lock));
946 return (0);
947
948 fail1:
949 DTRACE_PROBE1(fail1, int, rc);
950 mutex_exit(&(smp->sm_lock));
951
952 return (rc);
953 }
954
955 int
956 sfxge_mac_multicst_remove(sfxge_t *sp, uint8_t *addr)
957 {
958 sfxge_mac_t *smp = &(sp->s_mac);
959 efx_nic_t *enp = sp->s_enp;
960 uint32_t crc;
961 int rc;
962
963 mutex_enter(&(smp->sm_lock));
964
965 CRC32(crc, addr, ETHERADDRL, 0xffffffff, crc32_table);
966 ASSERT(smp->sm_bucket[crc % EFX_MAC_HASH_BITS] != 0);
967 smp->sm_bucket[crc % EFX_MAC_HASH_BITS]--;
968
969 if (smp->sm_state != SFXGE_MAC_STARTED)
970 goto done;
971
972 if (smp->sm_promisc >= SFXGE_PROMISC_ALL_MULTI)
973 goto done;
974
975 if ((rc = efx_mac_hash_set(enp, smp->sm_bucket)) != 0)
976 goto fail1;
977
978 done:
979 mutex_exit(&(smp->sm_lock));
980 return (0);
981
982 fail1:
983 DTRACE_PROBE1(fail1, int, rc);
984 mutex_exit(&(smp->sm_lock));
985
986 return (rc);
987 }
988
989 static int
990 sfxge_mac_loopback_set(sfxge_t *sp, efx_loopback_type_t type)
991 {
992 sfxge_mac_t *smp = &(sp->s_mac);
993 efx_nic_t *enp = sp->s_enp;
994 int rc;
995
996 mutex_enter(&(smp->sm_lock));
997 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
998
999 if ((rc = efx_port_loopback_set(enp, EFX_LINK_UNKNOWN, type)) != 0)
1000 goto fail1;
1001
1002 mutex_exit(&(smp->sm_lock));
1003 return (0);
1004
1005 fail1:
1006 DTRACE_PROBE1(fail1, int, rc);
1007 mutex_exit(&(smp->sm_lock));
1008
1009 return (rc);
1010 }
1011
1012 int
1013 sfxge_mac_ioctl(sfxge_t *sp, sfxge_mac_ioc_t *smip)
1014 {
1015 int rc;
1016
1017 switch (smip->smi_op) {
1018 case SFXGE_MAC_OP_LOOPBACK: {
1019 efx_loopback_type_t type = smip->smi_data;
1020
1021 if ((rc = sfxge_mac_loopback_set(sp, type)) != 0)
1022 goto fail1;
1023
1024 break;
1025 }
1026 default:
1027 rc = ENOTSUP;
1028 goto fail1;
1029 }
1030
1031 return (0);
1032
1033 fail1:
1034 DTRACE_PROBE1(fail1, int, rc);
1035
1036 return (rc);
1037 }
1038
1039 void
1040 sfxge_mac_stop(sfxge_t *sp)
1041 {
1042 sfxge_mac_t *smp = &(sp->s_mac);
1043 efx_nic_t *enp = sp->s_enp;
1044 efsys_mem_t *esmp = &(smp->sm_mem);
1045
1046 mutex_enter(&(smp->sm_lock));
1047
1048 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
1049 ASSERT3P(smp->sm_sp, ==, sp);
1050 smp->sm_state = SFXGE_MAC_INITIALIZED;
1051
1052 /* If stopping in response to an MC reboot this may fail */
1053 if (!smp->sm_mac_stats_timer_reqd)
1054 (void) efx_mac_stats_periodic(enp, esmp, 0, B_FALSE);
1055
1056 sfxge_mac_poll_stop(sp);
1057
1058 smp->sm_lbolt = 0;
1059
1060 smp->sm_link_up = B_FALSE;
1061 smp->sm_link_speed = 0;
1062 smp->sm_link_duplex = SFXGE_LINK_DUPLEX_UNKNOWN;
1063
1064 /* This may call MCDI */
1065 (void) efx_mac_drain(enp, B_TRUE);
1066
1067 smp->sm_link_mode = EFX_LINK_UNKNOWN;
1068
1069
1070 efx_port_fini(enp);
1071
1072 mutex_exit(&(smp->sm_lock));
1073 }
1074
1075 void
1076 sfxge_mac_fini(sfxge_t *sp)
1077 {
1078 sfxge_mac_t *smp = &(sp->s_mac);
1079 efsys_mem_t *esmp = &(smp->sm_mem);
1080 unsigned int index;
1081
1082 ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
1083 ASSERT3P(smp->sm_sp, ==, sp);
1084
1085 /* Tear down the statistics */
1086 sfxge_phy_kstat_fini(sp);
1087 sfxge_mac_kstat_fini(sp);
1088
1089 smp->sm_state = SFXGE_MAC_UNINITIALIZED;
1090 smp->sm_link_mode = EFX_LINK_UNKNOWN;
1091 smp->sm_promisc = SFXGE_PROMISC_OFF;
1092
1093 /* Clear the group hash */
1094 for (index = 0; index < EFX_MAC_HASH_BITS; index++)
1095 smp->sm_bucket[index] = 0;
1096
1097 bzero(smp->sm_laa, ETHERADDRL);
1098 smp->sm_laa_valid = B_FALSE;
1099
1100 bzero(smp->sm_bia, ETHERADDRL);
1101
1102 smp->sm_fcntl = 0;
1103
1104 /* Finish with PHY DMA memory */
1105 sfxge_phy_fini(sp);
1106
1107 /* Teardown the DMA */
1108 sfxge_dma_buffer_destroy(esmp);
1109
1110 /* Destroy the link poll taskq */
1111 ddi_taskq_destroy(smp->sm_tqp);
1112 smp->sm_tqp = NULL;
1113
1114 mutex_destroy(&(smp->sm_lock));
1115
1116 smp->sm_sp = NULL;
1117
1118 SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
1119 }