1 /*
2 * usbgem.c: General USB to Fast Ethernet mac driver framework
3 *
4 * Copyright (c) 2002-2012 Masayuki Murayama. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the author nor the names of its contributors may be
17 * used to endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE.
32 */
33
34 /*
35 * Copyright 2019 Joyent, Inc.
36 */
37
38 /*
39 * Change log
40 */
41
42 /*
43 * TODO:
44 * implement DELAYED_START
45 */
46
47 /*
48 * System Header files.
49 */
50 #include <sys/types.h>
51 #include <sys/conf.h>
52 #include <sys/debug.h>
53 #include <sys/kmem.h>
54 #include <sys/vtrace.h>
55 #include <sys/ethernet.h>
56 #include <sys/modctl.h>
57 #include <sys/errno.h>
58 #include <sys/ddi.h>
59 #include <sys/sunddi.h>
60 #ifndef USBGEM_CONFIG_GLDv3
61 #include <sys/dlpi.h>
62 #include <sys/strsubr.h>
63 #endif
64 #include <sys/stream.h> /* required for MBLK* */
65 #include <sys/strsun.h> /* required for mionack() */
66 #include <sys/byteorder.h>
67
68 #include <sys/usb/usba.h>
69 #ifdef USBGEM_CONFIG_GLDv3
70 #include <inet/common.h>
71 #include <inet/led.h>
72 #include <inet/mi.h>
73 #include <inet/nd.h>
74 #endif
75
76 /* supplement definitions */
77 extern const char *usb_str_cr(usb_cr_t);
78
79 #ifndef USBGEM_CONFIG_GLDv3
80 #pragma weak gld_linkstate
81 #endif
82 #include <sys/note.h>
83
84 #include "usbgem_mii.h"
85 #include "usbgem.h"
86
87 #ifdef MODULE
88 char ident[] = "usb general ethernet mac driver v" VERSION;
89 #else
90 extern char ident[];
91 #endif
92
93 /* Debugging support */
94 #ifdef USBGEM_DEBUG_LEVEL
95 static int usbgem_debug = USBGEM_DEBUG_LEVEL;
96 #define DPRINTF(n, args) if (usbgem_debug > (n)) cmn_err args
97 #else
98 #define DPRINTF(n, args)
99 #endif
100
101 /*
102 * Useful macros and typedefs
103 */
104 #define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
105 #define DEFAULT_PIPE(dp) ((dp)->reg_data->dev_default_ph)
106 #define VTAG_SIZE 4
107 #define BOOLEAN(x) ((x) != 0)
108 /*
109 * configuration parameters
110 */
111 #define USBDRV_MAJOR_VER 2
112 #define USBDRV_MINOR_VER 0
113
114 #define ETHERHEADERL (sizeof (struct ether_header))
115 #define MAXPKTLEN(dp) ((dp)->mtu + ETHERHEADERL)
116 #define MAXPKTBUF(dp) ((dp)->mtu + ETHERHEADERL + ETHERFCSL)
117
118 #define WATCH_INTERVAL_FAST drv_usectohz(100*1000)
119
120 #define STOP_GRACEFUL B_TRUE
121
122 /*
123 * Private functions
124 */
125 static int usbgem_open_pipes(struct usbgem_dev *dp);
126 static int usbgem_close_pipes(struct usbgem_dev *dp);
127 static void usbgem_intr_cb(usb_pipe_handle_t, usb_intr_req_t *);
128 static void usbgem_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
129 static void usbgem_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
130
131 static int usbgem_mii_start(struct usbgem_dev *);
132 static void usbgem_mii_stop(struct usbgem_dev *);
133
134 /* local buffer management */
135 static int usbgem_init_rx_buf(struct usbgem_dev *);
136
137 /* internal mac interfaces */
138 static void usbgem_tx_timeout(struct usbgem_dev *);
139 static void usbgem_mii_link_watcher(struct usbgem_dev *);
140 static int usbgem_mac_init(struct usbgem_dev *);
141 static int usbgem_mac_start(struct usbgem_dev *);
142 static int usbgem_mac_stop(struct usbgem_dev *, int, boolean_t);
143 static void usbgem_mac_ioctl(struct usbgem_dev *, queue_t *, mblk_t *);
144
145 int usbgem_speed_value[] = {10, 100, 1000};
146
147 static int usbgem_ctrl_retry = 5;
148
149 /* usb event support */
150 static int usbgem_disconnect_cb(dev_info_t *dip);
151 static int usbgem_reconnect_cb(dev_info_t *dip);
152 int usbgem_suspend(dev_info_t *dip);
153 int usbgem_resume(dev_info_t *dip);
154
155 static uint8_t usbgem_bcastaddr[] = {
156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
157 };
158
159 #ifdef MODULE
160 extern struct mod_ops mod_miscops;
161
162 static struct modlmisc modlmisc = {
163 &mod_miscops,
164 "usbgem v" VERSION,
165 };
166
167 static struct modlinkage modlinkage = {
168 MODREV_1, &modlmisc, NULL
169 };
170
171 /*
172 * _init : done
173 */
174 int
175 _init(void)
176 {
177 int status;
178
179 DPRINTF(2, (CE_CONT, "!usbgem: _init: called"));
180 status = mod_install(&modlinkage);
181
182 return (status);
183 }
184
185 /*
186 * _fini : done
187 */
188 int
189 _fini(void)
190 {
191 int status;
192
193 DPRINTF(2, (CE_CONT, "!usbgem: _fini: called"));
194 status = mod_remove(&modlinkage);
195 return (status);
196 }
197
198 int
199 _info(struct modinfo *modinfop)
200 {
201 return (mod_info(&modlinkage, modinfop));
202 }
203 #endif /* MODULE */
204
205 /* ============================================================== */
206 /*
207 * Ether CRC calculation utilities
208 */
209 /* ============================================================== */
210 /*
211 * Ether CRC calculation according to 21143 data sheet
212 */
213 #define CRC32_POLY_LE 0xedb88320
214 uint32_t
215 usbgem_ether_crc_le(const uint8_t *addr)
216 {
217 int idx;
218 int bit;
219 uint_t data;
220 uint32_t crc = 0xffffffff;
221
222 crc = 0xffffffff;
223 for (idx = 0; idx < ETHERADDRL; idx++) {
224 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
225 crc = (crc >> 1) ^
226 (((crc ^ data) & 1) ? CRC32_POLY_LE : 0);
227 }
228 }
229 return (crc);
230 }
231
232 #define CRC32_POLY_BE 0x04c11db7
233 uint32_t
234 usbgem_ether_crc_be(const uint8_t *addr)
235 {
236 int idx;
237 int bit;
238 uint_t data;
239 uint32_t crc;
240
241 crc = 0xffffffff;
242 for (idx = 0; idx < ETHERADDRL; idx++) {
243 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
244 crc = (crc << 1) ^
245 ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
246 }
247 }
248 return (crc);
249 }
250
251 int
252 usbgem_prop_get_int(struct usbgem_dev *dp, char *prop_template, int def_val)
253 {
254 char propname[32];
255
256 (void) sprintf(propname, prop_template, dp->name);
257
258 return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
259 DDI_PROP_DONTPASS, propname, def_val));
260 }
261
262 static int
263 usbgem_population(uint32_t x)
264 {
265 int i;
266 int cnt;
267
268 cnt = 0;
269 for (i = 0; i < 32; i++) {
270 if (x & (1 << i)) {
271 cnt++;
272 }
273 }
274 return (cnt);
275 }
276
277 static clock_t
278 usbgem_timestamp_nz()
279 {
280 clock_t now;
281 now = ddi_get_lbolt();
282 return (now ? now : (clock_t)1);
283 }
284
285 #ifdef USBGEM_DEBUG_LEVEL
286 #ifdef USBGEM_DEBUG_VLAN
287 #ifdef notdef
288 #include <netinet/in.h>
289 #endif
290 static void
291 usbgem_dump_packet(struct usbgem_dev *dp, char *title, mblk_t *mp,
292 boolean_t check_cksum)
293 {
294 char msg[180];
295 uint8_t buf[18+20+20];
296 uint8_t *p;
297 size_t offset;
298 uint_t ethertype;
299 uint_t proto;
300 uint_t ipproto = 0;
301 uint_t iplen;
302 uint_t iphlen;
303 uint_t tcplen;
304 uint_t udplen;
305 uint_t cksum;
306 int rest;
307 int len;
308 char *bp;
309 mblk_t *tp;
310 extern uint_t ip_cksum(mblk_t *, int, uint32_t);
311
312 msg[0] = 0;
313 bp = msg;
314
315 rest = sizeof (buf);
316 offset = 0;
317 for (tp = mp; tp; tp = tp->b_cont) {
318 len = tp->b_wptr - tp->b_rptr;
319 len = min(rest, len);
320 bcopy(tp->b_rptr, &buf[offset], len);
321 rest -= len;
322 offset += len;
323 if (rest == 0) {
324 break;
325 }
326 }
327
328 offset = 0;
329 p = &buf[offset];
330
331 /* ethernet address */
332 sprintf(bp,
333 "ether: %02x:%02x:%02x:%02x:%02x:%02x"
334 " -> %02x:%02x:%02x:%02x:%02x:%02x",
335 p[6], p[7], p[8], p[9], p[10], p[11],
336 p[0], p[1], p[2], p[3], p[4], p[5]);
337 bp = &msg[strlen(msg)];
338
339 /* vlag tag and etherrtype */
340 ethertype = GET_ETHERTYPE(p);
341 if (ethertype == VTAG_TPID) {
342 sprintf(bp, " vtag:0x%04x", GET_NET16(&p[14]));
343 bp = &msg[strlen(msg)];
344
345 offset += VTAG_SIZE;
346 p = &buf[offset];
347 ethertype = GET_ETHERTYPE(p);
348 }
349 sprintf(bp, " type:%04x", ethertype);
350 bp = &msg[strlen(msg)];
351
352 /* ethernet packet length */
353 sprintf(bp, " mblklen:%d", msgdsize(mp));
354 bp = &msg[strlen(msg)];
355 if (mp->b_cont) {
356 sprintf(bp, "(");
357 bp = &msg[strlen(msg)];
358 for (tp = mp; tp; tp = tp->b_cont) {
359 if (tp == mp) {
360 sprintf(bp, "%d", tp->b_wptr - tp->b_rptr);
361 } else {
362 sprintf(bp, "+%d", tp->b_wptr - tp->b_rptr);
363 }
364 bp = &msg[strlen(msg)];
365 }
366 sprintf(bp, ")");
367 bp = &msg[strlen(msg)];
368 }
369
370 if (ethertype != ETHERTYPE_IP) {
371 goto x;
372 }
373
374 /* ip address */
375 offset += sizeof (struct ether_header);
376 p = &buf[offset];
377 ipproto = p[9];
378 iplen = GET_NET16(&p[2]);
379 sprintf(bp, ", ip: %d.%d.%d.%d -> %d.%d.%d.%d proto:%d iplen:%d",
380 p[12], p[13], p[14], p[15],
381 p[16], p[17], p[18], p[19],
382 ipproto, iplen);
383 bp = (void *)&msg[strlen(msg)];
384
385 iphlen = (p[0] & 0xf) * 4;
386
387 /* cksum for psuedo header */
388 cksum = *(uint16_t *)&p[12];
389 cksum += *(uint16_t *)&p[14];
390 cksum += *(uint16_t *)&p[16];
391 cksum += *(uint16_t *)&p[18];
392 cksum += BE_16(ipproto);
393
394 /* tcp or udp protocol header */
395 offset += iphlen;
396 p = &buf[offset];
397 if (ipproto == IPPROTO_TCP) {
398 tcplen = iplen - iphlen;
399 sprintf(bp, ", tcp: len:%d cksum:%x",
400 tcplen, GET_NET16(&p[16]));
401 bp = (void *)&msg[strlen(msg)];
402
403 if (check_cksum) {
404 cksum += BE_16(tcplen);
405 cksum = (uint16_t)ip_cksum(mp, offset, cksum);
406 sprintf(bp, " (%s)",
407 (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
408 bp = (void *)&msg[strlen(msg)];
409 }
410 } else if (ipproto == IPPROTO_UDP) {
411 udplen = GET_NET16(&p[4]);
412 sprintf(bp, ", udp: len:%d cksum:%x",
413 udplen, GET_NET16(&p[6]));
414 bp = (void *)&msg[strlen(msg)];
415
416 if (GET_NET16(&p[6]) && check_cksum) {
417 cksum += *(uint16_t *)&p[4];
418 cksum = (uint16_t)ip_cksum(mp, offset, cksum);
419 sprintf(bp, " (%s)",
420 (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
421 bp = (void *)&msg[strlen(msg)];
422 }
423 }
424 x:
425 cmn_err(CE_CONT, "!%s: %s: %s", dp->name, title, msg);
426 }
427 #endif /* USBGEM_DEBUG_VLAN */
428 #endif /* USBGEM_DEBUG_LEVEL */
429
430 #ifdef GEM_GCC_RUNTIME
431 /*
432 * gcc3 runtime routines
433 */
434 #pragma weak memcmp
435 int
436 memcmp(const void *s1, const void *s2, size_t n)
437 {
438 int i;
439 int ret;
440
441 ret = 0;
442 for (i = 0; i < n; i++) {
443 ret = (int)((uint8_t *)s1)[i] - (int)((uint8_t *)s2)[i];
444 if (ret) {
445 return (ret);
446 }
447 }
448 return (0);
449 }
450
451 #pragma weak memset
452 void *
453 memset(void *s, int c, size_t n)
454 {
455 if ((c & 0xff) == 0) {
456 bzero(s, n);
457 } else {
458 while (n--) {
459 ((uint8_t *)s)[n] = c;
460 }
461 }
462 return (s);
463 }
464
465 #pragma weak _memcpy = memcpy
466 #pragma weak memcpy
467 void *
468 memcpy(void *s1, const void *s2, size_t n)
469 {
470 bcopy(s2, s1, n);
471 return (s1);
472 }
473 #endif /* GEM_GCC_RUNTIME */
474 /* ============================================================== */
475 /*
476 * hardware operations
477 */
478 /* ============================================================== */
479 static int
480 usbgem_hal_reset_chip(struct usbgem_dev *dp)
481 {
482 int err;
483
484 sema_p(&dp->hal_op_lock);
485 err = (*dp->ugc.usbgc_reset_chip)(dp);
486 sema_v(&dp->hal_op_lock);
487 return (err);
488 }
489
490 static int
491 usbgem_hal_init_chip(struct usbgem_dev *dp)
492 {
493 int err;
494
495 sema_p(&dp->hal_op_lock);
496 err = (*dp->ugc.usbgc_init_chip)(dp);
497 sema_v(&dp->hal_op_lock);
498 return (err);
499 }
500
501 static int
502 usbgem_hal_attach_chip(struct usbgem_dev *dp)
503 {
504 int err;
505
506 sema_p(&dp->hal_op_lock);
507 err = (*dp->ugc.usbgc_attach_chip)(dp);
508 sema_v(&dp->hal_op_lock);
509 return (err);
510 }
511
512 static int
513 usbgem_hal_set_rx_filter(struct usbgem_dev *dp)
514 {
515 int err;
516
517 sema_p(&dp->hal_op_lock);
518 err = (*dp->ugc.usbgc_set_rx_filter)(dp);
519 sema_v(&dp->hal_op_lock);
520 return (err);
521 }
522
523 static int
524 usbgem_hal_set_media(struct usbgem_dev *dp)
525 {
526 int err;
527
528 sema_p(&dp->hal_op_lock);
529 err = (*dp->ugc.usbgc_set_media)(dp);
530 sema_v(&dp->hal_op_lock);
531 return (err);
532 }
533
534 static int
535 usbgem_hal_start_chip(struct usbgem_dev *dp)
536 {
537 int err;
538
539 sema_p(&dp->hal_op_lock);
540 err = (*dp->ugc.usbgc_start_chip)(dp);
541 sema_v(&dp->hal_op_lock);
542 return (err);
543 }
544
545 static int
546 usbgem_hal_stop_chip(struct usbgem_dev *dp)
547 {
548 int err;
549
550 sema_p(&dp->hal_op_lock);
551 err = (*dp->ugc.usbgc_stop_chip)(dp);
552 sema_v(&dp->hal_op_lock);
553 return (err);
554 }
555
556 static int
557 usbgem_hal_get_stats(struct usbgem_dev *dp)
558 {
559 int err;
560
561 sema_p(&dp->hal_op_lock);
562 err = (*dp->ugc.usbgc_get_stats)(dp);
563 sema_v(&dp->hal_op_lock);
564 return (err);
565 }
566
567
568 /* ============================================================== */
569 /*
570 * USB pipe management
571 */
572 /* ============================================================== */
573 static boolean_t
574 usbgem_rx_start_unit(struct usbgem_dev *dp, usb_bulk_req_t *req)
575 {
576 mblk_t *mp;
577 int err;
578 usb_flags_t flags;
579
580 ASSERT(req);
581
582 mp = allocb(dp->rx_buf_len, BPRI_MED);
583 if (mp == NULL) {
584 cmn_err(CE_WARN, "!%s: %s: failed to allocate mblk",
585 dp->name, __func__);
586 goto err;
587 }
588
589 req->bulk_len = dp->rx_buf_len;
590 req->bulk_data = mp;
591 req->bulk_client_private = (usb_opaque_t)dp;
592 req->bulk_timeout = 0;
593 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
594 req->bulk_cb = usbgem_bulkin_cb;
595 req->bulk_exc_cb = usbgem_bulkin_cb;
596 req->bulk_completion_reason = 0;
597 req->bulk_cb_flags = 0;
598
599 flags = 0;
600 err = usb_pipe_bulk_xfer(dp->bulkin_pipe, req, flags);
601
602 if (err != USB_SUCCESS) {
603 cmn_err(CE_WARN, "%s: failed to bulk_xfer for rx, err:%d",
604 dp->name, err);
605
606 /* free req and mp */
607 usb_free_bulk_req(req);
608 goto err;
609 }
610 return (B_TRUE);
611 err:
612 return (B_FALSE);
613 }
614
615 /* ============================================================== */
616 /*
617 * Rx/Tx buffer management
618 */
619 /* ============================================================== */
620 static int
621 usbgem_init_rx_buf(struct usbgem_dev *dp)
622 {
623 int i;
624 usb_bulk_req_t *req;
625
626 ASSERT(dp->mac_state == MAC_STATE_ONLINE);
627
628 for (i = 0; i < dp->ugc.usbgc_rx_list_max; i++) {
629 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
630 if (req == NULL) {
631 cmn_err(CE_WARN,
632 "!%s: %s: failed to allocate bulkreq for rx",
633 dp->name, __func__);
634 return (USB_FAILURE);
635 }
636 if (!usbgem_rx_start_unit(dp, req)) {
637 return (USB_FAILURE);
638 }
639 mutex_enter(&dp->rxlock);
640 dp->rx_busy_cnt++;
641 mutex_exit(&dp->rxlock);
642 }
643 return (USB_SUCCESS);
644 }
645
646 /* ============================================================== */
647 /*
648 * memory resource management
649 */
650 /* ============================================================== */
651 static int
652 usbgem_free_memory(struct usbgem_dev *dp)
653 {
654 usb_bulk_req_t *req;
655
656 /* free all tx requst structure */
657 while ((req = dp->tx_free_list) != NULL) {
658 dp->tx_free_list =
659 (usb_bulk_req_t *)req->bulk_client_private;
660 req->bulk_data = NULL;
661 usb_free_bulk_req(req);
662 }
663 return (USB_SUCCESS);
664 }
665
666 static int
667 usbgem_alloc_memory(struct usbgem_dev *dp)
668 {
669 int i;
670 usb_bulk_req_t *req;
671
672 /* allocate tx requests */
673 dp->tx_free_list = NULL;
674 for (i = 0; i < dp->ugc.usbgc_tx_list_max; i++) {
675 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
676 if (req == NULL) {
677 cmn_err(CE_WARN,
678 "%s:%s failed to allocate tx requests",
679 dp->name, __func__);
680
681 /* free partially allocated tx requests */
682 (void) usbgem_free_memory(dp);
683 return (USB_FAILURE);
684 }
685
686 /* add the new one allocated into tx free list */
687 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
688 dp->tx_free_list = req;
689 }
690
691 return (USB_SUCCESS);
692 }
693
694 /* ========================================================== */
695 /*
696 * Start transmission.
697 * Return zero on success,
698 */
699 /* ========================================================== */
700
701 #ifdef TXTIMEOUT_TEST
702 static int usbgem_send_cnt = 0;
703 #endif
704
705 /*
706 * usbgem_send is used only to send data packet into ethernet line.
707 */
708 static mblk_t *
709 usbgem_send_common(struct usbgem_dev *dp, mblk_t *mp, uint32_t flags)
710 {
711 int err;
712 mblk_t *new;
713 usb_bulk_req_t *req;
714 int mcast;
715 int bcast;
716 int len;
717 boolean_t intr;
718 usb_flags_t usb_flags = 0;
719 #ifdef USBGEM_DEBUG_LEVEL
720 usb_pipe_state_t p_state;
721 #endif
722 DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
723
724 intr = (flags & 1) != 0;
725 len = msgdsize(mp);
726 bcast = 0;
727 mcast = 0;
728 if (mp->b_rptr[0] & 1) {
729 if (bcmp(mp->b_rptr, &usbgem_bcastaddr, ETHERADDRL) == 0) {
730 bcast = 1;
731 } else {
732 mcast = 1;
733 }
734 }
735 new = (*dp->ugc.usbgc_tx_make_packet)(dp, mp);
736 if (new == NULL) {
737 /*
738 * no memory resource. we don't stop downstream,
739 * we just discard the packet.
740 */
741 DPRINTF(0, (CE_CONT, "!%s: %s: no memory",
742 dp->name, __func__));
743 freemsg(mp);
744
745 mutex_enter(&dp->txlock);
746 dp->stats.noxmtbuf++;
747 dp->stats.errxmt++;
748 mutex_exit(&dp->txlock);
749
750 return (NULL);
751 }
752
753 ASSERT(new->b_cont == NULL);
754
755 mutex_enter(&dp->txlock);
756 if (dp->tx_free_list == NULL) {
757 /*
758 * no tx free slot
759 */
760 ASSERT(dp->tx_busy_cnt == dp->ugc.usbgc_tx_list_max);
761 mutex_exit(&dp->txlock);
762
763 DPRINTF(4, (CE_CONT, "!%s: %s: no free slot",
764 dp->name, __func__));
765 if (new && new != mp) {
766 /* free reallocated message */
767 freemsg(new);
768 }
769 return (mp);
770 }
771 req = dp->tx_free_list;
772 dp->tx_free_list = (usb_bulk_req_t *)req->bulk_client_private;
773 dp->tx_busy_cnt++;
774
775 if (dp->tx_free_list == NULL) {
776 intr = B_TRUE;
777 }
778 if (intr) {
779 dp->tx_intr_pended++;
780 }
781 DB_TCI(new) = intr;
782 #ifdef USBGEM_DEBUG_LEVEL
783 new->b_datap->db_cksum32 = dp->tx_seq_num;
784 dp->tx_seq_num++;
785 #endif
786 dp->stats.obytes += len;
787 dp->stats.opackets++;
788 if (bcast | mcast) {
789 dp->stats.obcast += bcast;
790 dp->stats.omcast += mcast;
791 }
792 mutex_exit(&dp->txlock);
793
794 DPRINTF(2, (CE_CONT, "!%s: %s: sending", dp->name, __func__));
795
796 req->bulk_len = (long)new->b_wptr - (long)new->b_rptr;
797 req->bulk_data = new;
798 req->bulk_client_private = (usb_opaque_t)dp;
799 req->bulk_timeout = dp->bulkout_timeout; /* in second */
800 req->bulk_attributes = 0;
801 req->bulk_cb = usbgem_bulkout_cb;
802 req->bulk_exc_cb = usbgem_bulkout_cb;
803 req->bulk_completion_reason = 0;
804 req->bulk_cb_flags = 0;
805
806 if (intr) {
807 usb_flags = USB_FLAGS_SLEEP;
808 }
809 if ((err = usb_pipe_bulk_xfer(dp->bulkout_pipe, req, usb_flags))
810 != USB_SUCCESS) {
811
812 /* failed to transfer the packet, discard it. */
813 freemsg(new);
814 req->bulk_data = NULL;
815
816 /* recycle the request block */
817 mutex_enter(&dp->txlock);
818 dp->tx_busy_cnt--;
819 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
820 dp->tx_free_list = req;
821 mutex_exit(&dp->txlock);
822
823 cmn_err(CE_NOTE,
824 "%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
825 dp->name, __func__, err);
826
827 /* we use another flag to indicate error state. */
828 if (dp->fatal_error == (clock_t)0) {
829 dp->fatal_error = usbgem_timestamp_nz();
830 }
831 } else {
832 /* record the start time */
833 dp->tx_start_time = ddi_get_lbolt();
834 }
835
836 if (err == USB_SUCCESS && (usb_flags & USB_FLAGS_SLEEP)) {
837 usbgem_bulkout_cb(dp->bulkout_pipe, req);
838 }
839
840 if (new != mp) {
841 freemsg(mp);
842 }
843 return (NULL);
844 }
845
846 int
847 usbgem_restart_nic(struct usbgem_dev *dp)
848 {
849 int ret;
850 int flags = 0;
851
852 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
853
854 ASSERT(dp->mac_state != MAC_STATE_DISCONNECTED);
855
856 /*
857 * ensure to stop the nic
858 */
859 if (dp->mac_state == MAC_STATE_ONLINE) {
860 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
861 }
862
863 /* now the nic become quiescent, reset the chip */
864 if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
865 cmn_err(CE_WARN, "%s: %s: failed to reset chip",
866 dp->name, __func__);
867 goto err;
868 }
869
870 /*
871 * restore the nic state step by step
872 */
873 if (dp->nic_state < NIC_STATE_INITIALIZED) {
874 goto done;
875 }
876
877 if (usbgem_mac_init(dp) != USB_SUCCESS) {
878 cmn_err(CE_WARN, "%s: %s: failed to initialize chip",
879 dp->name, __func__);
880 goto err;
881 }
882
883 /* setup mac address and enable rx filter */
884 sema_p(&dp->rxfilter_lock);
885 dp->rxmode |= RXMODE_ENABLE;
886 ret = usbgem_hal_set_rx_filter(dp);
887 sema_v(&dp->rxfilter_lock);
888 if (ret != USB_SUCCESS) {
889 goto err;
890 }
891
892 /*
893 * update the link state asynchronously
894 */
895 cv_signal(&dp->link_watcher_wait_cv);
896
897 /*
898 * XXX - a panic happened because of linkdown.
899 * We must check mii_state here, because the link can be down just
900 * before the restart event happen. If the link is down now,
901 * gem_mac_start() will be called from gem_mii_link_check() when
902 * the link become up later.
903 */
904 if (dp->mii_state == MII_STATE_LINKUP) {
905 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
906 goto err;
907 }
908 if (dp->nic_state < NIC_STATE_ONLINE) {
909 goto done;
910 }
911
912 (void) usbgem_mac_start(dp);
913
914 }
915 done:
916 return (USB_SUCCESS);
917 err:
918 #ifdef GEM_CONFIG_FMA
919 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
920 #endif
921 return (USB_FAILURE);
922 }
923
924 static void
925 usbgem_tx_timeout(struct usbgem_dev *dp)
926 {
927 uint_t rwlock;
928 clock_t now;
929
930 for (; ; ) {
931 mutex_enter(&dp->tx_watcher_lock);
932 (void) cv_timedwait(&dp->tx_watcher_cv, &dp->tx_watcher_lock,
933 dp->tx_watcher_interval + ddi_get_lbolt());
934 mutex_exit(&dp->tx_watcher_lock);
935
936 if (dp->tx_watcher_stop) {
937 break;
938 }
939
940 now = ddi_get_lbolt();
941
942 rwlock = RW_READER;
943 again:
944 rw_enter(&dp->dev_state_lock, rwlock);
945
946 if ((dp->mac_state != MAC_STATE_DISCONNECTED &&
947 dp->fatal_error &&
948 now - dp->fatal_error >= dp->ugc.usbgc_tx_timeout) ||
949 (dp->mac_state == MAC_STATE_ONLINE &&
950 dp->mii_state == MII_STATE_LINKUP &&
951 dp->tx_busy_cnt != 0 &&
952 now - dp->tx_start_time >= dp->ugc.usbgc_tx_timeout)) {
953 if (rwlock == RW_READER) {
954 /*
955 * Upgrade dev_state_lock from shared mode
956 * to exclusive mode to restart nic
957 */
958 rwlock = RW_WRITER;
959 rw_exit(&dp->dev_state_lock);
960 goto again;
961 }
962 cmn_err(CE_WARN, "%s: %s: restarting the nic:"
963 " fatal_error:%ld nic_state:%d"
964 " mac_state:%d starttime:%ld",
965 dp->name, __func__,
966 dp->fatal_error ? now - dp->fatal_error: 0,
967 dp->nic_state, dp->mac_state,
968 dp->tx_busy_cnt ? now - dp->tx_start_time : 0);
969
970 (void) usbgem_restart_nic(dp);
971 }
972
973 rw_exit(&dp->dev_state_lock);
974 }
975 }
976
977 static int
978 usbgem_tx_watcher_start(struct usbgem_dev *dp)
979 {
980 int err;
981 kthread_t *wdth;
982
983 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
984
985 /* make a first call of uwgem_lw_link_check() */
986 dp->tx_watcher_stop = 0;
987 dp->tx_watcher_interval = drv_usectohz(1000*1000);
988
989 wdth = thread_create(NULL, 0, usbgem_tx_timeout, dp, 0, &p0,
990 TS_RUN, minclsyspri);
991 if (wdth == NULL) {
992 cmn_err(CE_WARN,
993 "!%s: %s: failed to create a tx_watcher thread",
994 dp->name, __func__);
995 return (USB_FAILURE);
996 }
997 dp->tx_watcher_did = wdth->t_did;
998
999 return (USB_SUCCESS);
1000 }
1001
1002 static void
1003 usbgem_tx_watcher_stop(struct usbgem_dev *dp)
1004 {
1005 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1006 if (dp->tx_watcher_did) {
1007 /* Ensure timer routine stopped */
1008 dp->tx_watcher_stop = 1;
1009 cv_signal(&dp->tx_watcher_cv);
1010 thread_join(dp->tx_watcher_did);
1011 dp->tx_watcher_did = 0;
1012 }
1013 }
1014
1015 /* ================================================================== */
1016 /*
1017 * Callback handlers
1018 */
1019 /* ================================================================== */
1020 static void
1021 usbgem_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1022 {
1023 mblk_t *newmp;
1024 mblk_t *mp;
1025 mblk_t *tp;
1026 uint64_t len = 0;
1027 int pkts = 0;
1028 int bcast = 0;
1029 int mcast = 0;
1030 boolean_t busy;
1031 struct usbgem_dev *dp;
1032
1033 dp = (struct usbgem_dev *)req->bulk_client_private;
1034 mp = req->bulk_data;
1035 req->bulk_data = NULL;
1036
1037 DPRINTF(2, (CE_CONT, "!%s: %s: mp:%p, cr:%s(%d)",
1038 dp->name, __func__, mp,
1039 usb_str_cr(req->bulk_completion_reason),
1040 req->bulk_completion_reason));
1041
1042 /*
1043 * we cannot acquire dev_state_lock because the routine
1044 * must be executed during usbgem_mac_stop() to avoid
1045 * dead lock.
1046 * we use a simle membar operation to get the state correctly.
1047 */
1048 membar_consumer();
1049
1050 if (req->bulk_completion_reason == USB_CR_OK &&
1051 dp->nic_state == NIC_STATE_ONLINE) {
1052 newmp = (*dp->ugc.usbgc_rx_make_packet)(dp, mp);
1053
1054 if (newmp != mp) {
1055 /* the message has been reallocated, free old one */
1056 freemsg(mp);
1057 }
1058
1059 /* the message may includes one or more ethernet packets */
1060 for (tp = newmp; tp; tp = tp->b_next) {
1061 len += (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
1062 pkts++;
1063 if (tp->b_rptr[0] & 1) {
1064 if (bcmp(tp->b_rptr, &usbgem_bcastaddr,
1065 ETHERADDRL) == 0) {
1066 bcast++;
1067 } else {
1068 mcast++;
1069 }
1070 }
1071 }
1072
1073 /* send up if it is a valid packet */
1074 #ifdef USBGEM_CONFIG_GLDv3
1075 mac_rx(dp->mh, NULL, newmp);
1076 #else
1077 while (newmp) {
1078 tp = newmp;
1079 newmp = newmp->b_next;
1080 tp->b_next = NULL;
1081 gld_recv(dp->macinfo, tp);
1082 }
1083 #endif
1084 } else {
1085 freemsg(mp);
1086 len = 0;
1087 }
1088
1089 mutex_enter(&dp->rxlock);
1090 /* update rx_active */
1091 if (dp->rx_active) {
1092 dp->rx_active = dp->mac_state == MAC_STATE_ONLINE;
1093 }
1094
1095 dp->stats.rbytes += len;
1096 dp->stats.rpackets += pkts;
1097 if (bcast | mcast) {
1098 dp->stats.rbcast += bcast;
1099 dp->stats.rmcast += mcast;
1100 }
1101 mutex_exit(&dp->rxlock);
1102
1103 if (dp->rx_active) {
1104 /* prepare to receive the next packets */
1105 if (usbgem_rx_start_unit(dp, req)) {
1106 /* we successed */
1107 goto done;
1108 }
1109 cmn_err(CE_WARN,
1110 "!%s: %s: failed to fill next rx packet",
1111 dp->name, __func__);
1112 /*
1113 * we use another flag to indicate error state.
1114 * if we acquire dev_state_lock for RW_WRITER here,
1115 * usbgem_mac_stop() may hang.
1116 */
1117 if (dp->fatal_error == (clock_t)0) {
1118 dp->fatal_error = usbgem_timestamp_nz();
1119 }
1120 } else {
1121 /* no need to prepare the next packets */
1122 usb_free_bulk_req(req);
1123 }
1124
1125 mutex_enter(&dp->rxlock);
1126 dp->rx_active = B_FALSE;
1127 dp->rx_busy_cnt--;
1128 if (dp->rx_busy_cnt == 0) {
1129 /* wake up someone waits for me */
1130 cv_broadcast(&dp->rx_drain_cv);
1131 }
1132 mutex_exit(&dp->rxlock);
1133 done:
1134 ;
1135 }
1136
1137 static void
1138 usbgem_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1139 {
1140 boolean_t intr;
1141 boolean_t tx_sched;
1142 struct usbgem_dev *dp;
1143
1144 dp = (struct usbgem_dev *)req->bulk_client_private;
1145 tx_sched = B_FALSE;
1146
1147 DPRINTF(2, (CE_CONT,
1148 "!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
1149 dp->name, __func__,
1150 usb_str_cr(req->bulk_completion_reason),
1151 req->bulk_completion_reason,
1152 req->bulk_cb_flags,
1153 dp->tx_busy_cnt));
1154
1155 /* we have finished to transfer the packet into tx fifo */
1156 intr = DB_TCI(req->bulk_data);
1157 freemsg(req->bulk_data);
1158
1159 if (req->bulk_completion_reason != USB_CR_OK &&
1160 dp->fatal_error == (clock_t)0) {
1161 dp->fatal_error = usbgem_timestamp_nz();
1162 }
1163
1164 mutex_enter(&dp->txlock);
1165
1166 if (intr) {
1167 ASSERT(dp->tx_intr_pended > 0);
1168 /* find the last interrupt we have scheduled */
1169 if (--(dp->tx_intr_pended) == 0) {
1170 tx_sched = B_TRUE;
1171 }
1172 }
1173
1174 ASSERT(dp->tx_busy_cnt > 0);
1175 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
1176 dp->tx_free_list = req;
1177 dp->tx_busy_cnt--;
1178
1179 #ifdef CONFIG_TX_LIMITER
1180 if (tx_sched) {
1181 dp->tx_max_packets =
1182 min(dp->tx_max_packets + 1, dp->ugc.usbgc_tx_list_max);
1183 }
1184 #endif
1185 if (dp->mac_state != MAC_STATE_ONLINE && dp->tx_busy_cnt == 0) {
1186 cv_broadcast(&dp->tx_drain_cv);
1187 }
1188
1189 mutex_exit(&dp->txlock);
1190
1191 if (tx_sched) {
1192 #ifdef USBGEM_CONFIG_GLDv3
1193 mac_tx_update(dp->mh);
1194 #else
1195 gld_sched(dp->macinfo);
1196 #endif
1197 }
1198 }
1199
1200 static void
1201 usbgem_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1202 {
1203 struct usbgem_dev *dp;
1204
1205 dp = (struct usbgem_dev *)req->intr_client_private;
1206 dp->stats.intr++;
1207
1208 if (req->intr_completion_reason == USB_CR_OK) {
1209 (*dp->ugc.usbgc_interrupt)(dp, req->intr_data);
1210 }
1211
1212 /* free the request and data */
1213 usb_free_intr_req(req);
1214 }
1215
1216 /* ======================================================================== */
1217 /*
1218 * MII support routines
1219 */
1220 /* ======================================================================== */
1221 static void
1222 usbgem_choose_forcedmode(struct usbgem_dev *dp)
1223 {
1224 /* choose media mode */
1225 if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
1226 dp->speed = USBGEM_SPD_1000;
1227 dp->full_duplex = dp->anadv_1000fdx;
1228 } else if (dp->anadv_100fdx || dp->anadv_100t4) {
1229 dp->speed = USBGEM_SPD_100;
1230 dp->full_duplex = B_TRUE;
1231 } else if (dp->anadv_100hdx) {
1232 dp->speed = USBGEM_SPD_100;
1233 dp->full_duplex = B_FALSE;
1234 } else {
1235 dp->speed = USBGEM_SPD_10;
1236 dp->full_duplex = dp->anadv_10fdx;
1237 }
1238 }
1239
1240 static uint16_t
1241 usbgem_mii_read(struct usbgem_dev *dp, uint_t reg, int *errp)
1242 {
1243 uint16_t val;
1244
1245 sema_p(&dp->hal_op_lock);
1246 val = (*dp->ugc.usbgc_mii_read)(dp, reg, errp);
1247 sema_v(&dp->hal_op_lock);
1248
1249 return (val);
1250 }
1251
1252 static void
1253 usbgem_mii_write(struct usbgem_dev *dp, uint_t reg, uint16_t val, int *errp)
1254 {
1255 sema_p(&dp->hal_op_lock);
1256 (*dp->ugc.usbgc_mii_write)(dp, reg, val, errp);
1257 sema_v(&dp->hal_op_lock);
1258 }
1259
1260 static int
1261 usbgem_mii_probe(struct usbgem_dev *dp)
1262 {
1263 int err;
1264
1265 err = (*dp->ugc.usbgc_mii_probe)(dp);
1266 return (err);
1267 }
1268
1269 static int
1270 usbgem_mii_init(struct usbgem_dev *dp)
1271 {
1272 int err;
1273
1274 err = (*dp->ugc.usbgc_mii_init)(dp);
1275 return (err);
1276 }
1277
1278 #define fc_cap_decode(x) \
1279 ((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) | \
1280 (((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
1281
1282 int
1283 usbgem_mii_config_default(struct usbgem_dev *dp, int *errp)
1284 {
1285 uint16_t mii_stat;
1286 uint16_t val;
1287
1288 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1289
1290 /*
1291 * Configure bits in advertisement register
1292 */
1293 mii_stat = dp->mii_status;
1294
1295 DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
1296 dp->name, __func__, mii_stat, MII_STATUS_BITS));
1297
1298 if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
1299 /* it's funny */
1300 cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
1301 dp->name, mii_stat, MII_STATUS_BITS);
1302 return (USB_FAILURE);
1303 }
1304
1305 /* Do not change the rest of ability bits in advert reg */
1306 val = usbgem_mii_read(dp, MII_AN_ADVERT, errp) & ~MII_ABILITY_ALL;
1307 if (*errp != USB_SUCCESS) {
1308 goto usberr;
1309 }
1310
1311 DPRINTF(0, (CE_CONT,
1312 "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
1313 dp->name, __func__,
1314 dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
1315 dp->anadv_10fdx, dp->anadv_10hdx));
1316
1317 /* set technology bits */
1318 if (dp->anadv_100t4) {
1319 val |= MII_ABILITY_100BASE_T4;
1320 }
1321 if (dp->anadv_100fdx) {
1322 val |= MII_ABILITY_100BASE_TX_FD;
1323 }
1324 if (dp->anadv_100hdx) {
1325 val |= MII_ABILITY_100BASE_TX;
1326 }
1327 if (dp->anadv_10fdx) {
1328 val |= MII_ABILITY_10BASE_T_FD;
1329 }
1330 if (dp->anadv_10hdx) {
1331 val |= MII_ABILITY_10BASE_T;
1332 }
1333
1334 /* set flow control capabilities */
1335 if (dp->anadv_pause) {
1336 val |= MII_ABILITY_PAUSE;
1337 }
1338 if (dp->anadv_asmpause) {
1339 val |= MII_ABILITY_ASM_DIR;
1340 }
1341
1342 DPRINTF(0, (CE_CONT,
1343 "!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
1344 dp->name, __func__, val, MII_ABILITY_BITS,
1345 dp->anadv_pause, dp->anadv_asmpause));
1346
1347 usbgem_mii_write(dp, MII_AN_ADVERT, val, errp);
1348 if (*errp != USB_SUCCESS) {
1349 goto usberr;
1350 }
1351
1352 if (dp->mii_status & MII_STATUS_XSTATUS) {
1353 /*
1354 * 1000Base-T GMII support
1355 */
1356 if (!dp->anadv_autoneg) {
1357 /* enable manual configuration */
1358 val = MII_1000TC_CFG_EN;
1359 if (dp->anadv_1000t_ms == 2) {
1360 val |= MII_1000TC_CFG_VAL;
1361 }
1362 } else {
1363 val = 0;
1364 if (dp->anadv_1000fdx) {
1365 val |= MII_1000TC_ADV_FULL;
1366 }
1367 if (dp->anadv_1000hdx) {
1368 val |= MII_1000TC_ADV_HALF;
1369 }
1370 switch (dp->anadv_1000t_ms) {
1371 case 1:
1372 /* slave */
1373 val |= MII_1000TC_CFG_EN;
1374 break;
1375
1376 case 2:
1377 /* master */
1378 val |= MII_1000TC_CFG_EN | MII_1000TC_CFG_VAL;
1379 break;
1380
1381 default:
1382 /* auto: do nothing */
1383 break;
1384 }
1385 }
1386 DPRINTF(0, (CE_CONT,
1387 "!%s: %s: setting MII_1000TC reg:%b",
1388 dp->name, __func__, val, MII_1000TC_BITS));
1389
1390 usbgem_mii_write(dp, MII_1000TC, val, errp);
1391 if (*errp != USB_SUCCESS) {
1392 goto usberr;
1393 }
1394 }
1395 return (USB_SUCCESS);
1396
1397 usberr:
1398 return (*errp);
1399 }
1400
1401 static char *usbgem_fc_type[] = {
1402 "without",
1403 "with symmetric",
1404 "with tx",
1405 "with rx",
1406 };
1407
1408 #ifdef USBGEM_CONFIG_GLDv3
1409 #define USBGEM_LINKUP(dp) mac_link_update((dp)->mh, LINK_STATE_UP)
1410 #define USBGEM_LINKDOWN(dp) mac_link_update((dp)->mh, LINK_STATE_DOWN)
1411 #else
1412 #define USBGEM_LINKUP(dp) \
1413 if (gld_linkstate) { \
1414 gld_linkstate((dp)->macinfo, GLD_LINKSTATE_UP); \
1415 }
1416 #define USBGEM_LINKDOWN(dp) \
1417 if (gld_linkstate) { \
1418 gld_linkstate((dp)->macinfo, GLD_LINKSTATE_DOWN); \
1419 }
1420 #endif
1421
1422 static uint8_t usbgem_fc_result[4 /* my cap */][4 /* lp cap */] = {
1423 /* none symm tx rx/symm */
1424 /* none */
1425 {FLOW_CONTROL_NONE,
1426 FLOW_CONTROL_NONE,
1427 FLOW_CONTROL_NONE,
1428 FLOW_CONTROL_NONE},
1429 /* sym */
1430 {FLOW_CONTROL_NONE,
1431 FLOW_CONTROL_SYMMETRIC,
1432 FLOW_CONTROL_NONE,
1433 FLOW_CONTROL_SYMMETRIC},
1434 /* tx */
1435 {FLOW_CONTROL_NONE,
1436 FLOW_CONTROL_NONE,
1437 FLOW_CONTROL_NONE,
1438 FLOW_CONTROL_TX_PAUSE},
1439 /* rx/symm */
1440 {FLOW_CONTROL_NONE,
1441 FLOW_CONTROL_SYMMETRIC,
1442 FLOW_CONTROL_RX_PAUSE,
1443 FLOW_CONTROL_SYMMETRIC},
1444 };
1445
1446 static boolean_t
1447 usbgem_mii_link_check(struct usbgem_dev *dp, int *oldstatep, int *newstatep)
1448 {
1449 boolean_t tx_sched = B_FALSE;
1450 uint16_t status;
1451 uint16_t advert;
1452 uint16_t lpable;
1453 uint16_t exp;
1454 uint16_t ctl1000;
1455 uint16_t stat1000;
1456 uint16_t val;
1457 clock_t now;
1458 clock_t diff;
1459 int linkdown_action;
1460 boolean_t fix_phy = B_FALSE;
1461 int err;
1462 uint_t rwlock;
1463
1464 DPRINTF(4, (CE_CONT, "!%s: %s: time:%d state:%d",
1465 dp->name, __func__, ddi_get_lbolt(), dp->mii_state));
1466
1467 if (dp->mii_state != MII_STATE_LINKUP) {
1468 rwlock = RW_WRITER;
1469 } else {
1470 rwlock = RW_READER;
1471 }
1472 again:
1473 rw_enter(&dp->dev_state_lock, rwlock);
1474
1475 /* save old mii state */
1476 *oldstatep = dp->mii_state;
1477
1478 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
1479 /* stop periodic execution of the link watcher */
1480 dp->mii_interval = 0;
1481 tx_sched = B_FALSE;
1482 goto next;
1483 }
1484
1485 now = ddi_get_lbolt();
1486 diff = now - dp->mii_last_check;
1487 dp->mii_last_check = now;
1488
1489 /*
1490 * For NWAM, don't show linkdown state right
1491 * when the device is attached.
1492 */
1493 if (dp->linkup_delay > 0) {
1494 if (dp->linkup_delay > diff) {
1495 dp->linkup_delay -= diff;
1496 } else {
1497 /* link up timeout */
1498 dp->linkup_delay = -1;
1499 }
1500 }
1501
1502 next_nowait:
1503 switch (dp->mii_state) {
1504 case MII_STATE_UNKNOWN:
1505 goto reset_phy;
1506
1507 case MII_STATE_RESETTING:
1508 dp->mii_timer -= diff;
1509 if (dp->mii_timer > 0) {
1510 /* don't read phy registers in resetting */
1511 dp->mii_interval = WATCH_INTERVAL_FAST;
1512 goto next;
1513 }
1514
1515 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1516 if (err != USB_SUCCESS) {
1517 goto usberr;
1518 }
1519 if (val & MII_CONTROL_RESET) {
1520 cmn_err(CE_NOTE,
1521 "!%s: time:%ld resetting phy not complete."
1522 " mii_control:0x%b",
1523 dp->name, ddi_get_lbolt(),
1524 val, MII_CONTROL_BITS);
1525 }
1526
1527 /* ensure neither isolated nor pwrdown nor auto-nego mode */
1528 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1529 if (err != USB_SUCCESS) {
1530 goto usberr;
1531 }
1532 #if USBGEM_DEBUG_LEVEL > 10
1533 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1534 cmn_err(CE_CONT, "!%s: readback control %b",
1535 dp->name, val, MII_CONTROL_BITS);
1536 #endif
1537 /* As resetting PHY has completed, configure PHY registers */
1538 if ((*dp->ugc.usbgc_mii_config)(dp, &err) != USB_SUCCESS) {
1539 /* we failed to configure PHY */
1540 goto usberr;
1541 }
1542
1543 /* prepare for forced mode */
1544 usbgem_choose_forcedmode(dp);
1545
1546 dp->mii_lpable = 0;
1547 dp->mii_advert = 0;
1548 dp->mii_exp = 0;
1549 dp->mii_ctl1000 = 0;
1550 dp->mii_stat1000 = 0;
1551
1552 dp->flow_control = FLOW_CONTROL_NONE;
1553
1554 if (!dp->anadv_autoneg) {
1555 /* skip auto-negotiation phase */
1556 dp->mii_state = MII_STATE_MEDIA_SETUP;
1557 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1558 goto next_nowait;
1559 }
1560
1561 /* issue an auto-negotiation command */
1562 goto autonego;
1563
1564 case MII_STATE_AUTONEGOTIATING:
1565 /*
1566 * Autonegotiation in progress
1567 */
1568 dp->mii_timer -= diff;
1569 if (dp->mii_timer -
1570 (dp->ugc.usbgc_mii_an_timeout - dp->ugc.usbgc_mii_an_wait)
1571 > 0) {
1572 /* wait for minimum time (2.3 - 2.5 sec) */
1573 dp->mii_interval = WATCH_INTERVAL_FAST;
1574 goto next;
1575 }
1576
1577 /* read PHY status */
1578 status = usbgem_mii_read(dp, MII_STATUS, &err);
1579 if (err != USB_SUCCESS) {
1580 goto usberr;
1581 }
1582 DPRINTF(4, (CE_CONT,
1583 "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
1584 dp->name, __func__, dp->mii_state,
1585 status, MII_STATUS_BITS));
1586
1587 if (status & MII_STATUS_REMFAULT) {
1588 /*
1589 * The link parnert told me something wrong happend.
1590 * What do we do ?
1591 */
1592 cmn_err(CE_CONT,
1593 "!%s: auto-negotiation failed: remote fault",
1594 dp->name);
1595 goto autonego;
1596 }
1597
1598 if ((status & MII_STATUS_ANDONE) == 0) {
1599 if (dp->mii_timer <= 0) {
1600 /*
1601 * Auto-negotiation has been timed out,
1602 * Reset PHY and try again.
1603 */
1604 if (!dp->mii_supress_msg) {
1605 cmn_err(CE_WARN,
1606 "!%s: auto-negotiation failed:"
1607 " timeout",
1608 dp->name);
1609 dp->mii_supress_msg = B_TRUE;
1610 }
1611 goto autonego;
1612 }
1613 /*
1614 * Auto-negotiation is in progress. Wait for a while.
1615 */
1616 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1617 goto next;
1618 }
1619
1620 /*
1621 * Auto-negotiation has been completed. Let's go to AN_DONE.
1622 */
1623 dp->mii_state = MII_STATE_AN_DONE;
1624 dp->mii_supress_msg = B_FALSE;
1625 DPRINTF(0, (CE_CONT,
1626 "!%s: auto-negotiation completed, MII_STATUS:%b",
1627 dp->name, status, MII_STATUS_BITS));
1628
1629 if (dp->ugc.usbgc_mii_an_delay > 0) {
1630 dp->mii_timer = dp->ugc.usbgc_mii_an_delay;
1631 dp->mii_interval = drv_usectohz(20*1000);
1632 goto next;
1633 }
1634
1635 dp->mii_timer = 0;
1636 diff = 0;
1637 goto next_nowait;
1638
1639 case MII_STATE_AN_DONE:
1640 /*
1641 * Auto-negotiation has done. Now we can set up media.
1642 */
1643 dp->mii_timer -= diff;
1644 if (dp->mii_timer > 0) {
1645 /* wait for a while */
1646 dp->mii_interval = WATCH_INTERVAL_FAST;
1647 goto next;
1648 }
1649
1650 /*
1651 * Setup speed and duplex mode according with
1652 * the result of auto negotiation.
1653 */
1654
1655 /*
1656 * Read registers required to determin current
1657 * duplex mode and media speed.
1658 */
1659 if (dp->ugc.usbgc_mii_an_delay > 0) {
1660 /* the 'status' variable is not initialized yet */
1661 status = usbgem_mii_read(dp, MII_STATUS, &err);
1662 if (err != USB_SUCCESS) {
1663 goto usberr;
1664 }
1665 }
1666 advert = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
1667 if (err != USB_SUCCESS) {
1668 goto usberr;
1669 }
1670 lpable = usbgem_mii_read(dp, MII_AN_LPABLE, &err);
1671 if (err != USB_SUCCESS) {
1672 goto usberr;
1673 }
1674 exp = usbgem_mii_read(dp, MII_AN_EXPANSION, &err);
1675 if (err != USB_SUCCESS) {
1676 goto usberr;
1677 }
1678 if (exp == 0xffff) {
1679 /* some phys don't have exp register */
1680 exp = 0;
1681 }
1682
1683 ctl1000 = 0;
1684 stat1000 = 0;
1685 if (dp->mii_status & MII_STATUS_XSTATUS) {
1686 ctl1000 = usbgem_mii_read(dp, MII_1000TC, &err);
1687 if (err != USB_SUCCESS) {
1688 goto usberr;
1689 }
1690 stat1000 = usbgem_mii_read(dp, MII_1000TS, &err);
1691 if (err != USB_SUCCESS) {
1692 goto usberr;
1693 }
1694 }
1695 dp->mii_lpable = lpable;
1696 dp->mii_advert = advert;
1697 dp->mii_exp = exp;
1698 dp->mii_ctl1000 = ctl1000;
1699 dp->mii_stat1000 = stat1000;
1700
1701 cmn_err(CE_CONT,
1702 "!%s: auto-negotiation done: "
1703 "status:%b, advert:%b, lpable:%b, exp:%b",
1704 dp->name,
1705 status, MII_STATUS_BITS,
1706 advert, MII_ABILITY_BITS,
1707 lpable, MII_ABILITY_BITS,
1708 exp, MII_AN_EXP_BITS);
1709
1710 DPRINTF(0, (CE_CONT, "!%s: MII_STATUS:%b",
1711 dp->name, status, MII_STATUS_BITS));
1712
1713 if (dp->mii_status & MII_STATUS_XSTATUS) {
1714 cmn_err(CE_CONT,
1715 "! MII_1000TC reg:%b, MII_1000TS reg:%b",
1716 ctl1000, MII_1000TC_BITS,
1717 stat1000, MII_1000TS_BITS);
1718 }
1719
1720 if (usbgem_population(lpable) <= 1 &&
1721 (exp & MII_AN_EXP_LPCANAN) == 0) {
1722 if ((advert & MII_ABILITY_TECH) != lpable) {
1723 cmn_err(CE_WARN,
1724 "!%s: but the link partner doesn't seem"
1725 " to have auto-negotiation capability."
1726 " please check the link configuration.",
1727 dp->name);
1728 }
1729 /*
1730 * it should be a result of pararell detection,
1731 * which cannot detect duplex mode.
1732 */
1733 if ((advert & lpable) == 0 &&
1734 lpable & MII_ABILITY_10BASE_T) {
1735 /* no common technology, try 10M half mode */
1736 lpable |= advert & MII_ABILITY_10BASE_T;
1737 fix_phy = B_TRUE;
1738 }
1739 } else if (lpable == 0) {
1740 cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
1741 goto reset_phy;
1742 }
1743 /*
1744 * configure current link mode according to AN priority.
1745 */
1746 val = advert & lpable;
1747 if ((ctl1000 & MII_1000TC_ADV_FULL) &&
1748 (stat1000 & MII_1000TS_LP_FULL)) {
1749 /* 1000BaseT & full duplex */
1750 dp->speed = USBGEM_SPD_1000;
1751 dp->full_duplex = B_TRUE;
1752 } else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
1753 (stat1000 & MII_1000TS_LP_HALF)) {
1754 /* 1000BaseT & half duplex */
1755 dp->speed = USBGEM_SPD_1000;
1756 dp->full_duplex = B_FALSE;
1757 } else if ((val & MII_ABILITY_100BASE_TX_FD)) {
1758 /* 100BaseTx & fullduplex */
1759 dp->speed = USBGEM_SPD_100;
1760 dp->full_duplex = B_TRUE;
1761 } else if ((val & MII_ABILITY_100BASE_T4)) {
1762 /* 100BaseTx & fullduplex */
1763 dp->speed = USBGEM_SPD_100;
1764 dp->full_duplex = B_TRUE;
1765 } else if ((val & MII_ABILITY_100BASE_TX)) {
1766 /* 100BaseTx & half duplex */
1767 dp->speed = USBGEM_SPD_100;
1768 dp->full_duplex = B_FALSE;
1769 } else if ((val & MII_ABILITY_10BASE_T_FD)) {
1770 /* 10BaseT & full duplex */
1771 dp->speed = USBGEM_SPD_10;
1772 dp->full_duplex = B_TRUE;
1773 } else if ((val & MII_ABILITY_10BASE_T)) {
1774 /* 10BaseT & half duplex */
1775 dp->speed = USBGEM_SPD_10;
1776 dp->full_duplex = B_FALSE;
1777 } else {
1778 /*
1779 * the link partner doesn't seem to have
1780 * auto-negotiation capability and our PHY
1781 * could not report current mode correctly.
1782 * We guess current mode by mii_control register.
1783 */
1784 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1785 if (err != USB_SUCCESS) {
1786 goto usberr;
1787 }
1788
1789 /* select 100m half or 10m half */
1790 dp->speed = (val & MII_CONTROL_100MB) ?
1791 USBGEM_SPD_100 : USBGEM_SPD_10;
1792 dp->full_duplex = B_FALSE;
1793 fix_phy = B_TRUE;
1794
1795 cmn_err(CE_NOTE,
1796 "!%s: auto-negotiation done but "
1797 "common ability not found.\n"
1798 "PHY state: control:%b advert:%b lpable:%b\n"
1799 "guessing %d Mbps %s duplex mode",
1800 dp->name,
1801 val, MII_CONTROL_BITS,
1802 advert, MII_ABILITY_BITS,
1803 lpable, MII_ABILITY_BITS,
1804 usbgem_speed_value[dp->speed],
1805 dp->full_duplex ? "full" : "half");
1806 }
1807
1808 if (dp->full_duplex) {
1809 dp->flow_control =
1810 usbgem_fc_result[fc_cap_decode(advert)]
1811 [fc_cap_decode(lpable)];
1812 } else {
1813 dp->flow_control = FLOW_CONTROL_NONE;
1814 }
1815 dp->mii_state = MII_STATE_MEDIA_SETUP;
1816 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1817 goto next_nowait;
1818
1819 case MII_STATE_MEDIA_SETUP:
1820 DPRINTF(2, (CE_CONT, "!%s: setup midia mode", dp->name));
1821
1822 /* assume the link state is down */
1823 dp->mii_state = MII_STATE_LINKDOWN;
1824 dp->mii_supress_msg = B_FALSE;
1825
1826 /* use short interval */
1827 dp->mii_interval = WATCH_INTERVAL_FAST;
1828
1829 if ((!dp->anadv_autoneg) ||
1830 dp->ugc.usbgc_mii_an_oneshot || fix_phy) {
1831
1832 /*
1833 * write the result of auto negotiation back.
1834 */
1835 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1836 if (err != USB_SUCCESS) {
1837 goto usberr;
1838 }
1839 val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
1840 MII_CONTROL_ANE | MII_CONTROL_RSAN);
1841
1842 if (dp->full_duplex) {
1843 val |= MII_CONTROL_FDUPLEX;
1844 }
1845
1846 switch (dp->speed) {
1847 case USBGEM_SPD_1000:
1848 val |= MII_CONTROL_1000MB;
1849 break;
1850
1851 case USBGEM_SPD_100:
1852 val |= MII_CONTROL_100MB;
1853 break;
1854
1855 default:
1856 cmn_err(CE_WARN, "%s: unknown speed:%d",
1857 dp->name, dp->speed);
1858 /* FALLTHROUGH */
1859
1860 case USBGEM_SPD_10:
1861 /* for USBGEM_SPD_10, do nothing */
1862 break;
1863 }
1864
1865 if (dp->mii_status & MII_STATUS_XSTATUS) {
1866 usbgem_mii_write(dp,
1867 MII_1000TC, MII_1000TC_CFG_EN, &err);
1868 if (err != USB_SUCCESS) {
1869 goto usberr;
1870 }
1871 }
1872 usbgem_mii_write(dp, MII_CONTROL, val, &err);
1873 if (err != USB_SUCCESS) {
1874 goto usberr;
1875 }
1876 }
1877 /*
1878 * XXX -- nic state should be one of
1879 * NIC_STATE_DISCONNECTED
1880 * NIC_STATE_STOPPED
1881 * NIC_STATE_INITIALIZED
1882 * NIC_STATE_ONLINE
1883 */
1884 if (dp->nic_state >= NIC_STATE_INITIALIZED) {
1885 /* notify the result of autonegotiation to mac */
1886 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
1887 goto usberr;
1888 }
1889 }
1890 goto next_nowait;
1891
1892 case MII_STATE_LINKDOWN:
1893 status = usbgem_mii_read(dp, MII_STATUS, &err);
1894 if (err != USB_SUCCESS) {
1895 goto usberr;
1896 }
1897 if (status & MII_STATUS_LINKUP) {
1898 /*
1899 * Link is going up
1900 */
1901 dp->mii_state = MII_STATE_LINKUP;
1902 dp->mii_supress_msg = B_FALSE;
1903
1904 DPRINTF(0, (CE_CONT,
1905 "!%s: link up detected: status:%b",
1906 dp->name, status, MII_STATUS_BITS));
1907
1908 /*
1909 * MII_CONTROL_100MB and MII_CONTROL_FDUPLEX are
1910 * ignored when MII_CONTROL_ANE is set.
1911 */
1912 cmn_err(CE_CONT,
1913 "!%s: Link up: %d Mbps %s duplex %s flow control",
1914 dp->name,
1915 usbgem_speed_value[dp->speed],
1916 dp->full_duplex ? "full" : "half",
1917 usbgem_fc_type[dp->flow_control]);
1918
1919 dp->mii_interval =
1920 dp->ugc.usbgc_mii_link_watch_interval;
1921
1922 if (dp->ugc.usbgc_mii_hw_link_detection &&
1923 dp->nic_state == NIC_STATE_ONLINE) {
1924 dp->mii_interval = 0;
1925 }
1926
1927 if (dp->nic_state == NIC_STATE_ONLINE) {
1928 if (dp->mac_state == MAC_STATE_INITIALIZED) {
1929 (void) usbgem_mac_start(dp);
1930 }
1931 tx_sched = B_TRUE;
1932 }
1933
1934 goto next;
1935 }
1936
1937 dp->mii_supress_msg = B_TRUE;
1938 if (dp->anadv_autoneg) {
1939 dp->mii_timer -= diff;
1940 if (dp->mii_timer <= 0) {
1941 /*
1942 * the link down timer expired.
1943 * need to restart auto-negotiation.
1944 */
1945 linkdown_action =
1946 dp->ugc.usbgc_mii_linkdown_timeout_action;
1947 goto restart_autonego;
1948 }
1949 }
1950 /* don't change mii_state */
1951 goto next;
1952
1953 case MII_STATE_LINKUP:
1954 if (rwlock == RW_READER) {
1955 /* first pass, read mii status */
1956 status = usbgem_mii_read(dp, MII_STATUS, &err);
1957 if (err != USB_SUCCESS) {
1958 goto usberr;
1959 }
1960 }
1961 if ((status & MII_STATUS_LINKUP) == 0) {
1962 /*
1963 * Link is going down
1964 */
1965 cmn_err(CE_NOTE,
1966 "!%s: link down detected: status:%b",
1967 dp->name, status, MII_STATUS_BITS);
1968 /*
1969 * Acquire exclusive lock to change mii_state
1970 */
1971 if (rwlock == RW_READER) {
1972 rwlock = RW_WRITER;
1973 rw_exit(&dp->dev_state_lock);
1974 goto again;
1975 }
1976
1977 dp->mii_state = MII_STATE_LINKDOWN;
1978 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1979
1980 /*
1981 * As we may change the state of the device,
1982 * let us acquire exclusive lock for the state.
1983 */
1984 if (dp->nic_state == NIC_STATE_ONLINE &&
1985 dp->mac_state == MAC_STATE_ONLINE &&
1986 dp->ugc.usbgc_mii_stop_mac_on_linkdown) {
1987 (void) usbgem_restart_nic(dp);
1988 /* drain tx */
1989 tx_sched = B_TRUE;
1990 }
1991
1992 if (dp->anadv_autoneg) {
1993 /* need to restart auto-negotiation */
1994 linkdown_action =
1995 dp->ugc.usbgc_mii_linkdown_action;
1996 goto restart_autonego;
1997 }
1998 /*
1999 * don't use hw link down detection until the link
2000 * status become stable for a while.
2001 */
2002 dp->mii_interval =
2003 dp->ugc.usbgc_mii_link_watch_interval;
2004
2005 goto next;
2006 }
2007
2008 /*
2009 * still link up, no need to change mii_state
2010 */
2011 if (dp->ugc.usbgc_mii_hw_link_detection &&
2012 dp->nic_state == NIC_STATE_ONLINE) {
2013 /*
2014 * no need to check link status periodicly
2015 * if nic can generate interrupts when link go down.
2016 */
2017 dp->mii_interval = 0;
2018 }
2019 goto next;
2020 }
2021 /* NOTREACHED */
2022 cmn_err(CE_PANIC, "!%s: %s: not reached", dp->name, __func__);
2023
2024 /*
2025 * Actions for new state.
2026 */
2027 restart_autonego:
2028 switch (linkdown_action) {
2029 case MII_ACTION_RESET:
2030 if (!dp->mii_supress_msg) {
2031 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2032 }
2033 dp->mii_supress_msg = B_TRUE;
2034 goto reset_phy;
2035
2036 case MII_ACTION_NONE:
2037 dp->mii_supress_msg = B_TRUE;
2038 if (dp->ugc.usbgc_mii_an_oneshot) {
2039 goto autonego;
2040 }
2041 /* PHY will restart autonego automatically */
2042 dp->mii_state = MII_STATE_AUTONEGOTIATING;
2043 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2044 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2045 goto next;
2046
2047 case MII_ACTION_RSA:
2048 if (!dp->mii_supress_msg) {
2049 cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
2050 dp->name);
2051 }
2052 dp->mii_supress_msg = B_TRUE;
2053 goto autonego;
2054
2055 default:
2056 cmn_err(CE_PANIC, "!%s: unknowm linkdown action: %d",
2057 dp->name, dp->ugc.usbgc_mii_linkdown_action);
2058 }
2059 /* NOTREACHED */
2060
2061 reset_phy:
2062 if (!dp->mii_supress_msg) {
2063 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2064 }
2065 dp->mii_state = MII_STATE_RESETTING;
2066 dp->mii_timer = dp->ugc.usbgc_mii_reset_timeout;
2067 if (!dp->ugc.usbgc_mii_dont_reset) {
2068 usbgem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET, &err);
2069 if (err != USB_SUCCESS) {
2070 goto usberr;
2071 }
2072 }
2073 dp->mii_interval = WATCH_INTERVAL_FAST;
2074 goto next;
2075
2076 autonego:
2077 if (!dp->mii_supress_msg) {
2078 cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
2079 }
2080 dp->mii_state = MII_STATE_AUTONEGOTIATING;
2081 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2082
2083 /* start/restart autoneg */
2084 val = usbgem_mii_read(dp, MII_CONTROL, &err) &
2085 ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
2086 if (err != USB_SUCCESS) {
2087 goto usberr;
2088 }
2089 if (val & MII_CONTROL_ANE) {
2090 val |= MII_CONTROL_RSAN;
2091 }
2092 usbgem_mii_write(dp, MII_CONTROL,
2093 val | dp->ugc.usbgc_mii_an_cmd | MII_CONTROL_ANE, &err);
2094 if (err != USB_SUCCESS) {
2095 goto usberr;
2096 }
2097
2098 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2099 goto next;
2100
2101 usberr:
2102 dp->mii_state = MII_STATE_UNKNOWN;
2103 dp->mii_interval = dp->ugc.usbgc_mii_link_watch_interval;
2104 tx_sched = B_TRUE;
2105
2106 next:
2107 *newstatep = dp->mii_state;
2108 rw_exit(&dp->dev_state_lock);
2109 return (tx_sched);
2110 }
2111
2112 static void
2113 usbgem_mii_link_watcher(struct usbgem_dev *dp)
2114 {
2115 int old_mii_state;
2116 int new_mii_state;
2117 boolean_t tx_sched;
2118
2119 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2120
2121 for (; ; ) {
2122
2123 mutex_enter(&dp->link_watcher_lock);
2124 if (dp->mii_interval) {
2125 (void) cv_timedwait(&dp->link_watcher_wait_cv,
2126 &dp->link_watcher_lock,
2127 dp->mii_interval + ddi_get_lbolt());
2128 } else {
2129 cv_wait(&dp->link_watcher_wait_cv,
2130 &dp->link_watcher_lock);
2131 }
2132 mutex_exit(&dp->link_watcher_lock);
2133
2134 if (dp->link_watcher_stop) {
2135 break;
2136 }
2137
2138 /* we block callbacks from disconnect/suspend and restart */
2139 tx_sched = usbgem_mii_link_check(dp,
2140 &old_mii_state, &new_mii_state);
2141
2142 /*
2143 * gld v2 notifier functions are not able to
2144 * be called with any locks in this layer.
2145 */
2146 if (tx_sched) {
2147 /* kick potentially stopped downstream */
2148 #ifdef USBGEM_CONFIG_GLDv3
2149 mac_tx_update(dp->mh);
2150 #else
2151 gld_sched(dp->macinfo);
2152 #endif
2153 }
2154
2155 if (old_mii_state != new_mii_state) {
2156 /* notify new mii link state */
2157 if (new_mii_state == MII_STATE_LINKUP) {
2158 dp->linkup_delay = 0;
2159 USBGEM_LINKUP(dp);
2160 } else if (dp->linkup_delay <= 0) {
2161 USBGEM_LINKDOWN(dp);
2162 }
2163 } else if (dp->linkup_delay < 0) {
2164 /* first linkup timeout */
2165 dp->linkup_delay = 0;
2166 USBGEM_LINKDOWN(dp);
2167 }
2168 }
2169
2170 thread_exit();
2171 }
2172
2173 void
2174 usbgem_mii_update_link(struct usbgem_dev *dp)
2175 {
2176 cv_signal(&dp->link_watcher_wait_cv);
2177 }
2178
2179 int
2180 usbgem_mii_probe_default(struct usbgem_dev *dp)
2181 {
2182 int phy;
2183 uint16_t status;
2184 uint16_t xstatus;
2185 int err;
2186 uint16_t adv;
2187 uint16_t adv_org;
2188
2189 DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2190
2191 /*
2192 * Scan PHY
2193 */
2194 dp->mii_status = 0;
2195
2196 /* Try default phy first */
2197 if (dp->mii_phy_addr) {
2198 status = usbgem_mii_read(dp, MII_STATUS, &err);
2199 if (err != USB_SUCCESS) {
2200 goto usberr;
2201 }
2202 if (status != 0xffff && status != 0x0000) {
2203 goto PHY_found;
2204 }
2205
2206 if (dp->mii_phy_addr < 0) {
2207 cmn_err(CE_NOTE,
2208 "!%s: failed to probe default internal and/or non-MII PHY",
2209 dp->name);
2210 return (USB_FAILURE);
2211 }
2212
2213 cmn_err(CE_NOTE,
2214 "!%s: failed to probe default MII PHY at %d",
2215 dp->name, dp->mii_phy_addr);
2216 }
2217
2218 /* Try all possible address */
2219 for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2220 dp->mii_phy_addr = phy;
2221 status = usbgem_mii_read(dp, MII_STATUS, &err);
2222 if (err != USB_SUCCESS) {
2223 DPRINTF(0, (CE_CONT,
2224 "!%s: %s: mii_read(status) failed",
2225 dp->name, __func__));
2226 goto usberr;
2227 }
2228
2229 if (status != 0xffff && status != 0x0000) {
2230 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2231 if (err != USB_SUCCESS) {
2232 DPRINTF(0, (CE_CONT,
2233 "!%s: %s: mii_write(control) failed",
2234 dp->name, __func__));
2235 goto usberr;
2236 }
2237 goto PHY_found;
2238 }
2239 }
2240 for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2241 dp->mii_phy_addr = phy;
2242 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2243 if (err != USB_SUCCESS) {
2244 DPRINTF(0, (CE_CONT,
2245 "!%s: %s: mii_write(control) failed",
2246 dp->name, __func__));
2247 goto usberr;
2248 }
2249 status = usbgem_mii_read(dp, MII_STATUS, &err);
2250 if (err != USB_SUCCESS) {
2251 DPRINTF(0, (CE_CONT,
2252 "!%s: %s: mii_read(status) failed",
2253 dp->name, __func__));
2254 goto usberr;
2255 }
2256
2257 if (status != 0xffff && status != 0) {
2258 goto PHY_found;
2259 }
2260 }
2261
2262 cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
2263 return (USB_FAILURE);
2264
2265 PHY_found:
2266 dp->mii_status = status;
2267 dp->mii_status_ro = ~status;
2268 dp->mii_phy_id = usbgem_mii_read(dp, MII_PHYIDH, &err) << 16;
2269 if (err != USB_SUCCESS) {
2270 DPRINTF(0, (CE_CONT,
2271 "!%s: %s: mii_read(PHYIDH) failed",
2272 dp->name, __func__));
2273 goto usberr;
2274 }
2275 dp->mii_phy_id |= usbgem_mii_read(dp, MII_PHYIDL, &err);
2276 if (err != USB_SUCCESS) {
2277 DPRINTF(0, (CE_CONT,
2278 "!%s: %s: mii_read(PHYIDL) failed",
2279 dp->name, __func__));
2280 goto usberr;
2281 }
2282
2283 if (dp->mii_phy_addr < 0) {
2284 cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
2285 dp->name, dp->mii_phy_id);
2286 } else {
2287 cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
2288 dp->name, dp->mii_phy_id, dp->mii_phy_addr);
2289 }
2290
2291 cmn_err(CE_CONT,
2292 "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
2293 dp->name,
2294 usbgem_mii_read(dp, MII_CONTROL, &err), MII_CONTROL_BITS,
2295 status, MII_STATUS_BITS,
2296 usbgem_mii_read(dp, MII_AN_ADVERT, &err), MII_ABILITY_BITS,
2297 usbgem_mii_read(dp, MII_AN_LPABLE, &err), MII_ABILITY_BITS,
2298 usbgem_mii_read(dp, MII_AN_EXPANSION, &err), MII_AN_EXP_BITS);
2299
2300 dp->mii_xstatus = 0;
2301 if (status & MII_STATUS_XSTATUS) {
2302 dp->mii_xstatus = usbgem_mii_read(dp, MII_XSTATUS, &err);
2303
2304 cmn_err(CE_CONT, "!%s: xstatus:%b",
2305 dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
2306 }
2307 dp->mii_xstatus_ro = ~dp->mii_xstatus;
2308
2309 /* check if the phy can advertize pause abilities */
2310 adv_org = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2311 if (err != USB_SUCCESS) {
2312 goto usberr;
2313 }
2314
2315 usbgem_mii_write(dp, MII_AN_ADVERT,
2316 MII_ABILITY_PAUSE | MII_ABILITY_ASM_DIR, &err);
2317 if (err != USB_SUCCESS) {
2318 goto usberr;
2319 }
2320
2321 adv = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2322 if (err != USB_SUCCESS) {
2323 goto usberr;
2324 }
2325
2326 if ((adv & MII_ABILITY_PAUSE) == 0) {
2327 dp->ugc.usbgc_flow_control &= ~1;
2328 }
2329
2330 if ((adv & MII_ABILITY_ASM_DIR) == 0) {
2331 dp->ugc.usbgc_flow_control &= ~2;
2332 }
2333
2334 usbgem_mii_write(dp, MII_AN_ADVERT, adv_org, &err);
2335 if (err != USB_SUCCESS) {
2336 goto usberr;
2337 }
2338 return (USB_SUCCESS);
2339
2340 usberr:
2341 return (USB_FAILURE);
2342 }
2343
2344 int
2345 usbgem_mii_init_default(struct usbgem_dev *dp)
2346 {
2347 /* ENPTY */
2348 return (USB_SUCCESS);
2349 }
2350
2351 static int
2352 usbgem_mii_start(struct usbgem_dev *dp)
2353 {
2354 int err;
2355 kthread_t *lwth;
2356
2357 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2358
2359 /* make a first call of usbgem_mii_link_check() */
2360 dp->link_watcher_stop = 0;
2361 dp->mii_state = MII_STATE_UNKNOWN;
2362 dp->mii_interval = drv_usectohz(1000*1000); /* 1sec */
2363 dp->mii_last_check = ddi_get_lbolt();
2364 dp->linkup_delay = 600 * drv_usectohz(1000*1000); /* 10 minutes */
2365
2366 lwth = thread_create(NULL, 0, usbgem_mii_link_watcher, dp, 0, &p0,
2367 TS_RUN, minclsyspri);
2368 if (lwth == NULL) {
2369 cmn_err(CE_WARN,
2370 "!%s: %s: failed to create a link watcher thread",
2371 dp->name, __func__);
2372 return (USB_FAILURE);
2373 }
2374 dp->link_watcher_did = lwth->t_did;
2375
2376 return (USB_SUCCESS);
2377 }
2378
2379 static void
2380 usbgem_mii_stop(struct usbgem_dev *dp)
2381 {
2382 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2383
2384 /* Ensure timer routine stopped */
2385 dp->link_watcher_stop = 1;
2386 cv_signal(&dp->link_watcher_wait_cv);
2387 thread_join(dp->link_watcher_did);
2388 }
2389
2390 /* ============================================================== */
2391 /*
2392 * internal mac register operation interface
2393 */
2394 /* ============================================================== */
2395 /*
2396 * usbgem_mac_init: cold start
2397 */
2398 static int
2399 usbgem_mac_init(struct usbgem_dev *dp)
2400 {
2401 int err;
2402
2403 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2404
2405 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2406 /* pretend we succeeded */
2407 return (USB_SUCCESS);
2408 }
2409
2410 ASSERT(dp->mac_state == MAC_STATE_STOPPED);
2411
2412 /* reset fatal error timestamp */
2413 dp->fatal_error = (clock_t)0;
2414
2415 /* reset tx side state */
2416 mutex_enter(&dp->txlock);
2417 dp->tx_busy_cnt = 0;
2418 dp->tx_max_packets = dp->ugc.usbgc_tx_list_max;
2419 mutex_exit(&dp->txlock);
2420
2421 /* reset rx side state */
2422 mutex_enter(&dp->rxlock);
2423 dp->rx_busy_cnt = 0;
2424 mutex_exit(&dp->rxlock);
2425
2426 err = usbgem_hal_init_chip(dp);
2427 if (err == USB_SUCCESS) {
2428 dp->mac_state = MAC_STATE_INITIALIZED;
2429 }
2430
2431 return (err);
2432 }
2433
2434 /*
2435 * usbgem_mac_start: warm start
2436 */
2437 static int
2438 usbgem_mac_start(struct usbgem_dev *dp)
2439 {
2440 int err;
2441 int i;
2442 usb_flags_t flags = 0;
2443 usb_intr_req_t *req;
2444 #ifdef USBGEM_DEBUG_LEVEL
2445 usb_pipe_state_t p_state;
2446 #endif
2447 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2448
2449 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2450 /* do nothing but don't return failure */
2451 return (USB_SUCCESS);
2452 }
2453
2454 if (dp->mac_state != MAC_STATE_INITIALIZED) {
2455 /* don't return failer */
2456 DPRINTF(0, (CE_CONT,
2457 "!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
2458 dp->name, __func__, dp->mac_state));
2459 goto x;
2460 }
2461
2462 dp->mac_state = MAC_STATE_ONLINE;
2463
2464 if (usbgem_hal_start_chip(dp) != USB_SUCCESS) {
2465 cmn_err(CE_NOTE,
2466 "!%s: %s: usb error was detected during start_chip",
2467 dp->name, __func__);
2468 goto x;
2469 }
2470
2471 #ifdef USBGEM_DEBUG_LEVEL
2472 usb_pipe_get_state(dp->intr_pipe, &p_state, 0);
2473 ASSERT(p_state == USB_PIPE_STATE_IDLE);
2474 #endif /* USBGEM_DEBUG_LEVEL */
2475
2476 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2477
2478 /* make a request for interrupt */
2479
2480 req = usb_alloc_intr_req(dp->dip, 0, USB_FLAGS_SLEEP);
2481 if (req == NULL) {
2482 cmn_err(CE_WARN, "!%s: %s: failed to allocate intreq",
2483 dp->name, __func__);
2484 goto x;
2485 }
2486 req->intr_data = NULL;
2487 req->intr_client_private = (usb_opaque_t)dp;
2488 req->intr_timeout = 0;
2489 req->intr_attributes =
2490 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
2491 req->intr_len = dp->ep_intr->wMaxPacketSize;
2492 req->intr_cb = usbgem_intr_cb;
2493 req->intr_exc_cb = usbgem_intr_cb;
2494 req->intr_completion_reason = 0;
2495 req->intr_cb_flags = 0;
2496
2497 err = usb_pipe_intr_xfer(dp->intr_pipe, req, flags);
2498 if (err != USB_SUCCESS) {
2499 cmn_err(CE_WARN,
2500 "%s: err:%d failed to start polling of intr pipe",
2501 dp->name, err);
2502 goto x;
2503 }
2504 }
2505
2506 /* kick to receive the first packet */
2507 if (usbgem_init_rx_buf(dp) != USB_SUCCESS) {
2508 goto err_stop_intr;
2509 }
2510 dp->rx_active = B_TRUE;
2511
2512 return (USB_SUCCESS);
2513
2514 err_stop_intr:
2515 /* stop the interrupt pipe */
2516 DPRINTF(0, (CE_CONT, "!%s: %s: FAULURE", dp->name, __func__));
2517 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2518 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2519 }
2520 x:
2521 ASSERT(dp->mac_state == MAC_STATE_ONLINE);
2522 /* we use another flag to indicate error state. */
2523 if (dp->fatal_error == (clock_t)0) {
2524 dp->fatal_error = usbgem_timestamp_nz();
2525 }
2526 return (USB_FAILURE);
2527 }
2528
2529 static int
2530 usbgem_mac_stop(struct usbgem_dev *dp, int new_state, boolean_t graceful)
2531 {
2532 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2533
2534 /*
2535 * we must have writer lock for dev_state_lock
2536 */
2537 ASSERT(new_state == MAC_STATE_STOPPED ||
2538 new_state == MAC_STATE_DISCONNECTED);
2539
2540 /* stop polling interrupt pipe */
2541 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2542 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2543 }
2544
2545 if (new_state == MAC_STATE_STOPPED || graceful) {
2546 /* stop the nic hardware completely */
2547 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
2548 (void) usbgem_hal_reset_chip(dp);
2549 }
2550 }
2551
2552 /* stop preparing new rx packets and sending new packets */
2553 dp->mac_state = new_state;
2554
2555 /* other processors must get mac_state correctly after here */
2556 membar_producer();
2557
2558 /* cancel all requests we have sent */
2559 usb_pipe_reset(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
2560 usb_pipe_reset(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
2561
2562 DPRINTF(0, (CE_CONT,
2563 "!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
2564 dp->name, __func__, dp->rx_busy_cnt, dp->tx_busy_cnt));
2565
2566 /*
2567 * Here all rx packets has been cancelled and their call back
2568 * function has been exeuted, because we called usb_pipe_reset
2569 * synchronously.
2570 * So actually we just ensure rx_busy_cnt == 0.
2571 */
2572 mutex_enter(&dp->rxlock);
2573 while (dp->rx_busy_cnt > 0) {
2574 cv_wait(&dp->rx_drain_cv, &dp->rxlock);
2575 }
2576 mutex_exit(&dp->rxlock);
2577
2578 DPRINTF(0, (CE_CONT, "!%s: %s: rx_busy_cnt is %d now",
2579 dp->name, __func__, dp->rx_busy_cnt));
2580
2581 mutex_enter(&dp->txlock);
2582 while (dp->tx_busy_cnt > 0) {
2583 cv_wait(&dp->tx_drain_cv, &dp->txlock);
2584 }
2585 mutex_exit(&dp->txlock);
2586
2587 DPRINTF(0, (CE_CONT, "!%s: %s: tx_busy_cnt is %d now",
2588 dp->name, __func__, dp->tx_busy_cnt));
2589
2590 return (USB_SUCCESS);
2591 }
2592
2593 static int
2594 usbgem_add_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2595 {
2596 int cnt;
2597 int err;
2598
2599 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2600
2601 sema_p(&dp->rxfilter_lock);
2602 if (dp->mc_count_req++ < USBGEM_MAXMC) {
2603 /* append the new address at the end of the mclist */
2604 cnt = dp->mc_count;
2605 bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
2606 ETHERADDRL);
2607 if (dp->ugc.usbgc_multicast_hash) {
2608 dp->mc_list[cnt].hash =
2609 (*dp->ugc.usbgc_multicast_hash)(dp, ep);
2610 }
2611 dp->mc_count = cnt + 1;
2612 }
2613
2614 if (dp->mc_count_req != dp->mc_count) {
2615 /* multicast address list overflow */
2616 dp->rxmode |= RXMODE_MULTI_OVF;
2617 } else {
2618 dp->rxmode &= ~RXMODE_MULTI_OVF;
2619 }
2620
2621 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2622 /* tell new multicast list to the hardware */
2623 err = usbgem_hal_set_rx_filter(dp);
2624 }
2625 sema_v(&dp->rxfilter_lock);
2626
2627 return (err);
2628 }
2629
2630 static int
2631 usbgem_remove_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2632 {
2633 size_t len;
2634 int i;
2635 int cnt;
2636 int err;
2637
2638 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2639
2640 sema_p(&dp->rxfilter_lock);
2641 dp->mc_count_req--;
2642 cnt = dp->mc_count;
2643 for (i = 0; i < cnt; i++) {
2644 if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
2645 continue;
2646 }
2647 /* shrink the mclist by copying forward */
2648 len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
2649 if (len > 0) {
2650 bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
2651 }
2652 dp->mc_count--;
2653 break;
2654 }
2655
2656 if (dp->mc_count_req != dp->mc_count) {
2657 /* multicast address list overflow */
2658 dp->rxmode |= RXMODE_MULTI_OVF;
2659 } else {
2660 dp->rxmode &= ~RXMODE_MULTI_OVF;
2661 }
2662
2663 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2664 err = usbgem_hal_set_rx_filter(dp);
2665 }
2666 sema_v(&dp->rxfilter_lock);
2667
2668 return (err);
2669 }
2670
2671
2672 /* ============================================================== */
2673 /*
2674 * ioctl
2675 */
2676 /* ============================================================== */
2677 enum ioc_reply {
2678 IOC_INVAL = -1, /* bad, NAK with EINVAL */
2679 IOC_DONE, /* OK, reply sent */
2680 IOC_ACK, /* OK, just send ACK */
2681 IOC_REPLY, /* OK, just send reply */
2682 IOC_RESTART_ACK, /* OK, restart & ACK */
2683 IOC_RESTART_REPLY /* OK, restart & reply */
2684 };
2685
2686
2687 #ifdef USBGEM_CONFIG_MAC_PROP
2688 static int
2689 usbgem_get_def_val(struct usbgem_dev *dp, mac_prop_id_t pr_num,
2690 uint_t pr_valsize, void *pr_val)
2691 {
2692 link_flowctrl_t fl;
2693 int err = 0;
2694
2695 ASSERT(pr_valsize > 0);
2696 switch (pr_num) {
2697 case MAC_PROP_AUTONEG:
2698 *(uint8_t *)pr_val =
2699 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
2700 break;
2701
2702 case MAC_PROP_FLOWCTRL:
2703 if (pr_valsize < sizeof (link_flowctrl_t)) {
2704 return (EINVAL);
2705 }
2706 switch (dp->ugc.usbgc_flow_control) {
2707 case FLOW_CONTROL_NONE:
2708 fl = LINK_FLOWCTRL_NONE;
2709 break;
2710 case FLOW_CONTROL_SYMMETRIC:
2711 fl = LINK_FLOWCTRL_BI;
2712 break;
2713 case FLOW_CONTROL_TX_PAUSE:
2714 fl = LINK_FLOWCTRL_TX;
2715 break;
2716 case FLOW_CONTROL_RX_PAUSE:
2717 fl = LINK_FLOWCTRL_RX;
2718 break;
2719 }
2720 bcopy(&fl, pr_val, sizeof (fl));
2721 break;
2722
2723 case MAC_PROP_ADV_1000FDX_CAP:
2724 case MAC_PROP_EN_1000FDX_CAP:
2725 *(uint8_t *)pr_val =
2726 (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
2727 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
2728 break;
2729
2730 case MAC_PROP_ADV_1000HDX_CAP:
2731 case MAC_PROP_EN_1000HDX_CAP:
2732 *(uint8_t *)pr_val =
2733 (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
2734 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
2735 break;
2736
2737 case MAC_PROP_ADV_100T4_CAP:
2738 case MAC_PROP_EN_100T4_CAP:
2739 *(uint8_t *)pr_val =
2740 BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
2741 break;
2742
2743 case MAC_PROP_ADV_100FDX_CAP:
2744 case MAC_PROP_EN_100FDX_CAP:
2745 *(uint8_t *)pr_val =
2746 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
2747 break;
2748
2749 case MAC_PROP_ADV_100HDX_CAP:
2750 case MAC_PROP_EN_100HDX_CAP:
2751 *(uint8_t *)pr_val =
2752 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
2753 break;
2754
2755 case MAC_PROP_ADV_10FDX_CAP:
2756 case MAC_PROP_EN_10FDX_CAP:
2757 *(uint8_t *)pr_val =
2758 BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
2759 break;
2760
2761 case MAC_PROP_ADV_10HDX_CAP:
2762 case MAC_PROP_EN_10HDX_CAP:
2763 *(uint8_t *)pr_val =
2764 BOOLEAN(dp->mii_status & MII_STATUS_10);
2765 break;
2766
2767 default:
2768 err = ENOTSUP;
2769 break;
2770 }
2771 return (err);
2772 }
2773
2774 #ifdef MAC_VERSION_V1
2775 static void
2776 usbgem_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2777 mac_prop_info_handle_t prh)
2778 {
2779 struct usbgem_dev *dp = arg;
2780 link_flowctrl_t fl;
2781
2782 /*
2783 * By default permissions are read/write unless specified
2784 * otherwise by the driver.
2785 */
2786
2787 switch (pr_num) {
2788 case MAC_PROP_DUPLEX:
2789 case MAC_PROP_SPEED:
2790 case MAC_PROP_STATUS:
2791 case MAC_PROP_ADV_1000FDX_CAP:
2792 case MAC_PROP_ADV_1000HDX_CAP:
2793 case MAC_PROP_ADV_100FDX_CAP:
2794 case MAC_PROP_ADV_100HDX_CAP:
2795 case MAC_PROP_ADV_10FDX_CAP:
2796 case MAC_PROP_ADV_10HDX_CAP:
2797 case MAC_PROP_ADV_100T4_CAP:
2798 case MAC_PROP_EN_100T4_CAP:
2799 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2800 break;
2801
2802 case MAC_PROP_EN_1000FDX_CAP:
2803 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0) {
2804 mac_prop_info_set_default_uint8(prh,
2805 BOOLEAN(
2806 dp->mii_xstatus & MII_XSTATUS_1000BASET_FD));
2807 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)
2808 == 0) {
2809 mac_prop_info_set_default_uint8(prh,
2810 BOOLEAN(
2811 dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD));
2812 } else {
2813 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2814 }
2815 break;
2816
2817 case MAC_PROP_EN_1000HDX_CAP:
2818 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0) {
2819 mac_prop_info_set_default_uint8(prh,
2820 BOOLEAN(
2821 dp->mii_xstatus & MII_XSTATUS_1000BASET));
2822 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2823 mac_prop_info_set_default_uint8(prh,
2824 BOOLEAN(
2825 dp->mii_xstatus & MII_XSTATUS_1000BASEX));
2826 } else {
2827 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2828 }
2829 break;
2830
2831 case MAC_PROP_EN_100FDX_CAP:
2832 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2833 mac_prop_info_set_default_uint8(prh,
2834 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD));
2835 } else {
2836 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2837 }
2838 break;
2839
2840 case MAC_PROP_EN_100HDX_CAP:
2841 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2842 mac_prop_info_set_default_uint8(prh,
2843 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX));
2844 } else {
2845 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2846 }
2847 break;
2848
2849 case MAC_PROP_EN_10FDX_CAP:
2850 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2851 mac_prop_info_set_default_uint8(prh,
2852 BOOLEAN(dp->mii_status & MII_STATUS_10_FD));
2853 } else {
2854 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2855 }
2856 break;
2857
2858 case MAC_PROP_EN_10HDX_CAP:
2859 if ((dp->mii_status_ro & MII_STATUS_10) == 0) {
2860 mac_prop_info_set_default_uint8(prh,
2861 BOOLEAN(dp->mii_status & MII_STATUS_10));
2862 } else {
2863 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2864 }
2865 break;
2866
2867 case MAC_PROP_AUTONEG:
2868 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2869 mac_prop_info_set_default_uint8(prh,
2870 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG));
2871 } else {
2872 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2873 }
2874 break;
2875
2876 case MAC_PROP_FLOWCTRL:
2877 switch (dp->ugc.usbgc_flow_control) {
2878 case FLOW_CONTROL_NONE:
2879 fl = LINK_FLOWCTRL_NONE;
2880 break;
2881 case FLOW_CONTROL_SYMMETRIC:
2882 fl = LINK_FLOWCTRL_BI;
2883 break;
2884 case FLOW_CONTROL_TX_PAUSE:
2885 fl = LINK_FLOWCTRL_TX;
2886 break;
2887 case FLOW_CONTROL_RX_PAUSE:
2888 fl = LINK_FLOWCTRL_RX;
2889 break;
2890 }
2891 mac_prop_info_set_default_link_flowctrl(prh, fl);
2892 break;
2893
2894 case MAC_PROP_MTU:
2895 mac_prop_info_set_range_uint32(prh,
2896 dp->ugc.usbgc_min_mtu, dp->ugc.usbgc_max_mtu);
2897 break;
2898
2899 case MAC_PROP_PRIVATE:
2900 break;
2901 }
2902 }
2903 #endif
2904
2905 static int
2906 usbgem_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2907 uint_t pr_valsize, const void *pr_val)
2908 {
2909 struct usbgem_dev *dp = arg;
2910 int err = 0;
2911 boolean_t update = B_FALSE;
2912 link_flowctrl_t flowctrl;
2913 uint32_t cur_mtu, new_mtu;
2914
2915 rw_enter(&dp->dev_state_lock, RW_WRITER);
2916 switch (pr_num) {
2917 case MAC_PROP_EN_1000FDX_CAP:
2918 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0 ||
2919 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD) == 0) {
2920 if (dp->anadv_1000fdx != *(uint8_t *)pr_val) {
2921 dp->anadv_1000fdx = *(uint8_t *)pr_val;
2922 update = B_TRUE;
2923 }
2924 } else {
2925 err = ENOTSUP;
2926 }
2927 break;
2928
2929 case MAC_PROP_EN_1000HDX_CAP:
2930 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0 ||
2931 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2932 if (dp->anadv_1000hdx != *(uint8_t *)pr_val) {
2933 dp->anadv_1000hdx = *(uint8_t *)pr_val;
2934 update = B_TRUE;
2935 }
2936 } else {
2937 err = ENOTSUP;
2938 }
2939 break;
2940
2941 case MAC_PROP_EN_100FDX_CAP:
2942 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2943 if (dp->anadv_100fdx != *(uint8_t *)pr_val) {
2944 dp->anadv_100fdx = *(uint8_t *)pr_val;
2945 update = B_TRUE;
2946 }
2947 } else {
2948 err = ENOTSUP;
2949 }
2950 break;
2951
2952 case MAC_PROP_EN_100HDX_CAP:
2953 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2954 if (dp->anadv_100hdx != *(uint8_t *)pr_val) {
2955 dp->anadv_100hdx = *(uint8_t *)pr_val;
2956 update = B_TRUE;
2957 }
2958 } else {
2959 err = ENOTSUP;
2960 }
2961 break;
2962
2963 case MAC_PROP_EN_10FDX_CAP:
2964 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2965 if (dp->anadv_10fdx != *(uint8_t *)pr_val) {
2966 dp->anadv_10fdx = *(uint8_t *)pr_val;
2967 update = B_TRUE;
2968 }
2969 } else {
2970 err = ENOTSUP;
2971 }
2972 break;
2973
2974 case MAC_PROP_EN_10HDX_CAP:
2975 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2976 if (dp->anadv_10hdx != *(uint8_t *)pr_val) {
2977 dp->anadv_10hdx = *(uint8_t *)pr_val;
2978 update = B_TRUE;
2979 }
2980 } else {
2981 err = ENOTSUP;
2982 }
2983 break;
2984
2985 case MAC_PROP_AUTONEG:
2986 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2987 if (dp->anadv_autoneg != *(uint8_t *)pr_val) {
2988 dp->anadv_autoneg = *(uint8_t *)pr_val;
2989 update = B_TRUE;
2990 }
2991 } else {
2992 err = ENOTSUP;
2993 }
2994 break;
2995
2996 case MAC_PROP_FLOWCTRL:
2997 bcopy(pr_val, &flowctrl, sizeof (flowctrl));
2998
2999 switch (flowctrl) {
3000 default:
3001 err = EINVAL;
3002 break;
3003
3004 case LINK_FLOWCTRL_NONE:
3005 if (dp->flow_control != FLOW_CONTROL_NONE) {
3006 dp->flow_control = FLOW_CONTROL_NONE;
3007 update = B_TRUE;
3008 }
3009 break;
3010
3011 case LINK_FLOWCTRL_RX:
3012 if (dp->flow_control != FLOW_CONTROL_RX_PAUSE) {
3013 dp->flow_control = FLOW_CONTROL_RX_PAUSE;
3014 update = B_TRUE;
3015 }
3016 break;
3017
3018 case LINK_FLOWCTRL_TX:
3019 if (dp->flow_control != FLOW_CONTROL_TX_PAUSE) {
3020 dp->flow_control = FLOW_CONTROL_TX_PAUSE;
3021 update = B_TRUE;
3022 }
3023 break;
3024
3025 case LINK_FLOWCTRL_BI:
3026 if (dp->flow_control != FLOW_CONTROL_SYMMETRIC) {
3027 dp->flow_control = FLOW_CONTROL_SYMMETRIC;
3028 update = B_TRUE;
3029 }
3030 break;
3031 }
3032 break;
3033
3034 case MAC_PROP_ADV_1000FDX_CAP:
3035 case MAC_PROP_ADV_1000HDX_CAP:
3036 case MAC_PROP_ADV_100FDX_CAP:
3037 case MAC_PROP_ADV_100HDX_CAP:
3038 case MAC_PROP_ADV_10FDX_CAP:
3039 case MAC_PROP_ADV_10HDX_CAP:
3040 case MAC_PROP_STATUS:
3041 case MAC_PROP_SPEED:
3042 case MAC_PROP_DUPLEX:
3043 err = ENOTSUP; /* read-only prop. Can't set this. */
3044 break;
3045
3046 case MAC_PROP_MTU:
3047 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
3048 if (new_mtu != dp->mtu) {
3049 err = EINVAL;
3050 }
3051 break;
3052
3053 case MAC_PROP_PRIVATE:
3054 err = ENOTSUP;
3055 break;
3056
3057 default:
3058 err = ENOTSUP;
3059 break;
3060 }
3061
3062 if (update) {
3063 /* sync with PHY */
3064 usbgem_choose_forcedmode(dp);
3065 dp->mii_state = MII_STATE_UNKNOWN;
3066 cv_signal(&dp->link_watcher_wait_cv);
3067 }
3068 rw_exit(&dp->dev_state_lock);
3069 return (err);
3070 }
3071
3072 static int
3073 #ifdef MAC_VERSION_V1
3074 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3075 uint_t pr_valsize, void *pr_val)
3076 #else
3077 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3078 uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
3079 #endif
3080 {
3081 struct usbgem_dev *dp = arg;
3082 int err = 0;
3083 link_flowctrl_t flowctrl;
3084 uint64_t tmp = 0;
3085
3086 if (pr_valsize == 0) {
3087 return (EINVAL);
3088 }
3089 #ifndef MAC_VERSION_V1
3090 *perm = MAC_PROP_PERM_RW;
3091 #endif
3092 bzero(pr_val, pr_valsize);
3093 #ifndef MAC_VERSION_V1
3094 if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE)) {
3095 return (usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val));
3096 }
3097 #endif
3098 rw_enter(&dp->dev_state_lock, RW_READER);
3099 switch (pr_num) {
3100 case MAC_PROP_DUPLEX:
3101 #ifndef MAC_VERSION_V1
3102 *perm = MAC_PROP_PERM_READ;
3103 #endif
3104 if (pr_valsize >= sizeof (link_duplex_t)) {
3105 if (dp->mii_state != MII_STATE_LINKUP) {
3106 *(link_duplex_t *)pr_val = LINK_DUPLEX_UNKNOWN;
3107 } else if (dp->full_duplex) {
3108 *(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
3109 } else {
3110 *(link_duplex_t *)pr_val = LINK_DUPLEX_HALF;
3111 }
3112 } else {
3113 err = EINVAL;
3114 }
3115 break;
3116 case MAC_PROP_SPEED:
3117 #ifndef MAC_VERSION_V1
3118 *perm = MAC_PROP_PERM_READ;
3119 #endif
3120 if (pr_valsize >= sizeof (uint64_t)) {
3121 switch (dp->speed) {
3122 case USBGEM_SPD_1000:
3123 tmp = 1000000000;
3124 break;
3125 case USBGEM_SPD_100:
3126 tmp = 100000000;
3127 break;
3128 case USBGEM_SPD_10:
3129 tmp = 10000000;
3130 break;
3131 default:
3132 tmp = 0;
3133 }
3134 bcopy(&tmp, pr_val, sizeof (tmp));
3135 } else {
3136 err = EINVAL;
3137 }
3138 break;
3139
3140 case MAC_PROP_AUTONEG:
3141 #ifndef MAC_VERSION_V1
3142 if (dp->mii_status_ro & MII_STATUS_CANAUTONEG) {
3143 *perm = MAC_PROP_PERM_READ;
3144 }
3145 #endif
3146 *(uint8_t *)pr_val = dp->anadv_autoneg;
3147 break;
3148
3149 case MAC_PROP_FLOWCTRL:
3150 if (pr_valsize >= sizeof (link_flowctrl_t)) {
3151 switch (dp->flow_control) {
3152 case FLOW_CONTROL_NONE:
3153 flowctrl = LINK_FLOWCTRL_NONE;
3154 break;
3155 case FLOW_CONTROL_RX_PAUSE:
3156 flowctrl = LINK_FLOWCTRL_RX;
3157 break;
3158 case FLOW_CONTROL_TX_PAUSE:
3159 flowctrl = LINK_FLOWCTRL_TX;
3160 break;
3161 case FLOW_CONTROL_SYMMETRIC:
3162 flowctrl = LINK_FLOWCTRL_BI;
3163 break;
3164 }
3165 bcopy(&flowctrl, pr_val, sizeof (flowctrl));
3166 } else {
3167 err = EINVAL;
3168 }
3169 break;
3170
3171 case MAC_PROP_ADV_1000FDX_CAP:
3172 case MAC_PROP_ADV_1000HDX_CAP:
3173 case MAC_PROP_ADV_100FDX_CAP:
3174 case MAC_PROP_ADV_100HDX_CAP:
3175 case MAC_PROP_ADV_10FDX_CAP:
3176 case MAC_PROP_ADV_10HDX_CAP:
3177 case MAC_PROP_ADV_100T4_CAP:
3178 usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val);
3179 break;
3180
3181 case MAC_PROP_EN_1000FDX_CAP:
3182 #ifndef MAC_VERSION_V1
3183 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) &&
3184 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)) {
3185 *perm = MAC_PROP_PERM_READ;
3186 }
3187 #endif
3188 *(uint8_t *)pr_val = dp->anadv_1000fdx;
3189 break;
3190
3191 case MAC_PROP_EN_1000HDX_CAP:
3192 #ifndef MAC_VERSION_V1
3193 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) &&
3194 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX)) {
3195 *perm = MAC_PROP_PERM_READ;
3196 }
3197 #endif
3198 *(uint8_t *)pr_val = dp->anadv_1000hdx;
3199 break;
3200
3201 case MAC_PROP_EN_100FDX_CAP:
3202 #ifndef MAC_VERSION_V1
3203 if (dp->mii_status_ro & MII_STATUS_100_BASEX_FD) {
3204 *perm = MAC_PROP_PERM_READ;
3205 }
3206 #endif
3207 *(uint8_t *)pr_val = dp->anadv_100fdx;
3208 break;
3209
3210 case MAC_PROP_EN_100HDX_CAP:
3211 #ifndef MAC_VERSION_V1
3212 if (dp->mii_status_ro & MII_STATUS_100_BASEX) {
3213 *perm = MAC_PROP_PERM_READ;
3214 }
3215 #endif
3216 *(uint8_t *)pr_val = dp->anadv_100hdx;
3217 break;
3218
3219 case MAC_PROP_EN_10FDX_CAP:
3220 #ifndef MAC_VERSION_V1
3221 if (dp->mii_status_ro & MII_STATUS_10_FD) {
3222 *perm = MAC_PROP_PERM_READ;
3223 }
3224 #endif
3225 *(uint8_t *)pr_val = dp->anadv_10fdx;
3226 break;
3227
3228 case MAC_PROP_EN_10HDX_CAP:
3229 #ifndef MAC_VERSION_V1
3230 if (dp->mii_status_ro & MII_STATUS_10) {
3231 *perm = MAC_PROP_PERM_READ;
3232 }
3233 #endif
3234 *(uint8_t *)pr_val = dp->anadv_10hdx;
3235 break;
3236
3237 case MAC_PROP_EN_100T4_CAP:
3238 #ifndef MAC_VERSION_V1
3239 if (dp->mii_status_ro & MII_STATUS_100_BASE_T4) {
3240 *perm = MAC_PROP_PERM_READ;
3241 }
3242 #endif
3243 *(uint8_t *)pr_val = dp->anadv_100t4;
3244 break;
3245
3246 case MAC_PROP_PRIVATE:
3247 err = ENOTSUP;
3248 break;
3249
3250 #ifndef MAC_VERSION_V1
3251 case MAC_PROP_MTU: {
3252 mac_propval_range_t range;
3253 if (!(pr_flags & MAC_PROP_POSSIBLE)) {
3254 err = ENOTSUP;
3255 break;
3256 }
3257 if (pr_valsize < sizeof (mac_propval_range_t)) {
3258 err = EINVAL;
3259 break;
3260 }
3261 range.mpr_count = 1;
3262 range.mpr_type = MAC_PROPVAL_UINT32;
3263 range.range_uint32[0].mpur_min = ETHERMTU;
3264 range.range_uint32[0].mpur_max = dp->mtu;
3265 bcopy(&range, pr_val, sizeof (range));
3266 break;
3267 }
3268 #endif
3269 default:
3270 err = ENOTSUP;
3271 break;
3272 }
3273
3274 rw_exit(&dp->dev_state_lock);
3275 return (err);
3276 }
3277 #endif /* USBGEM_CONFIG_MAC_PROP */
3278
3279 #ifdef USBGEM_CONFIG_ND
3280 /* ============================================================== */
3281 /*
3282 * ND interface
3283 */
3284 /* ============================================================== */
3285 enum {
3286 PARAM_AUTONEG_CAP,
3287 PARAM_PAUSE_CAP,
3288 PARAM_ASYM_PAUSE_CAP,
3289 PARAM_1000FDX_CAP,
3290 PARAM_1000HDX_CAP,
3291 PARAM_100T4_CAP,
3292 PARAM_100FDX_CAP,
3293 PARAM_100HDX_CAP,
3294 PARAM_10FDX_CAP,
3295 PARAM_10HDX_CAP,
3296
3297 PARAM_ADV_AUTONEG_CAP,
3298 PARAM_ADV_PAUSE_CAP,
3299 PARAM_ADV_ASYM_PAUSE_CAP,
3300 PARAM_ADV_1000FDX_CAP,
3301 PARAM_ADV_1000HDX_CAP,
3302 PARAM_ADV_100T4_CAP,
3303 PARAM_ADV_100FDX_CAP,
3304 PARAM_ADV_100HDX_CAP,
3305 PARAM_ADV_10FDX_CAP,
3306 PARAM_ADV_10HDX_CAP,
3307 PARAM_ADV_1000T_MS,
3308
3309 PARAM_LP_AUTONEG_CAP,
3310 PARAM_LP_PAUSE_CAP,
3311 PARAM_LP_ASYM_PAUSE_CAP,
3312 PARAM_LP_1000FDX_CAP,
3313 PARAM_LP_1000HDX_CAP,
3314 PARAM_LP_100T4_CAP,
3315 PARAM_LP_100FDX_CAP,
3316 PARAM_LP_100HDX_CAP,
3317 PARAM_LP_10FDX_CAP,
3318 PARAM_LP_10HDX_CAP,
3319
3320 PARAM_LINK_STATUS,
3321 PARAM_LINK_SPEED,
3322 PARAM_LINK_DUPLEX,
3323
3324 PARAM_LINK_AUTONEG,
3325 PARAM_LINK_RX_PAUSE,
3326 PARAM_LINK_TX_PAUSE,
3327
3328 PARAM_LOOP_MODE,
3329 PARAM_MSI_CNT,
3330 #ifdef DEBUG_RESUME
3331 PARAM_RESUME_TEST,
3332 #endif
3333
3334 PARAM_COUNT
3335 };
3336
3337 struct usbgem_nd_arg {
3338 struct usbgem_dev *dp;
3339 int item;
3340 };
3341
3342 static int
3343 usbgem_param_get(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
3344 {
3345 struct usbgem_dev *dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3346 int item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3347 long val;
3348
3349 DPRINTF(1, (CE_CONT, "!%s: %s: called, item:%d",
3350 dp->name, __func__, item));
3351
3352 switch (item) {
3353 case PARAM_AUTONEG_CAP:
3354 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
3355 DPRINTF(1, (CE_CONT, "autoneg_cap:%d", val));
3356 break;
3357
3358 case PARAM_PAUSE_CAP:
3359 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
3360 break;
3361
3362 case PARAM_ASYM_PAUSE_CAP:
3363 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
3364 break;
3365
3366 case PARAM_1000FDX_CAP:
3367 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
3368 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
3369 break;
3370
3371 case PARAM_1000HDX_CAP:
3372 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
3373 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
3374 break;
3375
3376 case PARAM_100T4_CAP:
3377 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
3378 break;
3379
3380 case PARAM_100FDX_CAP:
3381 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
3382 break;
3383
3384 case PARAM_100HDX_CAP:
3385 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
3386 break;
3387
3388 case PARAM_10FDX_CAP:
3389 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
3390 break;
3391
3392 case PARAM_10HDX_CAP:
3393 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
3394 break;
3395
3396 case PARAM_ADV_AUTONEG_CAP:
3397 val = dp->anadv_autoneg;
3398 break;
3399
3400 case PARAM_ADV_PAUSE_CAP:
3401 val = dp->anadv_pause;
3402 break;
3403
3404 case PARAM_ADV_ASYM_PAUSE_CAP:
3405 val = dp->anadv_asmpause;
3406 break;
3407
3408 case PARAM_ADV_1000FDX_CAP:
3409 val = dp->anadv_1000fdx;
3410 break;
3411
3412 case PARAM_ADV_1000HDX_CAP:
3413 val = dp->anadv_1000hdx;
3414 break;
3415
3416 case PARAM_ADV_100T4_CAP:
3417 val = dp->anadv_100t4;
3418 break;
3419
3420 case PARAM_ADV_100FDX_CAP:
3421 val = dp->anadv_100fdx;
3422 break;
3423
3424 case PARAM_ADV_100HDX_CAP:
3425 val = dp->anadv_100hdx;
3426 break;
3427
3428 case PARAM_ADV_10FDX_CAP:
3429 val = dp->anadv_10fdx;
3430 break;
3431
3432 case PARAM_ADV_10HDX_CAP:
3433 val = dp->anadv_10hdx;
3434 break;
3435
3436 case PARAM_ADV_1000T_MS:
3437 val = dp->anadv_1000t_ms;
3438 break;
3439
3440 case PARAM_LP_AUTONEG_CAP:
3441 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3442 break;
3443
3444 case PARAM_LP_PAUSE_CAP:
3445 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
3446 break;
3447
3448 case PARAM_LP_ASYM_PAUSE_CAP:
3449 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
3450 break;
3451
3452 case PARAM_LP_1000FDX_CAP:
3453 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
3454 break;
3455
3456 case PARAM_LP_1000HDX_CAP:
3457 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
3458 break;
3459
3460 case PARAM_LP_100T4_CAP:
3461 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
3462 break;
3463
3464 case PARAM_LP_100FDX_CAP:
3465 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
3466 break;
3467
3468 case PARAM_LP_100HDX_CAP:
3469 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
3470 break;
3471
3472 case PARAM_LP_10FDX_CAP:
3473 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
3474 break;
3475
3476 case PARAM_LP_10HDX_CAP:
3477 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
3478 break;
3479
3480 case PARAM_LINK_STATUS:
3481 val = (dp->mii_state == MII_STATE_LINKUP);
3482 break;
3483
3484 case PARAM_LINK_SPEED:
3485 val = usbgem_speed_value[dp->speed];
3486 break;
3487
3488 case PARAM_LINK_DUPLEX:
3489 val = 0;
3490 if (dp->mii_state == MII_STATE_LINKUP) {
3491 val = dp->full_duplex ? 2 : 1;
3492 }
3493 break;
3494
3495 case PARAM_LINK_AUTONEG:
3496 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3497 break;
3498
3499 case PARAM_LINK_RX_PAUSE:
3500 val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3501 (dp->flow_control == FLOW_CONTROL_RX_PAUSE);
3502 break;
3503
3504 case PARAM_LINK_TX_PAUSE:
3505 val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3506 (dp->flow_control == FLOW_CONTROL_TX_PAUSE);
3507 break;
3508
3509 #ifdef DEBUG_RESUME
3510 case PARAM_RESUME_TEST:
3511 val = 0;
3512 break;
3513 #endif
3514 default:
3515 cmn_err(CE_WARN, "%s: unimplemented ndd control (%d)",
3516 dp->name, item);
3517 break;
3518 }
3519
3520 (void) mi_mpprintf(mp, "%ld", val);
3521
3522 return (0);
3523 }
3524
3525 static int
3526 usbgem_param_set(queue_t *q,
3527 mblk_t *mp, char *value, caddr_t arg, cred_t *credp)
3528 {
3529 struct usbgem_dev *dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3530 int item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3531 long val;
3532 char *end;
3533
3534 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3535 if (ddi_strtol(value, &end, 10, &val)) {
3536 return (EINVAL);
3537 }
3538 if (end == value) {
3539 return (EINVAL);
3540 }
3541
3542 switch (item) {
3543 case PARAM_ADV_AUTONEG_CAP:
3544 if (val != 0 && val != 1) {
3545 goto err;
3546 }
3547 if (val && (dp->mii_status & MII_STATUS_CANAUTONEG) == 0) {
3548 goto err;
3549 }
3550 dp->anadv_autoneg = (int)val;
3551 break;
3552
3553 case PARAM_ADV_PAUSE_CAP:
3554 if (val != 0 && val != 1) {
3555 goto err;
3556 }
3557 if (val && dp->ugc.usbgc_flow_control == FLOW_CONTROL_NONE) {
3558 goto err;
3559 }
3560 dp->anadv_pause = (int)val;
3561 break;
3562
3563 case PARAM_ADV_ASYM_PAUSE_CAP:
3564 if (val != 0 && val != 1) {
3565 goto err;
3566 }
3567 if (val &&
3568 dp->ugc.usbgc_flow_control <= FLOW_CONTROL_SYMMETRIC) {
3569 goto err;
3570 }
3571 dp->anadv_asmpause = (int)val;
3572 break;
3573
3574 case PARAM_ADV_1000FDX_CAP:
3575 if (val != 0 && val != 1) {
3576 goto err;
3577 }
3578 if (val && (dp->mii_xstatus &
3579 (MII_XSTATUS_1000BASET_FD |
3580 MII_XSTATUS_1000BASEX_FD)) == 0) {
3581 goto err;
3582 }
3583 dp->anadv_1000fdx = (int)val;
3584 break;
3585
3586 case PARAM_ADV_1000HDX_CAP:
3587 if (val != 0 && val != 1) {
3588 goto err;
3589 }
3590 if (val && (dp->mii_xstatus &
3591 (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASEX)) == 0) {
3592 goto err;
3593 }
3594 dp->anadv_1000hdx = (int)val;
3595 break;
3596
3597 case PARAM_ADV_100T4_CAP:
3598 if (val != 0 && val != 1) {
3599 goto err;
3600 }
3601 if (val && (dp->mii_status & MII_STATUS_100_BASE_T4) == 0) {
3602 goto err;
3603 }
3604 dp->anadv_100t4 = (int)val;
3605 break;
3606
3607 case PARAM_ADV_100FDX_CAP:
3608 if (val != 0 && val != 1) {
3609 goto err;
3610 }
3611 if (val && (dp->mii_status & MII_STATUS_100_BASEX_FD) == 0) {
3612 goto err;
3613 }
3614 dp->anadv_100fdx = (int)val;
3615 break;
3616
3617 case PARAM_ADV_100HDX_CAP:
3618 if (val != 0 && val != 1) {
3619 goto err;
3620 }
3621 if (val && (dp->mii_status & MII_STATUS_100_BASEX) == 0) {
3622 goto err;
3623 }
3624 dp->anadv_100hdx = (int)val;
3625 break;
3626
3627 case PARAM_ADV_10FDX_CAP:
3628 if (val != 0 && val != 1) {
3629 goto err;
3630 }
3631 if (val && (dp->mii_status & MII_STATUS_10_FD) == 0) {
3632 goto err;
3633 }
3634 dp->anadv_10fdx = (int)val;
3635 break;
3636
3637 case PARAM_ADV_10HDX_CAP:
3638 if (val != 0 && val != 1) {
3639 goto err;
3640 }
3641 if (val && (dp->mii_status & MII_STATUS_10) == 0) {
3642 goto err;
3643 }
3644 dp->anadv_10hdx = (int)val;
3645 break;
3646
3647 case PARAM_ADV_1000T_MS:
3648 if (val != 0 && val != 1 && val != 2) {
3649 goto err;
3650 }
3651 if (val && (dp->mii_xstatus &
3652 (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASET_FD)) == 0) {
3653 goto err;
3654 }
3655 dp->anadv_1000t_ms = (int)val;
3656 break;
3657
3658 #ifdef DEBUG_RESUME
3659 case PARAM_RESUME_TEST:
3660 mutex_exit(&dp->xmitlock);
3661 mutex_exit(&dp->intrlock);
3662 gem_suspend(dp->dip);
3663 gem_resume(dp->dip);
3664 mutex_enter(&dp->intrlock);
3665 mutex_enter(&dp->xmitlock);
3666 break;
3667 #endif
3668 }
3669
3670 /* sync with PHY */
3671 usbgem_choose_forcedmode(dp);
3672
3673 dp->mii_state = MII_STATE_UNKNOWN;
3674 if (dp->ugc.usbgc_mii_hw_link_detection) {
3675 /* wake up link watcher possiblely sleeps */
3676 cv_signal(&dp->link_watcher_wait_cv);
3677 }
3678
3679 return (0);
3680 err:
3681 return (EINVAL);
3682 }
3683
3684 static void
3685 usbgem_nd_load(struct usbgem_dev *dp,
3686 char *name, ndgetf_t gf, ndsetf_t sf, int item)
3687 {
3688 struct usbgem_nd_arg *arg;
3689
3690 ASSERT(item >= 0);
3691 ASSERT(item < PARAM_COUNT);
3692
3693 arg = &((struct usbgem_nd_arg *)(void *)dp->nd_arg_p)[item];
3694 arg->dp = dp;
3695 arg->item = item;
3696
3697 DPRINTF(2, (CE_CONT, "!%s: %s: name:%s, item:%d",
3698 dp->name, __func__, name, item));
3699 (void) nd_load(&dp->nd_data_p, name, gf, sf, (caddr_t)arg);
3700 }
3701
3702 static void
3703 usbgem_nd_setup(struct usbgem_dev *dp)
3704 {
3705 DPRINTF(1, (CE_CONT, "!%s: %s: called, mii_status:0x%b",
3706 dp->name, __func__, dp->mii_status, MII_STATUS_BITS));
3707
3708 ASSERT(dp->nd_arg_p == NULL);
3709
3710 dp->nd_arg_p =
3711 kmem_zalloc(sizeof (struct usbgem_nd_arg) * PARAM_COUNT, KM_SLEEP);
3712
3713 #define SETFUNC(x) ((x) ? usbgem_param_set : NULL)
3714
3715 usbgem_nd_load(dp, "autoneg_cap",
3716 usbgem_param_get, NULL, PARAM_AUTONEG_CAP);
3717 usbgem_nd_load(dp, "pause_cap",
3718 usbgem_param_get, NULL, PARAM_PAUSE_CAP);
3719 usbgem_nd_load(dp, "asym_pause_cap",
3720 usbgem_param_get, NULL, PARAM_ASYM_PAUSE_CAP);
3721 usbgem_nd_load(dp, "1000fdx_cap",
3722 usbgem_param_get, NULL, PARAM_1000FDX_CAP);
3723 usbgem_nd_load(dp, "1000hdx_cap",
3724 usbgem_param_get, NULL, PARAM_1000HDX_CAP);
3725 usbgem_nd_load(dp, "100T4_cap",
3726 usbgem_param_get, NULL, PARAM_100T4_CAP);
3727 usbgem_nd_load(dp, "100fdx_cap",
3728 usbgem_param_get, NULL, PARAM_100FDX_CAP);
3729 usbgem_nd_load(dp, "100hdx_cap",
3730 usbgem_param_get, NULL, PARAM_100HDX_CAP);
3731 usbgem_nd_load(dp, "10fdx_cap",
3732 usbgem_param_get, NULL, PARAM_10FDX_CAP);
3733 usbgem_nd_load(dp, "10hdx_cap",
3734 usbgem_param_get, NULL, PARAM_10HDX_CAP);
3735
3736 /* Our advertised capabilities */
3737 usbgem_nd_load(dp, "adv_autoneg_cap", usbgem_param_get,
3738 SETFUNC(dp->mii_status & MII_STATUS_CANAUTONEG),
3739 PARAM_ADV_AUTONEG_CAP);
3740 usbgem_nd_load(dp, "adv_pause_cap", usbgem_param_get,
3741 SETFUNC(dp->ugc.usbgc_flow_control & 1),
3742 PARAM_ADV_PAUSE_CAP);
3743 usbgem_nd_load(dp, "adv_asym_pause_cap", usbgem_param_get,
3744 SETFUNC(dp->ugc.usbgc_flow_control & 2),
3745 PARAM_ADV_ASYM_PAUSE_CAP);
3746 usbgem_nd_load(dp, "adv_1000fdx_cap", usbgem_param_get,
3747 SETFUNC(dp->mii_xstatus &
3748 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD)),
3749 PARAM_ADV_1000FDX_CAP);
3750 usbgem_nd_load(dp, "adv_1000hdx_cap", usbgem_param_get,
3751 SETFUNC(dp->mii_xstatus &
3752 (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET)),
3753 PARAM_ADV_1000HDX_CAP);
3754 usbgem_nd_load(dp, "adv_100T4_cap", usbgem_param_get,
3755 SETFUNC((dp->mii_status & MII_STATUS_100_BASE_T4) &&
3756 !dp->mii_advert_ro),
3757 PARAM_ADV_100T4_CAP);
3758 usbgem_nd_load(dp, "adv_100fdx_cap", usbgem_param_get,
3759 SETFUNC((dp->mii_status & MII_STATUS_100_BASEX_FD) &&
3760 !dp->mii_advert_ro),
3761 PARAM_ADV_100FDX_CAP);
3762 usbgem_nd_load(dp, "adv_100hdx_cap", usbgem_param_get,
3763 SETFUNC((dp->mii_status & MII_STATUS_100_BASEX) &&
3764 !dp->mii_advert_ro),
3765 PARAM_ADV_100HDX_CAP);
3766 usbgem_nd_load(dp, "adv_10fdx_cap", usbgem_param_get,
3767 SETFUNC((dp->mii_status & MII_STATUS_10_FD) &&
3768 !dp->mii_advert_ro),
3769 PARAM_ADV_10FDX_CAP);
3770 usbgem_nd_load(dp, "adv_10hdx_cap", usbgem_param_get,
3771 SETFUNC((dp->mii_status & MII_STATUS_10) &&
3772 !dp->mii_advert_ro),
3773 PARAM_ADV_10HDX_CAP);
3774 usbgem_nd_load(dp, "adv_1000t_ms", usbgem_param_get,
3775 SETFUNC(dp->mii_xstatus &
3776 (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)),
3777 PARAM_ADV_1000T_MS);
3778
3779
3780 /* Partner's advertised capabilities */
3781 usbgem_nd_load(dp, "lp_autoneg_cap",
3782 usbgem_param_get, NULL, PARAM_LP_AUTONEG_CAP);
3783 usbgem_nd_load(dp, "lp_pause_cap",
3784 usbgem_param_get, NULL, PARAM_LP_PAUSE_CAP);
3785 usbgem_nd_load(dp, "lp_asym_pause_cap",
3786 usbgem_param_get, NULL, PARAM_LP_ASYM_PAUSE_CAP);
3787 usbgem_nd_load(dp, "lp_1000fdx_cap",
3788 usbgem_param_get, NULL, PARAM_LP_1000FDX_CAP);
3789 usbgem_nd_load(dp, "lp_1000hdx_cap",
3790 usbgem_param_get, NULL, PARAM_LP_1000HDX_CAP);
3791 usbgem_nd_load(dp, "lp_100T4_cap",
3792 usbgem_param_get, NULL, PARAM_LP_100T4_CAP);
3793 usbgem_nd_load(dp, "lp_100fdx_cap",
3794 usbgem_param_get, NULL, PARAM_LP_100FDX_CAP);
3795 usbgem_nd_load(dp, "lp_100hdx_cap",
3796 usbgem_param_get, NULL, PARAM_LP_100HDX_CAP);
3797 usbgem_nd_load(dp, "lp_10fdx_cap",
3798 usbgem_param_get, NULL, PARAM_LP_10FDX_CAP);
3799 usbgem_nd_load(dp, "lp_10hdx_cap",
3800 usbgem_param_get, NULL, PARAM_LP_10HDX_CAP);
3801
3802 /* Current operating modes */
3803 usbgem_nd_load(dp, "link_status",
3804 usbgem_param_get, NULL, PARAM_LINK_STATUS);
3805 usbgem_nd_load(dp, "link_speed",
3806 usbgem_param_get, NULL, PARAM_LINK_SPEED);
3807 usbgem_nd_load(dp, "link_duplex",
3808 usbgem_param_get, NULL, PARAM_LINK_DUPLEX);
3809 usbgem_nd_load(dp, "link_autoneg",
3810 usbgem_param_get, NULL, PARAM_LINK_AUTONEG);
3811 usbgem_nd_load(dp, "link_rx_pause",
3812 usbgem_param_get, NULL, PARAM_LINK_RX_PAUSE);
3813 usbgem_nd_load(dp, "link_tx_pause",
3814 usbgem_param_get, NULL, PARAM_LINK_TX_PAUSE);
3815 #ifdef DEBUG_RESUME
3816 usbgem_nd_load(dp, "resume_test",
3817 usbgem_param_get, usbgem_param_set, PARAM_RESUME_TEST);
3818 #endif
3819 #undef SETFUNC
3820 }
3821
3822 static
3823 enum ioc_reply
3824 usbgem_nd_ioctl(struct usbgem_dev *dp,
3825 queue_t *wq, mblk_t *mp, struct iocblk *iocp)
3826 {
3827 boolean_t ok;
3828
3829 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3830
3831 switch (iocp->ioc_cmd) {
3832 case ND_GET:
3833 ok = nd_getset(wq, dp->nd_data_p, mp);
3834 DPRINTF(1, (CE_CONT,
3835 "%s: get %s", dp->name, ok ? "OK" : "FAIL"));
3836 return (ok ? IOC_REPLY : IOC_INVAL);
3837
3838 case ND_SET:
3839 ok = nd_getset(wq, dp->nd_data_p, mp);
3840
3841 DPRINTF(1, (CE_CONT, "%s: set %s err %d",
3842 dp->name, ok ? "OK" : "FAIL", iocp->ioc_error));
3843
3844 if (!ok) {
3845 return (IOC_INVAL);
3846 }
3847
3848 if (iocp->ioc_error) {
3849 return (IOC_REPLY);
3850 }
3851
3852 return (IOC_RESTART_REPLY);
3853 }
3854
3855 cmn_err(CE_WARN, "%s: invalid cmd 0x%x", dp->name, iocp->ioc_cmd);
3856
3857 return (IOC_INVAL);
3858 }
3859
3860 static void
3861 usbgem_nd_cleanup(struct usbgem_dev *dp)
3862 {
3863 ASSERT(dp->nd_data_p != NULL);
3864 ASSERT(dp->nd_arg_p != NULL);
3865
3866 nd_free(&dp->nd_data_p);
3867
3868 kmem_free(dp->nd_arg_p, sizeof (struct usbgem_nd_arg) * PARAM_COUNT);
3869 dp->nd_arg_p = NULL;
3870 }
3871 #endif /* USBGEM_CONFIG_ND */
3872
3873 static void
3874 usbgem_mac_ioctl(struct usbgem_dev *dp, queue_t *wq, mblk_t *mp)
3875 {
3876 struct iocblk *iocp;
3877 enum ioc_reply status;
3878
3879 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3880
3881 /*
3882 * Validate the command before bothering with the mutex ...
3883 */
3884 iocp = (void *)mp->b_rptr;
3885 iocp->ioc_error = 0;
3886
3887 DPRINTF(1, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__,
3888 iocp->ioc_cmd));
3889
3890 #ifdef USBGEM_CONFIG_ND
3891 switch (iocp->ioc_cmd) {
3892 default:
3893 _NOTE(NOTREACHED)
3894 status = IOC_INVAL;
3895 break;
3896
3897 case ND_GET:
3898 case ND_SET:
3899 status = usbgem_nd_ioctl(dp, wq, mp, iocp);
3900 break;
3901 }
3902
3903 /*
3904 * Finally, decide how to reply
3905 */
3906 switch (status) {
3907 default:
3908 case IOC_INVAL:
3909 /*
3910 * Error, reply with a NAK and EINVAL or the specified error
3911 */
3912 miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
3913 EINVAL : iocp->ioc_error);
3914 break;
3915
3916 case IOC_DONE:
3917 /*
3918 * OK, reply already sent
3919 */
3920 break;
3921
3922 case IOC_RESTART_ACK:
3923 case IOC_ACK:
3924 /*
3925 * OK, reply with an ACK
3926 */
3927 miocack(wq, mp, 0, 0);
3928 break;
3929
3930 case IOC_RESTART_REPLY:
3931 case IOC_REPLY:
3932 /*
3933 * OK, send prepared reply as ACK or NAK
3934 */
3935 mp->b_datap->db_type =
3936 iocp->ioc_error == 0 ? M_IOCACK : M_IOCNAK;
3937 qreply(wq, mp);
3938 break;
3939 }
3940 #else
3941 miocnak(wq, mp, 0, EINVAL);
3942 return;
3943 #endif /* USBGEM_CONFIG_GLDv3 */
3944 }
3945
3946 #ifndef SYS_MAC_H
3947 #define XCVR_UNDEFINED 0
3948 #define XCVR_NONE 1
3949 #define XCVR_10 2
3950 #define XCVR_100T4 3
3951 #define XCVR_100X 4
3952 #define XCVR_100T2 5
3953 #define XCVR_1000X 6
3954 #define XCVR_1000T 7
3955 #endif
3956 static int
3957 usbgem_mac_xcvr_inuse(struct usbgem_dev *dp)
3958 {
3959 int val = XCVR_UNDEFINED;
3960
3961 if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
3962 if (dp->mii_status & MII_STATUS_100_BASE_T4) {
3963 val = XCVR_100T4;
3964 } else if (dp->mii_status &
3965 (MII_STATUS_100_BASEX_FD |
3966 MII_STATUS_100_BASEX)) {
3967 val = XCVR_100X;
3968 } else if (dp->mii_status &
3969 (MII_STATUS_100_BASE_T2_FD |
3970 MII_STATUS_100_BASE_T2)) {
3971 val = XCVR_100T2;
3972 } else if (dp->mii_status &
3973 (MII_STATUS_10_FD | MII_STATUS_10)) {
3974 val = XCVR_10;
3975 }
3976 } else if (dp->mii_xstatus &
3977 (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
3978 val = XCVR_1000T;
3979 } else if (dp->mii_xstatus &
3980 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
3981 val = XCVR_1000X;
3982 }
3983
3984 return (val);
3985 }
3986
3987 #ifdef USBGEM_CONFIG_GLDv3
3988 /* ============================================================== */
3989 /*
3990 * GLDv3 interface
3991 */
3992 /* ============================================================== */
3993 static int usbgem_m_getstat(void *, uint_t, uint64_t *);
3994 static int usbgem_m_start(void *);
3995 static void usbgem_m_stop(void *);
3996 static int usbgem_m_setpromisc(void *, boolean_t);
3997 static int usbgem_m_multicst(void *, boolean_t, const uint8_t *);
3998 static int usbgem_m_unicst(void *, const uint8_t *);
3999 static mblk_t *usbgem_m_tx(void *, mblk_t *);
4000 static void usbgem_m_ioctl(void *, queue_t *, mblk_t *);
4001 #ifdef GEM_CONFIG_MAC_PROP
4002 static int usbgem_m_setprop(void *, const char *, mac_prop_id_t,
4003 uint_t, const void *);
4004 #ifdef MAC_VERSION_V1
4005 static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4006 uint_t, void *);
4007 #else
4008 static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4009 uint_t, uint_t, void *, uint_t *);
4010 #endif
4011 #endif
4012
4013 #ifdef _SYS_MAC_PROVIDER_H
4014 #define GEM_M_CALLBACK_FLAGS (MC_IOCTL)
4015 #else
4016 #define GEM_M_CALLBACK_FLAGS (MC_IOCTL)
4017 #endif
4018
4019 static mac_callbacks_t gem_m_callbacks = {
4020 #ifdef USBGEM_CONFIG_MAC_PROP
4021 #ifdef MAC_VERSION_V1
4022 GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
4023 #else
4024 GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP,
4025 #endif
4026 #else
4027 GEM_M_CALLBACK_FLAGS,
4028 #endif
4029 usbgem_m_getstat,
4030 usbgem_m_start,
4031 usbgem_m_stop,
4032 usbgem_m_setpromisc,
4033 usbgem_m_multicst,
4034 usbgem_m_unicst,
4035 usbgem_m_tx,
4036 #ifdef _SYS_MAC_PROVIDER_H
4037 #ifdef MAC_VERSION_V1
4038 NULL,
4039 #endif
4040 #else
4041 NULL, /* m_resources */
4042 #endif
4043 usbgem_m_ioctl,
4044 NULL, /* m_getcapab */
4045 #ifdef USBGEM_CONFIG_MAC_PROP
4046 NULL,
4047 NULL,
4048 usbgem_m_setprop,
4049 usbgem_m_getprop,
4050 #endif
4051 #ifdef MAC_VERSION_V1
4052 usbgem_m_propinfo,
4053 #endif
4054 };
4055
4056 static int
4057 usbgem_m_start(void *arg)
4058 {
4059 int ret;
4060 int err;
4061 struct usbgem_dev *dp = arg;
4062
4063 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4064
4065 err = EIO;
4066
4067 rw_enter(&dp->dev_state_lock, RW_WRITER);
4068 dp->nic_state = NIC_STATE_ONLINE;
4069
4070 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4071 err = 0;
4072 goto x;
4073 }
4074 if (usbgem_mac_init(dp) != USB_SUCCESS) {
4075 goto x;
4076 }
4077
4078 /* initialize rx filter state */
4079 sema_p(&dp->rxfilter_lock);
4080 dp->mc_count = 0;
4081 dp->mc_count_req = 0;
4082
4083 bcopy(dp->dev_addr.ether_addr_octet,
4084 dp->cur_addr.ether_addr_octet, ETHERADDRL);
4085 dp->rxmode |= RXMODE_ENABLE;
4086
4087 ret = usbgem_hal_set_rx_filter(dp);
4088 sema_v(&dp->rxfilter_lock);
4089
4090 if (ret != USB_SUCCESS) {
4091 goto x;
4092 }
4093
4094 if (dp->mii_state == MII_STATE_LINKUP) {
4095 /* setup media mode if the link have been up */
4096 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
4097 goto x;
4098 }
4099 if (usbgem_mac_start(dp) != USB_SUCCESS) {
4100 goto x;
4101 }
4102 }
4103
4104 err = 0;
4105 x:
4106 rw_exit(&dp->dev_state_lock);
4107 return (err);
4108 }
4109
4110 static void
4111 usbgem_m_stop(void *arg)
4112 {
4113 struct usbgem_dev *dp = arg;
4114
4115 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4116
4117 /* stop rx gracefully */
4118 rw_enter(&dp->dev_state_lock, RW_READER);
4119 sema_p(&dp->rxfilter_lock);
4120 dp->rxmode &= ~RXMODE_ENABLE;
4121
4122 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4123 (void) usbgem_hal_set_rx_filter(dp);
4124 }
4125 sema_v(&dp->rxfilter_lock);
4126 rw_exit(&dp->dev_state_lock);
4127
4128 /* make the nic state inactive */
4129 rw_enter(&dp->dev_state_lock, RW_WRITER);
4130 dp->nic_state = NIC_STATE_STOPPED;
4131
4132 /* stop mac completely */
4133 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4134 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
4135 }
4136 rw_exit(&dp->dev_state_lock);
4137 }
4138
4139 static int
4140 usbgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
4141 {
4142 int err;
4143 int ret;
4144 struct usbgem_dev *dp = arg;
4145
4146 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4147
4148 rw_enter(&dp->dev_state_lock, RW_READER);
4149 if (add) {
4150 ret = usbgem_add_multicast(dp, ep);
4151 } else {
4152 ret = usbgem_remove_multicast(dp, ep);
4153 }
4154 rw_exit(&dp->dev_state_lock);
4155
4156 err = 0;
4157 if (ret != USB_SUCCESS) {
4158 #ifdef GEM_CONFIG_FMA
4159 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4160 #endif
4161 err = EIO;
4162 }
4163
4164 return (err);
4165 }
4166
4167 static int
4168 usbgem_m_setpromisc(void *arg, boolean_t on)
4169 {
4170 int err;
4171 struct usbgem_dev *dp = arg;
4172
4173 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4174
4175 rw_enter(&dp->dev_state_lock, RW_READER);
4176
4177 sema_p(&dp->rxfilter_lock);
4178 if (on) {
4179 dp->rxmode |= RXMODE_PROMISC;
4180 } else {
4181 dp->rxmode &= ~RXMODE_PROMISC;
4182 }
4183
4184 err = 0;
4185 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4186 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4187 err = EIO;
4188 }
4189 }
4190 sema_v(&dp->rxfilter_lock);
4191
4192 rw_exit(&dp->dev_state_lock);
4193
4194 #ifdef GEM_CONFIG_FMA
4195 if (err != 0) {
4196 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4197 }
4198 #endif
4199 return (err);
4200 }
4201
4202 int
4203 usbgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
4204 {
4205 uint64_t val;
4206 struct usbgem_dev *dp = arg;
4207 struct usbgem_stats *gstp = &dp->stats;
4208
4209 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4210
4211 rw_enter(&dp->dev_state_lock, RW_READER);
4212 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4213 rw_exit(&dp->dev_state_lock);
4214 return (0);
4215 }
4216
4217 /* LINTED */
4218 if (usbgem_hal_get_stats(dp) != USB_SUCCESS) {
4219 #ifdef GEM_CONFIG_FMA
4220 rw_exit(&dp->dev_state_lock);
4221 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4222 return (EIO);
4223 #endif
4224 }
4225 rw_exit(&dp->dev_state_lock);
4226
4227 switch (stat) {
4228 case MAC_STAT_IFSPEED:
4229 val = usbgem_speed_value[dp->speed] *1000000ull;
4230 break;
4231
4232 case MAC_STAT_MULTIRCV:
4233 val = gstp->rmcast;
4234 break;
4235
4236 case MAC_STAT_BRDCSTRCV:
4237 val = gstp->rbcast;
4238 break;
4239
4240 case MAC_STAT_MULTIXMT:
4241 val = gstp->omcast;
4242 break;
4243
4244 case MAC_STAT_BRDCSTXMT:
4245 val = gstp->obcast;
4246 break;
4247
4248 case MAC_STAT_NORCVBUF:
4249 val = gstp->norcvbuf + gstp->missed;
4250 break;
4251
4252 case MAC_STAT_IERRORS:
4253 val = gstp->errrcv;
4254 break;
4255
4256 case MAC_STAT_NOXMTBUF:
4257 val = gstp->noxmtbuf;
4258 break;
4259
4260 case MAC_STAT_OERRORS:
4261 val = gstp->errxmt;
4262 break;
4263
4264 case MAC_STAT_COLLISIONS:
4265 val = gstp->collisions;
4266 break;
4267
4268 case MAC_STAT_RBYTES:
4269 val = gstp->rbytes;
4270 break;
4271
4272 case MAC_STAT_IPACKETS:
4273 val = gstp->rpackets;
4274 break;
4275
4276 case MAC_STAT_OBYTES:
4277 val = gstp->obytes;
4278 break;
4279
4280 case MAC_STAT_OPACKETS:
4281 val = gstp->opackets;
4282 break;
4283
4284 case MAC_STAT_UNDERFLOWS:
4285 val = gstp->underflow;
4286 break;
4287
4288 case MAC_STAT_OVERFLOWS:
4289 val = gstp->overflow;
4290 break;
4291
4292 case ETHER_STAT_ALIGN_ERRORS:
4293 val = gstp->frame;
4294 break;
4295
4296 case ETHER_STAT_FCS_ERRORS:
4297 val = gstp->crc;
4298 break;
4299
4300 case ETHER_STAT_FIRST_COLLISIONS:
4301 val = gstp->first_coll;
4302 break;
4303
4304 case ETHER_STAT_MULTI_COLLISIONS:
4305 val = gstp->multi_coll;
4306 break;
4307
4308 case ETHER_STAT_SQE_ERRORS:
4309 val = gstp->sqe;
4310 break;
4311
4312 case ETHER_STAT_DEFER_XMTS:
4313 val = gstp->defer;
4314 break;
4315
4316 case ETHER_STAT_TX_LATE_COLLISIONS:
4317 val = gstp->xmtlatecoll;
4318 break;
4319
4320 case ETHER_STAT_EX_COLLISIONS:
4321 val = gstp->excoll;
4322 break;
4323
4324 case ETHER_STAT_MACXMT_ERRORS:
4325 val = gstp->xmit_internal_err;
4326 break;
4327
4328 case ETHER_STAT_CARRIER_ERRORS:
4329 val = gstp->nocarrier;
4330 break;
4331
4332 case ETHER_STAT_TOOLONG_ERRORS:
4333 val = gstp->frame_too_long;
4334 break;
4335
4336 case ETHER_STAT_MACRCV_ERRORS:
4337 val = gstp->rcv_internal_err;
4338 break;
4339
4340 case ETHER_STAT_XCVR_ADDR:
4341 val = dp->mii_phy_addr;
4342 break;
4343
4344 case ETHER_STAT_XCVR_ID:
4345 val = dp->mii_phy_id;
4346 break;
4347
4348 case ETHER_STAT_XCVR_INUSE:
4349 val = usbgem_mac_xcvr_inuse(dp);
4350 break;
4351
4352 case ETHER_STAT_CAP_1000FDX:
4353 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
4354 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
4355 break;
4356
4357 case ETHER_STAT_CAP_1000HDX:
4358 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
4359 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
4360 break;
4361
4362 case ETHER_STAT_CAP_100FDX:
4363 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
4364 break;
4365
4366 case ETHER_STAT_CAP_100HDX:
4367 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
4368 break;
4369
4370 case ETHER_STAT_CAP_10FDX:
4371 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
4372 break;
4373
4374 case ETHER_STAT_CAP_10HDX:
4375 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
4376 break;
4377
4378 case ETHER_STAT_CAP_ASMPAUSE:
4379 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
4380 break;
4381
4382 case ETHER_STAT_CAP_PAUSE:
4383 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
4384 break;
4385
4386 case ETHER_STAT_CAP_AUTONEG:
4387 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
4388 break;
4389
4390 case ETHER_STAT_ADV_CAP_1000FDX:
4391 val = dp->anadv_1000fdx;
4392 break;
4393
4394 case ETHER_STAT_ADV_CAP_1000HDX:
4395 val = dp->anadv_1000hdx;
4396 break;
4397
4398 case ETHER_STAT_ADV_CAP_100FDX:
4399 val = dp->anadv_100fdx;
4400 break;
4401
4402 case ETHER_STAT_ADV_CAP_100HDX:
4403 val = dp->anadv_100hdx;
4404 break;
4405
4406 case ETHER_STAT_ADV_CAP_10FDX:
4407 val = dp->anadv_10fdx;
4408 break;
4409
4410 case ETHER_STAT_ADV_CAP_10HDX:
4411 val = dp->anadv_10hdx;
4412 break;
4413
4414 case ETHER_STAT_ADV_CAP_ASMPAUSE:
4415 val = dp->anadv_asmpause;
4416 break;
4417
4418 case ETHER_STAT_ADV_CAP_PAUSE:
4419 val = dp->anadv_pause;
4420 break;
4421
4422 case ETHER_STAT_ADV_CAP_AUTONEG:
4423 val = dp->anadv_autoneg;
4424 break;
4425
4426 case ETHER_STAT_LP_CAP_1000FDX:
4427 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
4428 break;
4429
4430 case ETHER_STAT_LP_CAP_1000HDX:
4431 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
4432 break;
4433
4434 case ETHER_STAT_LP_CAP_100FDX:
4435 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
4436 break;
4437
4438 case ETHER_STAT_LP_CAP_100HDX:
4439 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
4440 break;
4441
4442 case ETHER_STAT_LP_CAP_10FDX:
4443 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
4444 break;
4445
4446 case ETHER_STAT_LP_CAP_10HDX:
4447 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
4448 break;
4449
4450 case ETHER_STAT_LP_CAP_ASMPAUSE:
4451 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
4452 break;
4453
4454 case ETHER_STAT_LP_CAP_PAUSE:
4455 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
4456 break;
4457
4458 case ETHER_STAT_LP_CAP_AUTONEG:
4459 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4460 break;
4461
4462 case ETHER_STAT_LINK_ASMPAUSE:
4463 val = BOOLEAN(dp->flow_control & 2);
4464 break;
4465
4466 case ETHER_STAT_LINK_PAUSE:
4467 val = BOOLEAN(dp->flow_control & 1);
4468 break;
4469
4470 case ETHER_STAT_LINK_AUTONEG:
4471 val = dp->anadv_autoneg &&
4472 BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4473 break;
4474
4475 case ETHER_STAT_LINK_DUPLEX:
4476 val = (dp->mii_state == MII_STATE_LINKUP) ?
4477 (dp->full_duplex ? 2 : 1) : 0;
4478 break;
4479
4480 case ETHER_STAT_TOOSHORT_ERRORS:
4481 val = gstp->runt;
4482 break;
4483 #ifdef NEVER /* it doesn't make sense */
4484 case ETHER_STAT_CAP_REMFAULT:
4485 val = B_TRUE;
4486 break;
4487
4488 case ETHER_STAT_ADV_REMFAULT:
4489 val = dp->anadv_remfault;
4490 break;
4491 #endif
4492 case ETHER_STAT_LP_REMFAULT:
4493 val = BOOLEAN(dp->mii_lpable & MII_AN_ADVERT_REMFAULT);
4494 break;
4495
4496 case ETHER_STAT_JABBER_ERRORS:
4497 val = gstp->jabber;
4498 break;
4499
4500 case ETHER_STAT_CAP_100T4:
4501 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
4502 break;
4503
4504 case ETHER_STAT_ADV_CAP_100T4:
4505 val = dp->anadv_100t4;
4506 break;
4507
4508 case ETHER_STAT_LP_CAP_100T4:
4509 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
4510 break;
4511
4512 default:
4513 #if GEM_DEBUG_LEVEL > 2
4514 cmn_err(CE_WARN,
4515 "%s: unrecognized parameter value = %d",
4516 __func__, stat);
4517 #endif
4518 *valp = 0;
4519 return (ENOTSUP);
4520 }
4521
4522 *valp = val;
4523
4524 return (0);
4525 }
4526
4527 static int
4528 usbgem_m_unicst(void *arg, const uint8_t *mac)
4529 {
4530 int err;
4531 struct usbgem_dev *dp = arg;
4532
4533 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4534
4535 rw_enter(&dp->dev_state_lock, RW_READER);
4536
4537 sema_p(&dp->rxfilter_lock);
4538 bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4539 dp->rxmode |= RXMODE_ENABLE;
4540
4541 err = 0;
4542 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4543 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4544 err = EIO;
4545 }
4546 }
4547 sema_v(&dp->rxfilter_lock);
4548 rw_exit(&dp->dev_state_lock);
4549
4550 #ifdef GEM_CONFIG_FMA
4551 if (err != 0) {
4552 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4553 }
4554 #endif
4555 return (err);
4556 }
4557
4558 /*
4559 * usbgem_m_tx is used only for sending data packets into ethernet wire.
4560 */
4561 static mblk_t *
4562 usbgem_m_tx(void *arg, mblk_t *mp_head)
4563 {
4564 int limit;
4565 mblk_t *mp;
4566 mblk_t *nmp;
4567 struct usbgem_dev *dp = arg;
4568
4569 DPRINTF(4, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4570
4571 mp = mp_head;
4572
4573 rw_enter(&dp->dev_state_lock, RW_READER);
4574
4575 if (dp->mii_state != MII_STATE_LINKUP ||
4576 dp->mac_state != MAC_STATE_ONLINE) {
4577 /* some nics hate to send packets during the link is down */
4578 for (; mp; mp = nmp) {
4579 nmp = mp->b_next;
4580 mp->b_next = NULL;
4581 freemsg(mp);
4582 }
4583 goto x;
4584 }
4585
4586 ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4587
4588 limit = dp->tx_max_packets;
4589 for (; limit-- && mp; mp = nmp) {
4590 nmp = mp->b_next;
4591 mp->b_next = NULL;
4592 if (usbgem_send_common(dp, mp,
4593 (limit == 0 && nmp) ? 1 : 0)) {
4594 mp->b_next = nmp;
4595 break;
4596 }
4597 }
4598 #ifdef CONFIG_TX_LIMITER
4599 if (mp == mp_head) {
4600 /* no packets were sent, descrease allocation limit */
4601 mutex_enter(&dp->txlock);
4602 dp->tx_max_packets = max(dp->tx_max_packets - 1, 1);
4603 mutex_exit(&dp->txlock);
4604 }
4605 #endif
4606 x:
4607 rw_exit(&dp->dev_state_lock);
4608
4609 return (mp);
4610 }
4611
4612 static void
4613 usbgem_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4614 {
4615 struct usbgem_dev *dp = arg;
4616
4617 DPRINTF(1, (CE_CONT, "!%s: %s: called",
4618 ((struct usbgem_dev *)arg)->name, __func__));
4619
4620 rw_enter(&dp->dev_state_lock, RW_READER);
4621 usbgem_mac_ioctl((struct usbgem_dev *)arg, wq, mp);
4622 rw_exit(&dp->dev_state_lock);
4623 }
4624
4625 static void
4626 usbgem_gld3_init(struct usbgem_dev *dp, mac_register_t *macp)
4627 {
4628 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4629 macp->m_driver = dp;
4630 macp->m_dip = dp->dip;
4631 macp->m_src_addr = dp->dev_addr.ether_addr_octet;
4632 macp->m_callbacks = &gem_m_callbacks;
4633 macp->m_min_sdu = 0;
4634 macp->m_max_sdu = dp->mtu;
4635
4636 if (dp->misc_flag & USBGEM_VLAN) {
4637 macp->m_margin = VTAG_SIZE;
4638 }
4639 }
4640 #else
4641 /* ============================================================== */
4642 /*
4643 * GLDv2 interface
4644 */
4645 /* ============================================================== */
4646 static int usbgem_gld_reset(gld_mac_info_t *);
4647 static int usbgem_gld_start(gld_mac_info_t *);
4648 static int usbgem_gld_stop(gld_mac_info_t *);
4649 static int usbgem_gld_set_mac_address(gld_mac_info_t *, uint8_t *);
4650 static int usbgem_gld_set_multicast(gld_mac_info_t *, uint8_t *, int);
4651 static int usbgem_gld_set_promiscuous(gld_mac_info_t *, int);
4652 static int usbgem_gld_get_stats(gld_mac_info_t *, struct gld_stats *);
4653 static int usbgem_gld_send(gld_mac_info_t *, mblk_t *);
4654 static int usbgem_gld_send_tagged(gld_mac_info_t *, mblk_t *, uint32_t);
4655
4656 static int
4657 usbgem_gld_reset(gld_mac_info_t *macinfo)
4658 {
4659 int err;
4660 struct usbgem_dev *dp;
4661
4662 err = GLD_SUCCESS;
4663 dp = (struct usbgem_dev *)macinfo->gldm_private;
4664
4665 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4666
4667 rw_enter(&dp->dev_state_lock, RW_WRITER);
4668 if (usbgem_mac_init(dp) != USB_SUCCESS) {
4669 err = GLD_FAILURE;
4670 goto x;
4671 }
4672
4673 dp->nic_state = NIC_STATE_INITIALIZED;
4674
4675 /* setup media mode if the link have been up */
4676 if (dp->mii_state == MII_STATE_LINKUP) {
4677 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4678 (void) usbgem_hal_set_media(dp);
4679 }
4680 }
4681 x:
4682 rw_exit(&dp->dev_state_lock);
4683 return (err);
4684 }
4685
4686 static int
4687 usbgem_gld_start(gld_mac_info_t *macinfo)
4688 {
4689 int err;
4690 struct usbgem_dev *dp;
4691
4692 dp = (struct usbgem_dev *)macinfo->gldm_private;
4693
4694 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4695
4696 rw_enter(&dp->dev_state_lock, RW_WRITER);
4697
4698 dp->nic_state = NIC_STATE_ONLINE;
4699
4700 if (dp->mii_state == MII_STATE_LINKUP) {
4701 if (usbgem_mac_start(dp) != USB_SUCCESS) {
4702 /* sema_v(&dp->mii_lock); */
4703 err = GLD_FAILURE;
4704 goto x;
4705 }
4706 }
4707
4708 /*
4709 * XXX - don't call gld_linkstate() here,
4710 * otherwise it cause recursive mutex call.
4711 */
4712 err = GLD_SUCCESS;
4713 x:
4714 rw_exit(&dp->dev_state_lock);
4715
4716 return (err);
4717 }
4718
4719 static int
4720 usbgem_gld_stop(gld_mac_info_t *macinfo)
4721 {
4722 int err = GLD_SUCCESS;
4723 struct usbgem_dev *dp;
4724
4725 dp = (struct usbgem_dev *)macinfo->gldm_private;
4726
4727 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4728
4729 /* try to stop rx gracefully */
4730 rw_enter(&dp->dev_state_lock, RW_READER);
4731 sema_p(&dp->rxfilter_lock);
4732 dp->rxmode &= ~RXMODE_ENABLE;
4733
4734 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4735 (void) usbgem_hal_set_rx_filter(dp);
4736 }
4737 sema_v(&dp->rxfilter_lock);
4738 rw_exit(&dp->dev_state_lock);
4739
4740 /* make the nic state inactive */
4741 rw_enter(&dp->dev_state_lock, RW_WRITER);
4742 dp->nic_state = NIC_STATE_STOPPED;
4743
4744 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4745 if (usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL)
4746 != USB_SUCCESS) {
4747 err = GLD_FAILURE;
4748 }
4749 }
4750 rw_exit(&dp->dev_state_lock);
4751
4752 return (err);
4753 }
4754
4755 static int
4756 usbgem_gld_set_multicast(gld_mac_info_t *macinfo, uint8_t *ep, int flag)
4757 {
4758 int err;
4759 int ret;
4760 struct usbgem_dev *dp;
4761
4762 dp = (struct usbgem_dev *)macinfo->gldm_private;
4763
4764 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4765
4766 rw_enter(&dp->dev_state_lock, RW_READER);
4767 if (flag == GLD_MULTI_ENABLE) {
4768 ret = usbgem_add_multicast(dp, ep);
4769 } else {
4770 ret = usbgem_remove_multicast(dp, ep);
4771 }
4772 rw_exit(&dp->dev_state_lock);
4773
4774 err = GLD_SUCCESS;
4775 if (ret != USB_SUCCESS) {
4776 #ifdef GEM_CONFIG_FMA
4777 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4778 #endif
4779 err = GLD_FAILURE;
4780 }
4781 return (err);
4782 }
4783
4784 static int
4785 usbgem_gld_set_promiscuous(gld_mac_info_t *macinfo, int flag)
4786 {
4787 boolean_t need_to_change = B_TRUE;
4788 struct usbgem_dev *dp;
4789
4790 dp = (struct usbgem_dev *)macinfo->gldm_private;
4791
4792 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4793
4794 sema_p(&dp->rxfilter_lock);
4795 if (flag == GLD_MAC_PROMISC_NONE) {
4796 dp->rxmode &= ~(RXMODE_PROMISC | RXMODE_ALLMULTI_REQ);
4797 } else if (flag == GLD_MAC_PROMISC_MULTI) {
4798 dp->rxmode |= RXMODE_ALLMULTI_REQ;
4799 } else if (flag == GLD_MAC_PROMISC_PHYS) {
4800 dp->rxmode |= RXMODE_PROMISC;
4801 } else {
4802 /* mode unchanged */
4803 need_to_change = B_FALSE;
4804 }
4805
4806 if (need_to_change) {
4807 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4808 (void) usbgem_hal_set_rx_filter(dp);
4809 }
4810 }
4811 sema_v(&dp->rxfilter_lock);
4812
4813 return (GLD_SUCCESS);
4814 }
4815
4816 static int
4817 usbgem_gld_set_mac_address(gld_mac_info_t *macinfo, uint8_t *mac)
4818 {
4819 struct usbgem_dev *dp;
4820 dp = (struct usbgem_dev *)macinfo->gldm_private;
4821
4822 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4823
4824 sema_p(&dp->rxfilter_lock);
4825 bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4826 dp->rxmode |= RXMODE_ENABLE;
4827
4828 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4829 (void) usbgem_hal_set_rx_filter(dp);
4830 }
4831 sema_v(&dp->rxfilter_lock);
4832
4833 return (GLD_SUCCESS);
4834 }
4835
4836 static int
4837 usbgem_gld_get_stats(gld_mac_info_t *macinfo, struct gld_stats *gs)
4838 {
4839 struct usbgem_dev *dp;
4840 struct usbgem_stats *vs;
4841
4842 dp = (struct usbgem_dev *)macinfo->gldm_private;
4843
4844 if ((*dp->ugc.usbgc_get_stats)(dp) != USB_SUCCESS) {
4845 #ifdef GEM_CONFIG_FMA
4846 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4847 #endif
4848 return (USB_FAILURE);
4849 }
4850
4851 vs = &dp->stats;
4852
4853 gs->glds_errxmt = vs->errxmt;
4854 gs->glds_errrcv = vs->errrcv;
4855 gs->glds_collisions = vs->collisions;
4856
4857 gs->glds_excoll = vs->excoll;
4858 gs->glds_defer = vs->defer;
4859 gs->glds_frame = vs->frame;
4860 gs->glds_crc = vs->crc;
4861
4862 gs->glds_overflow = vs->overflow; /* fifo err,underrun,rbufovf */
4863 gs->glds_underflow = vs->underflow;
4864 gs->glds_short = vs->runt;
4865 gs->glds_missed = vs->missed; /* missed pkts while rbuf ovf */
4866 gs->glds_xmtlatecoll = vs->xmtlatecoll;
4867 gs->glds_nocarrier = vs->nocarrier;
4868 gs->glds_norcvbuf = vs->norcvbuf; /* OS resource exaust */
4869 gs->glds_intr = vs->intr;
4870
4871 /* all before here must be kept in place for v0 compatibility */
4872 gs->glds_speed = usbgem_speed_value[dp->speed] * 1000000;
4873 gs->glds_media = GLDM_PHYMII;
4874 gs->glds_duplex = dp->full_duplex ? GLD_DUPLEX_FULL : GLD_DUPLEX_HALF;
4875
4876 /* gs->glds_media_specific */
4877 gs->glds_dot3_first_coll = vs->first_coll;
4878 gs->glds_dot3_multi_coll = vs->multi_coll;
4879 gs->glds_dot3_sqe_error = 0;
4880 gs->glds_dot3_mac_xmt_error = 0;
4881 gs->glds_dot3_mac_rcv_error = 0;
4882 gs->glds_dot3_frame_too_long = vs->frame_too_long;
4883
4884 return (GLD_SUCCESS);
4885 }
4886
4887 static int
4888 usbgem_gld_ioctl(gld_mac_info_t *macinfo, queue_t *wq, mblk_t *mp)
4889 {
4890 struct usbgem_dev *dp;
4891
4892 dp = (struct usbgem_dev *)macinfo->gldm_private;
4893 usbgem_mac_ioctl(dp, wq, mp);
4894
4895 return (GLD_SUCCESS);
4896 }
4897
4898 /*
4899 * gem_gld_send is used only for sending data packets into ethernet wire.
4900 */
4901 static int
4902 usbgem_gld_send(gld_mac_info_t *macinfo, mblk_t *mp)
4903 {
4904 int ret;
4905 uint32_t flags = 0;
4906 struct usbgem_dev *dp;
4907
4908 dp = (struct usbgem_dev *)macinfo->gldm_private;
4909
4910 /* nic state must be online of suspended */
4911 rw_enter(&dp->dev_state_lock, RW_READER);
4912
4913 ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4914 ASSERT(mp->b_next == NULL);
4915
4916 if (dp->mii_state != MII_STATE_LINKUP) {
4917 /* Some nics hate to send packets while the link is down. */
4918 /* we discard the untransmitted packets silently */
4919 rw_exit(&dp->dev_state_lock);
4920
4921 freemsg(mp);
4922 #ifdef GEM_CONFIG_FMA
4923 /* FIXME - should we ignore the error? */
4924 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4925 #endif
4926 return (GLD_SUCCESS);
4927 }
4928
4929 ret = (usbgem_send_common(dp, mp, flags) == NULL)
4930 ? GLD_SUCCESS : GLD_NORESOURCES;
4931 rw_exit(&dp->dev_state_lock);
4932
4933 return (ret);
4934 }
4935
4936 /*
4937 * usbgem_gld_send is used only for sending data packets into ethernet wire.
4938 */
4939 static int
4940 usbgem_gld_send_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
4941 {
4942 uint32_t flags;
4943 struct usbgem_dev *dp;
4944
4945 dp = (struct usbgem_dev *)macinfo->gldm_private;
4946
4947 /*
4948 * Some nics hate to send packets while the link is down.
4949 */
4950 if (dp->mii_state != MII_STATE_LINKUP) {
4951 /* we dicard the untransmitted packets silently */
4952 freemsg(mp);
4953 #ifdef GEM_CONFIG_FMA
4954 /* FIXME - should we ignore the error? */
4955 ddi_fm_service_impact(dp->dip, DDI_SERVICE_UNAFFECTED);
4956 #endif
4957 return (GLD_SUCCESS);
4958 }
4959 #ifdef notyet
4960 flags = GLD_VTAG_TCI(vtag) << GEM_SEND_VTAG_SHIFT;
4961 #endif
4962 return ((usbgem_send_common(dp, mp, 0) == NULL) ?
4963 GLD_SUCCESS : GLD_NORESOURCES);
4964 }
4965
4966 static void
4967 usbgem_gld_init(struct usbgem_dev *dp, gld_mac_info_t *macinfo, char *ident)
4968 {
4969 /*
4970 * configure GLD
4971 */
4972 macinfo->gldm_devinfo = dp->dip;
4973 macinfo->gldm_private = (caddr_t)dp;
4974
4975 macinfo->gldm_reset = usbgem_gld_reset;
4976 macinfo->gldm_start = usbgem_gld_start;
4977 macinfo->gldm_stop = usbgem_gld_stop;
4978 macinfo->gldm_set_mac_addr = usbgem_gld_set_mac_address;
4979 macinfo->gldm_send = usbgem_gld_send;
4980 macinfo->gldm_set_promiscuous = usbgem_gld_set_promiscuous;
4981 macinfo->gldm_get_stats = usbgem_gld_get_stats;
4982 macinfo->gldm_ioctl = usbgem_gld_ioctl;
4983 macinfo->gldm_set_multicast = usbgem_gld_set_multicast;
4984 macinfo->gldm_intr = NULL;
4985 macinfo->gldm_mctl = NULL;
4986
4987 macinfo->gldm_ident = ident;
4988 macinfo->gldm_type = DL_ETHER;
4989 macinfo->gldm_minpkt = 0;
4990 macinfo->gldm_maxpkt = dp->mtu;
4991 macinfo->gldm_addrlen = ETHERADDRL;
4992 macinfo->gldm_saplen = -2;
4993 macinfo->gldm_ppa = ddi_get_instance(dp->dip);
4994 #ifdef GLD_CAP_LINKSTATE
4995 macinfo->gldm_capabilities = GLD_CAP_LINKSTATE;
4996 #endif
4997 macinfo->gldm_vendor_addr = dp->dev_addr.ether_addr_octet;
4998 macinfo->gldm_broadcast_addr = usbgem_bcastaddr;
4999 }
5000 #endif /* USBGEM_CONFIG_GLDv3 */
5001
5002
5003 /* ======================================================================== */
5004 /*
5005 * .conf interface
5006 */
5007 /* ======================================================================== */
5008 void
5009 usbgem_generate_macaddr(struct usbgem_dev *dp, uint8_t *mac)
5010 {
5011 extern char hw_serial[];
5012 char *hw_serial_p;
5013 int i;
5014 uint64_t val;
5015 uint64_t key;
5016
5017 cmn_err(CE_NOTE,
5018 "!%s: using temp ether address,"
5019 " do not use this for long time",
5020 dp->name);
5021
5022 /* prefer a fixed address for DHCP */
5023 hw_serial_p = &hw_serial[0];
5024 val = stoi(&hw_serial_p);
5025
5026 key = 0;
5027 for (i = 0; i < USBGEM_NAME_LEN; i++) {
5028 if (dp->name[i] == 0) {
5029 break;
5030 }
5031 key ^= dp->name[i];
5032 }
5033 key ^= ddi_get_instance(dp->dip);
5034 val ^= key << 32;
5035
5036 /* generate a local address */
5037 mac[0] = 0x02;
5038 mac[1] = (uint8_t)(val >> 32);
5039 mac[2] = (uint8_t)(val >> 24);
5040 mac[3] = (uint8_t)(val >> 16);
5041 mac[4] = (uint8_t)(val >> 8);
5042 mac[5] = (uint8_t)val;
5043 }
5044
5045 boolean_t
5046 usbgem_get_mac_addr_conf(struct usbgem_dev *dp)
5047 {
5048 char propname[32];
5049 char *valstr;
5050 uint8_t mac[ETHERADDRL];
5051 char *cp;
5052 int c;
5053 int i;
5054 int j;
5055 uint8_t v;
5056 uint8_t d;
5057 uint8_t ored;
5058
5059 DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5060 /*
5061 * Get ethernet address from .conf file
5062 */
5063 (void) sprintf(propname, "mac-addr");
5064 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dp->dip,
5065 DDI_PROP_DONTPASS, propname, &valstr)) != DDI_PROP_SUCCESS) {
5066 return (B_FALSE);
5067 }
5068
5069 if (strlen(valstr) != ETHERADDRL*3-1) {
5070 goto syntax_err;
5071 }
5072
5073 cp = valstr;
5074 j = 0;
5075 ored = 0;
5076 for (;;) {
5077 v = 0;
5078 for (i = 0; i < 2; i++) {
5079 c = *cp++;
5080
5081 if (c >= 'a' && c <= 'f') {
5082 d = c - 'a' + 10;
5083 } else if (c >= 'A' && c <= 'F') {
5084 d = c - 'A' + 10;
5085 } else if (c >= '0' && c <= '9') {
5086 d = c - '0';
5087 } else {
5088 goto syntax_err;
5089 }
5090 v = (v << 4) | d;
5091 }
5092
5093 mac[j++] = v;
5094 ored |= v;
5095 if (j == ETHERADDRL) {
5096 /* done */
5097 break;
5098 }
5099
5100 c = *cp++;
5101 if (c != ':') {
5102 goto syntax_err;
5103 }
5104 }
5105
5106 if (ored == 0) {
5107 usbgem_generate_macaddr(dp, mac);
5108 }
5109 for (i = 0; i < ETHERADDRL; i++) {
5110 dp->dev_addr.ether_addr_octet[i] = mac[i];
5111 }
5112 ddi_prop_free(valstr);
5113 return (B_TRUE);
5114
5115 syntax_err:
5116 cmn_err(CE_CONT,
5117 "!%s: read mac addr: trying .conf: syntax err %s",
5118 dp->name, valstr);
5119 ddi_prop_free(valstr);
5120
5121 return (B_FALSE);
5122 }
5123
5124 static void
5125 usbgem_read_conf(struct usbgem_dev *dp)
5126 {
5127 int val;
5128
5129 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5130
5131 /*
5132 * Get media mode infomation from .conf file
5133 */
5134 dp->anadv_autoneg = usbgem_prop_get_int(dp, "adv_autoneg_cap", 1) != 0;
5135 dp->anadv_1000fdx = usbgem_prop_get_int(dp, "adv_1000fdx_cap", 1) != 0;
5136 dp->anadv_1000hdx = usbgem_prop_get_int(dp, "adv_1000hdx_cap", 1) != 0;
5137 dp->anadv_100t4 = usbgem_prop_get_int(dp, "adv_100T4_cap", 1) != 0;
5138 dp->anadv_100fdx = usbgem_prop_get_int(dp, "adv_100fdx_cap", 1) != 0;
5139 dp->anadv_100hdx = usbgem_prop_get_int(dp, "adv_100hdx_cap", 1) != 0;
5140 dp->anadv_10fdx = usbgem_prop_get_int(dp, "adv_10fdx_cap", 1) != 0;
5141 dp->anadv_10hdx = usbgem_prop_get_int(dp, "adv_10hdx_cap", 1) != 0;
5142 dp->anadv_1000t_ms = usbgem_prop_get_int(dp, "adv_1000t_ms", 0);
5143
5144 if ((ddi_prop_exists(DDI_DEV_T_ANY, dp->dip,
5145 DDI_PROP_DONTPASS, "full-duplex"))) {
5146 dp->full_duplex =
5147 usbgem_prop_get_int(dp, "full-duplex", 1) != 0;
5148 dp->anadv_autoneg = B_FALSE;
5149 if (dp->full_duplex) {
5150 dp->anadv_1000hdx = B_FALSE;
5151 dp->anadv_100hdx = B_FALSE;
5152 dp->anadv_10hdx = B_FALSE;
5153 } else {
5154 dp->anadv_1000fdx = B_FALSE;
5155 dp->anadv_100fdx = B_FALSE;
5156 dp->anadv_10fdx = B_FALSE;
5157 }
5158 }
5159
5160 if ((val = usbgem_prop_get_int(dp, "speed", 0)) > 0) {
5161 dp->anadv_autoneg = B_FALSE;
5162 switch (val) {
5163 case 1000:
5164 dp->speed = USBGEM_SPD_1000;
5165 dp->anadv_100t4 = B_FALSE;
5166 dp->anadv_100fdx = B_FALSE;
5167 dp->anadv_100hdx = B_FALSE;
5168 dp->anadv_10fdx = B_FALSE;
5169 dp->anadv_10hdx = B_FALSE;
5170 break;
5171 case 100:
5172 dp->speed = USBGEM_SPD_100;
5173 dp->anadv_1000fdx = B_FALSE;
5174 dp->anadv_1000hdx = B_FALSE;
5175 dp->anadv_10fdx = B_FALSE;
5176 dp->anadv_10hdx = B_FALSE;
5177 break;
5178 case 10:
5179 dp->speed = USBGEM_SPD_10;
5180 dp->anadv_1000fdx = B_FALSE;
5181 dp->anadv_1000hdx = B_FALSE;
5182 dp->anadv_100t4 = B_FALSE;
5183 dp->anadv_100fdx = B_FALSE;
5184 dp->anadv_100hdx = B_FALSE;
5185 break;
5186 default:
5187 cmn_err(CE_WARN,
5188 "!%s: property %s: illegal value:%d",
5189 dp->name, "speed", val);
5190 dp->anadv_autoneg = B_TRUE;
5191 break;
5192 }
5193 }
5194 val = usbgem_prop_get_int(dp,
5195 "adv_pause", dp->ugc.usbgc_flow_control & 1);
5196 val |= usbgem_prop_get_int(dp,
5197 "adv_asmpause", BOOLEAN(dp->ugc.usbgc_flow_control & 2)) << 1;
5198 if (val > FLOW_CONTROL_RX_PAUSE || val < FLOW_CONTROL_NONE) {
5199 cmn_err(CE_WARN,
5200 "!%s: property %s: illegal value:%d",
5201 dp->name, "flow-control", val);
5202 } else {
5203 val = min(val, dp->ugc.usbgc_flow_control);
5204 }
5205 dp->anadv_pause = BOOLEAN(val & 1);
5206 dp->anadv_asmpause = BOOLEAN(val & 2);
5207
5208 dp->mtu = usbgem_prop_get_int(dp, "mtu", dp->mtu);
5209 dp->txthr = usbgem_prop_get_int(dp, "txthr", dp->txthr);
5210 dp->rxthr = usbgem_prop_get_int(dp, "rxthr", dp->rxthr);
5211 dp->txmaxdma = usbgem_prop_get_int(dp, "txmaxdma", dp->txmaxdma);
5212 dp->rxmaxdma = usbgem_prop_get_int(dp, "rxmaxdma", dp->rxmaxdma);
5213 #ifdef GEM_CONFIG_POLLING
5214 dp->poll_pkt_delay =
5215 usbgem_prop_get_int(dp, "pkt_delay", dp->poll_pkt_delay);
5216
5217 dp->max_poll_interval[GEM_SPD_10] =
5218 usbgem_prop_get_int(dp, "max_poll_interval_10",
5219 dp->max_poll_interval[GEM_SPD_10]);
5220 dp->max_poll_interval[GEM_SPD_100] =
5221 usbgem_prop_get_int(dp, "max_poll_interval_100",
5222 dp->max_poll_interval[GEM_SPD_100]);
5223 dp->max_poll_interval[GEM_SPD_1000] =
5224 usbgem_prop_get_int(dp, "max_poll_interval_1000",
5225 dp->max_poll_interval[GEM_SPD_1000]);
5226
5227 dp->min_poll_interval[GEM_SPD_10] =
5228 usbgem_prop_get_int(dp, "min_poll_interval_10",
5229 dp->min_poll_interval[GEM_SPD_10]);
5230 dp->min_poll_interval[GEM_SPD_100] =
5231 usbgem_prop_get_int(dp, "min_poll_interval_100",
5232 dp->min_poll_interval[GEM_SPD_100]);
5233 dp->min_poll_interval[GEM_SPD_1000] =
5234 usbgem_prop_get_int(dp, "min_poll_interval_1000",
5235 dp->min_poll_interval[GEM_SPD_1000]);
5236 #endif
5237 }
5238
5239 /*
5240 * usbem kstat support
5241 */
5242 #ifndef GEM_CONFIG_GLDv3
5243 /* kstat items based from dmfe driver */
5244
5245 struct usbgem_kstat_named {
5246 struct kstat_named ks_xcvr_addr;
5247 struct kstat_named ks_xcvr_id;
5248 struct kstat_named ks_xcvr_inuse;
5249 struct kstat_named ks_link_up;
5250 struct kstat_named ks_link_duplex; /* 0:unknwon, 1:half, 2:full */
5251 struct kstat_named ks_cap_1000fdx;
5252 struct kstat_named ks_cap_1000hdx;
5253 struct kstat_named ks_cap_100fdx;
5254 struct kstat_named ks_cap_100hdx;
5255 struct kstat_named ks_cap_10fdx;
5256 struct kstat_named ks_cap_10hdx;
5257 #ifdef NEVER
5258 struct kstat_named ks_cap_remfault;
5259 #endif
5260 struct kstat_named ks_cap_autoneg;
5261
5262 struct kstat_named ks_adv_cap_1000fdx;
5263 struct kstat_named ks_adv_cap_1000hdx;
5264 struct kstat_named ks_adv_cap_100fdx;
5265 struct kstat_named ks_adv_cap_100hdx;
5266 struct kstat_named ks_adv_cap_10fdx;
5267 struct kstat_named ks_adv_cap_10hdx;
5268 #ifdef NEVER
5269 struct kstat_named ks_adv_cap_remfault;
5270 #endif
5271 struct kstat_named ks_adv_cap_autoneg;
5272 struct kstat_named ks_lp_cap_1000fdx;
5273 struct kstat_named ks_lp_cap_1000hdx;
5274 struct kstat_named ks_lp_cap_100fdx;
5275 struct kstat_named ks_lp_cap_100hdx;
5276 struct kstat_named ks_lp_cap_10fdx;
5277 struct kstat_named ks_lp_cap_10hdx;
5278 struct kstat_named ks_lp_cap_remfault;
5279 struct kstat_named ks_lp_cap_autoneg;
5280 };
5281
5282 static int
5283 usbgem_kstat_update(kstat_t *ksp, int rw)
5284 {
5285 struct usbgem_kstat_named *knp;
5286 struct usbgem_dev *dp = (struct usbgem_dev *)ksp->ks_private;
5287
5288 if (rw != KSTAT_READ) {
5289 return (0);
5290 }
5291
5292 knp = (struct usbgem_kstat_named *)ksp->ks_data;
5293
5294 knp->ks_xcvr_addr.value.ul = dp->mii_phy_addr;
5295 knp->ks_xcvr_id.value.ul = dp->mii_phy_id;
5296 knp->ks_xcvr_inuse.value.ul = usbgem_mac_xcvr_inuse(dp);
5297 knp->ks_link_up.value.ul = dp->mii_state == MII_STATE_LINKUP;
5298 knp->ks_link_duplex.value.ul =
5299 (dp->mii_state == MII_STATE_LINKUP) ?
5300 (dp->full_duplex ? 2 : 1) : 0;
5301
5302 knp->ks_cap_1000fdx.value.ul =
5303 (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
5304 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
5305 knp->ks_cap_1000hdx.value.ul =
5306 (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
5307 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
5308 knp->ks_cap_100fdx.value.ul =
5309 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
5310 knp->ks_cap_100hdx.value.ul =
5311 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
5312 knp->ks_cap_10fdx.value.ul =
5313 BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
5314 knp->ks_cap_10hdx.value.ul =
5315 BOOLEAN(dp->mii_status & MII_STATUS_10);
5316 #ifdef NEVER
5317 knp->ks_cap_remfault.value.ul = B_TRUE;
5318 #endif
5319 knp->ks_cap_autoneg.value.ul =
5320 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
5321
5322 knp->ks_adv_cap_1000fdx.value.ul = dp->anadv_1000fdx;
5323 knp->ks_adv_cap_1000hdx.value.ul = dp->anadv_1000hdx;
5324 knp->ks_adv_cap_100fdx.value.ul = dp->anadv_100fdx;
5325 knp->ks_adv_cap_100hdx.value.ul = dp->anadv_100hdx;
5326 knp->ks_adv_cap_10fdx.value.ul = dp->anadv_10fdx;
5327 knp->ks_adv_cap_10hdx.value.ul = dp->anadv_10hdx;
5328 #ifdef NEVER
5329 knp->ks_adv_cap_remfault.value.ul = 0;
5330 #endif
5331 knp->ks_adv_cap_autoneg.value.ul = dp->anadv_autoneg;
5332
5333 knp->ks_lp_cap_1000fdx.value.ul =
5334 BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
5335 knp->ks_lp_cap_1000hdx.value.ul =
5336 BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
5337 knp->ks_lp_cap_100fdx.value.ul =
5338 BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
5339 knp->ks_lp_cap_100hdx.value.ul =
5340 BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
5341 knp->ks_lp_cap_10fdx.value.ul =
5342 BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
5343 knp->ks_lp_cap_10hdx.value.ul =
5344 BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
5345 knp->ks_lp_cap_remfault.value.ul =
5346 BOOLEAN(dp->mii_exp & MII_AN_EXP_PARFAULT);
5347 knp->ks_lp_cap_autoneg.value.ul =
5348 BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
5349
5350 return (0);
5351 }
5352
5353
5354 static int
5355 usbgem_kstat_init(struct usbgem_dev *dp)
5356 {
5357 int i;
5358 kstat_t *ksp;
5359 struct usbgem_kstat_named *knp;
5360
5361 ksp = kstat_create(
5362 (char *)ddi_driver_name(dp->dip), ddi_get_instance(dp->dip),
5363 "mii", "net", KSTAT_TYPE_NAMED,
5364 sizeof (*knp) / sizeof (knp->ks_xcvr_addr), 0);
5365
5366 if (ksp == NULL) {
5367 cmn_err(CE_WARN, "%s: %s() for mii failed",
5368 dp->name, __func__);
5369 return (USB_FAILURE);
5370 }
5371
5372 knp = (struct usbgem_kstat_named *)ksp->ks_data;
5373
5374 kstat_named_init(&knp->ks_xcvr_addr, "xcvr_addr",
5375 KSTAT_DATA_INT32);
5376 kstat_named_init(&knp->ks_xcvr_id, "xcvr_id",
5377 KSTAT_DATA_UINT32);
5378 kstat_named_init(&knp->ks_xcvr_inuse, "xcvr_inuse",
5379 KSTAT_DATA_UINT32);
5380 kstat_named_init(&knp->ks_link_up, "link_up",
5381 KSTAT_DATA_UINT32);
5382 kstat_named_init(&knp->ks_link_duplex, "link_duplex",
5383 KSTAT_DATA_UINT32);
5384 kstat_named_init(&knp->ks_cap_1000fdx, "cap_1000fdx",
5385 KSTAT_DATA_UINT32);
5386 kstat_named_init(&knp->ks_cap_1000hdx, "cap_1000hdx",
5387 KSTAT_DATA_UINT32);
5388 kstat_named_init(&knp->ks_cap_100fdx, "cap_100fdx",
5389 KSTAT_DATA_UINT32);
5390 kstat_named_init(&knp->ks_cap_100hdx, "cap_100hdx",
5391 KSTAT_DATA_UINT32);
5392 kstat_named_init(&knp->ks_cap_10fdx, "cap_10fdx",
5393 KSTAT_DATA_UINT32);
5394 kstat_named_init(&knp->ks_cap_10hdx, "cap_10hdx",
5395 KSTAT_DATA_UINT32);
5396 #ifdef NEVER
5397 kstat_named_init(&knp->ks_cap_remfault, "cap_rem_fault",
5398 KSTAT_DATA_UINT32);
5399 #endif
5400 kstat_named_init(&knp->ks_cap_autoneg, "cap_autoneg",
5401 KSTAT_DATA_UINT32);
5402 kstat_named_init(&knp->ks_adv_cap_1000fdx, "adv_cap_1000fdx",
5403 KSTAT_DATA_UINT32);
5404 kstat_named_init(&knp->ks_adv_cap_1000hdx, "adv_cap_1000hdx",
5405 KSTAT_DATA_UINT32);
5406 kstat_named_init(&knp->ks_adv_cap_100fdx, "adv_cap_100fdx",
5407 KSTAT_DATA_UINT32);
5408 kstat_named_init(&knp->ks_adv_cap_100hdx, "adv_cap_100hdx",
5409 KSTAT_DATA_UINT32);
5410 kstat_named_init(&knp->ks_adv_cap_10fdx, "adv_cap_10fdx",
5411 KSTAT_DATA_UINT32);
5412 kstat_named_init(&knp->ks_adv_cap_10hdx, "adv_cap_10hdx",
5413 KSTAT_DATA_UINT32);
5414 #ifdef NEVER
5415 kstat_named_init(&knp->ks_adv_cap_remfault, "adv_rem_fault",
5416 KSTAT_DATA_UINT32);
5417 #endif
5418 kstat_named_init(&knp->ks_adv_cap_autoneg, "adv_cap_autoneg",
5419 KSTAT_DATA_UINT32);
5420
5421 kstat_named_init(&knp->ks_lp_cap_1000fdx, "lp_cap_1000fdx",
5422 KSTAT_DATA_UINT32);
5423 kstat_named_init(&knp->ks_lp_cap_1000hdx, "lp_cap_1000hdx",
5424 KSTAT_DATA_UINT32);
5425 kstat_named_init(&knp->ks_lp_cap_100fdx, "lp_cap_100fdx",
5426 KSTAT_DATA_UINT32);
5427 kstat_named_init(&knp->ks_lp_cap_100hdx, "lp_cap_100hdx",
5428 KSTAT_DATA_UINT32);
5429 kstat_named_init(&knp->ks_lp_cap_10fdx, "lp_cap_10fdx",
5430 KSTAT_DATA_UINT32);
5431 kstat_named_init(&knp->ks_lp_cap_10hdx, "lp_cap_10hdx",
5432 KSTAT_DATA_UINT32);
5433 kstat_named_init(&knp->ks_lp_cap_remfault, "lp_cap_rem_fault",
5434 KSTAT_DATA_UINT32);
5435 kstat_named_init(&knp->ks_lp_cap_autoneg, "lp_cap_autoneg",
5436 KSTAT_DATA_UINT32);
5437
5438 ksp->ks_private = (void *) dp;
5439 ksp->ks_update = usbgem_kstat_update;
5440 dp->ksp = ksp;
5441
5442 kstat_install(ksp);
5443
5444 return (USB_SUCCESS);
5445 }
5446 #endif /* GEM_CONFIG_GLDv3 */
5447 /* ======================================================================== */
5448 /*
5449 * attach/detatch/usb support
5450 */
5451 /* ======================================================================== */
5452 int
5453 usbgem_ctrl_out(struct usbgem_dev *dp,
5454 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5455 void *bp, int size)
5456 {
5457 mblk_t *data;
5458 usb_ctrl_setup_t setup;
5459 usb_cr_t completion_reason;
5460 usb_cb_flags_t cb_flags;
5461 usb_flags_t flags;
5462 int i;
5463 int ret;
5464
5465 DPRINTF(4, (CE_CONT, "!%s: %s "
5466 "reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x "
5467 "bp:0x%p nic_state:%d",
5468 dp->name, __func__, reqt, req, val, ix, len, bp, dp->nic_state));
5469
5470 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5471 return (USB_PIPE_ERROR);
5472 }
5473
5474 data = NULL;
5475 if (size > 0) {
5476 if ((data = allocb(size, 0)) == NULL) {
5477 return (USB_FAILURE);
5478 }
5479
5480 bcopy(bp, data->b_rptr, size);
5481 data->b_wptr = data->b_rptr + size;
5482 }
5483
5484 setup.bmRequestType = reqt;
5485 setup.bRequest = req;
5486 setup.wValue = val;
5487 setup.wIndex = ix;
5488 setup.wLength = len;
5489 setup.attrs = 0; /* attributes */
5490
5491 for (i = usbgem_ctrl_retry; i > 0; i--) {
5492 completion_reason = 0;
5493 cb_flags = 0;
5494
5495 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp),
5496 &setup, &data, &completion_reason, &cb_flags, 0);
5497
5498 if (ret == USB_SUCCESS) {
5499 break;
5500 }
5501 if (i == 1) {
5502 cmn_err(CE_WARN,
5503 "!%s: %s failed: "
5504 "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5505 "ret:%d cr:%s(%d), cb_flags:0x%x %s",
5506 dp->name, __func__, reqt, req, val, ix, len,
5507 ret, usb_str_cr(completion_reason),
5508 completion_reason,
5509 cb_flags,
5510 (i > 1) ? "retrying..." : "fatal");
5511 }
5512 }
5513
5514 if (data != NULL) {
5515 freemsg(data);
5516 }
5517
5518 return (ret);
5519 }
5520
5521 int
5522 usbgem_ctrl_in(struct usbgem_dev *dp,
5523 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5524 void *bp, int size)
5525 {
5526 mblk_t *data;
5527 usb_ctrl_setup_t setup;
5528 usb_cr_t completion_reason;
5529 usb_cb_flags_t cb_flags;
5530 int i;
5531 int ret;
5532 int reclen;
5533
5534 DPRINTF(4, (CE_CONT,
5535 "!%s: %s:"
5536 " reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x"
5537 " bp:x%p mac_state:%d",
5538 dp->name, __func__, reqt, req, val, ix, len, bp, dp->mac_state));
5539
5540 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5541 return (USB_PIPE_ERROR);
5542 }
5543
5544 data = NULL;
5545
5546 setup.bmRequestType = reqt;
5547 setup.bRequest = req;
5548 setup.wValue = val;
5549 setup.wIndex = ix;
5550 setup.wLength = len;
5551 setup.attrs = USB_ATTRS_AUTOCLEARING; /* XXX */
5552
5553 for (i = usbgem_ctrl_retry; i > 0; i--) {
5554 completion_reason = 0;
5555 cb_flags = 0;
5556 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp), &setup, &data,
5557 &completion_reason, &cb_flags, 0);
5558
5559 if (ret == USB_SUCCESS) {
5560 reclen = msgdsize(data);
5561 bcopy(data->b_rptr, bp, min(reclen, size));
5562 break;
5563 }
5564 if (i == 1) {
5565 cmn_err(CE_WARN,
5566 "!%s: %s failed: "
5567 "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5568 "ret:%d cr:%s(%d) cb_flags:0x%x %s",
5569 dp->name, __func__,
5570 reqt, req, val, ix, len,
5571 ret, usb_str_cr(completion_reason),
5572 completion_reason,
5573 cb_flags,
5574 (i > 1) ? "retrying..." : "fatal");
5575 }
5576 }
5577
5578 if (data) {
5579 freemsg(data);
5580 }
5581
5582 return (ret);
5583 }
5584
5585 int
5586 usbgem_ctrl_out_val(struct usbgem_dev *dp,
5587 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5588 uint32_t v)
5589 {
5590 uint8_t buf[4];
5591
5592 /* convert to little endian from native byte order */
5593 switch (len) {
5594 case 4:
5595 buf[3] = v >> 24;
5596 buf[2] = v >> 16;
5597 /* FALLTHROUGH */
5598 case 2:
5599 buf[1] = v >> 8;
5600 /* FALLTHROUGH */
5601 case 1:
5602 buf[0] = v;
5603 }
5604
5605 return (usbgem_ctrl_out(dp, reqt, req, val, ix, len, buf, len));
5606 }
5607
5608 int
5609 usbgem_ctrl_in_val(struct usbgem_dev *dp,
5610 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5611 void *valp)
5612 {
5613 uint8_t buf[4];
5614 uint_t v;
5615 int err;
5616
5617 #ifdef SANITY
5618 bzero(buf, sizeof (buf));
5619 #endif
5620 err = usbgem_ctrl_in(dp, reqt, req, val, ix, len, buf, len);
5621 if (err == USB_SUCCESS) {
5622 v = 0;
5623 switch (len) {
5624 case 4:
5625 v |= buf[3] << 24;
5626 v |= buf[2] << 16;
5627 /* FALLTHROUGH */
5628 case 2:
5629 v |= buf[1] << 8;
5630 /* FALLTHROUGH */
5631 case 1:
5632 v |= buf[0];
5633 }
5634
5635 switch (len) {
5636 case 4:
5637 *(uint32_t *)valp = v;
5638 break;
5639 case 2:
5640 *(uint16_t *)valp = v;
5641 break;
5642 case 1:
5643 *(uint8_t *)valp = v;
5644 break;
5645 }
5646 }
5647 return (err);
5648 }
5649
5650 /*
5651 * Attach / detach / disconnect / reconnect management
5652 */
5653 static int
5654 usbgem_open_pipes(struct usbgem_dev *dp)
5655 {
5656 int i;
5657 int ret;
5658 int ifnum;
5659 int alt;
5660 usb_client_dev_data_t *reg_data;
5661 usb_ep_data_t *ep_tree_node;
5662
5663 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5664
5665 ifnum = dp->ugc.usbgc_ifnum;
5666 alt = dp->ugc.usbgc_alt;
5667
5668 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5669 0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
5670 if (ep_tree_node == NULL) {
5671 cmn_err(CE_WARN, "!%s: %s: ep_bulkin is NULL",
5672 dp->name, __func__);
5673 goto err;
5674 }
5675 dp->ep_bulkin = &ep_tree_node->ep_descr;
5676
5677 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5678 0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
5679 if (ep_tree_node == NULL) {
5680 cmn_err(CE_WARN, "!%s: %s: ep_bulkout is NULL",
5681 dp->name, __func__);
5682 goto err;
5683 }
5684 dp->ep_bulkout = &ep_tree_node->ep_descr;
5685
5686 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5687 0, USB_EP_ATTR_INTR, USB_EP_DIR_IN);
5688 if (ep_tree_node) {
5689 dp->ep_intr = &ep_tree_node->ep_descr;
5690 } else {
5691 /* don't care */
5692 DPRINTF(1, (CE_CONT, "!%s: %s: ep_intr is NULL",
5693 dp->name, __func__));
5694 dp->ep_intr = NULL;
5695 }
5696
5697 /* XXX -- no need to open default pipe */
5698
5699 /* open bulk out pipe */
5700 bzero(&dp->policy_bulkout, sizeof (usb_pipe_policy_t));
5701 dp->policy_bulkout.pp_max_async_reqs = 1;
5702
5703 if ((ret = usb_pipe_open(dp->dip,
5704 dp->ep_bulkout, &dp->policy_bulkout, USB_FLAGS_SLEEP,
5705 &dp->bulkout_pipe)) != USB_SUCCESS) {
5706 cmn_err(CE_WARN,
5707 "!%s: %s: err:%x: failed to open bulk-out pipe",
5708 dp->name, __func__, ret);
5709 dp->bulkout_pipe = NULL;
5710 goto err;
5711 }
5712 DPRINTF(1, (CE_CONT, "!%s: %s: bulkout_pipe opened successfully",
5713 dp->name, __func__));
5714
5715 /* open bulk in pipe */
5716 bzero(&dp->policy_bulkin, sizeof (usb_pipe_policy_t));
5717 dp->policy_bulkin.pp_max_async_reqs = 1;
5718 if ((ret = usb_pipe_open(dp->dip,
5719 dp->ep_bulkin, &dp->policy_bulkin, USB_FLAGS_SLEEP,
5720 &dp->bulkin_pipe)) != USB_SUCCESS) {
5721 cmn_err(CE_WARN,
5722 "!%s: %s: ret:%x failed to open bulk-in pipe",
5723 dp->name, __func__, ret);
5724 dp->bulkin_pipe = NULL;
5725 goto err;
5726 }
5727 DPRINTF(1, (CE_CONT, "!%s: %s: bulkin_pipe opened successfully",
5728 dp->name, __func__));
5729
5730 if (dp->ep_intr) {
5731 /* open interrupt pipe */
5732 bzero(&dp->policy_interrupt, sizeof (usb_pipe_policy_t));
5733 dp->policy_interrupt.pp_max_async_reqs = 1;
5734 if ((ret = usb_pipe_open(dp->dip, dp->ep_intr,
5735 &dp->policy_interrupt, USB_FLAGS_SLEEP,
5736 &dp->intr_pipe)) != USB_SUCCESS) {
5737 cmn_err(CE_WARN,
5738 "!%s: %s: ret:%x failed to open interrupt pipe",
5739 dp->name, __func__, ret);
5740 dp->intr_pipe = NULL;
5741 goto err;
5742 }
5743 }
5744 DPRINTF(1, (CE_CONT, "!%s: %s: intr_pipe opened successfully",
5745 dp->name, __func__));
5746
5747 return (USB_SUCCESS);
5748
5749 err:
5750 if (dp->bulkin_pipe) {
5751 usb_pipe_close(dp->dip,
5752 dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5753 dp->bulkin_pipe = NULL;
5754 }
5755 if (dp->bulkout_pipe) {
5756 usb_pipe_close(dp->dip,
5757 dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5758 dp->bulkout_pipe = NULL;
5759 }
5760 if (dp->intr_pipe) {
5761 usb_pipe_close(dp->dip,
5762 dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5763 dp->intr_pipe = NULL;
5764 }
5765
5766 return (USB_FAILURE);
5767 }
5768
5769 static int
5770 usbgem_close_pipes(struct usbgem_dev *dp)
5771 {
5772 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5773
5774 if (dp->intr_pipe) {
5775 usb_pipe_close(dp->dip,
5776 dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5777 dp->intr_pipe = NULL;
5778 }
5779 DPRINTF(1, (CE_CONT, "!%s: %s: 1", dp->name, __func__));
5780
5781 ASSERT(dp->bulkin_pipe);
5782 usb_pipe_close(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5783 dp->bulkin_pipe = NULL;
5784 DPRINTF(1, (CE_CONT, "!%s: %s: 2", dp->name, __func__));
5785
5786 ASSERT(dp->bulkout_pipe);
5787 usb_pipe_close(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5788 dp->bulkout_pipe = NULL;
5789 DPRINTF(1, (CE_CONT, "!%s: %s: 3", dp->name, __func__));
5790
5791 return (USB_SUCCESS);
5792 }
5793
5794 #define FREEZE_GRACEFUL (B_TRUE)
5795 #define FREEZE_NO_GRACEFUL (B_FALSE)
5796 static int
5797 usbgem_freeze_device(struct usbgem_dev *dp, boolean_t graceful)
5798 {
5799 DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5800
5801 /* stop nic activity */
5802 (void) usbgem_mac_stop(dp, MAC_STATE_DISCONNECTED, graceful);
5803
5804 /*
5805 * Here we free all memory resource allocated, because it will
5806 * cause to panic the system that we free usb_bulk_req objects
5807 * during the usb device is disconnected.
5808 */
5809 (void) usbgem_free_memory(dp);
5810
5811 return (USB_SUCCESS);
5812 }
5813
5814 static int
5815 usbgem_disconnect_cb(dev_info_t *dip)
5816 {
5817 int ret;
5818 struct usbgem_dev *dp;
5819
5820 dp = USBGEM_GET_DEV(dip);
5821
5822 cmn_err(CE_NOTE, "!%s: the usb device was disconnected (dp=%p)",
5823 dp->name, (void *)dp);
5824
5825 /* start serialize */
5826 rw_enter(&dp->dev_state_lock, RW_WRITER);
5827
5828 ret = usbgem_freeze_device(dp, 0);
5829
5830 /* end of serialize */
5831 rw_exit(&dp->dev_state_lock);
5832
5833 return (ret);
5834 }
5835
5836 static int
5837 usbgem_recover_device(struct usbgem_dev *dp)
5838 {
5839 int err;
5840
5841 DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5842
5843 err = USB_SUCCESS;
5844
5845 /* reinitialize the usb connection */
5846 usbgem_close_pipes(dp);
5847 if ((err = usbgem_open_pipes(dp)) != USB_SUCCESS) {
5848 goto x;
5849 }
5850
5851 /* initialize nic state */
5852 dp->mac_state = MAC_STATE_STOPPED;
5853 dp->mii_state = MII_STATE_UNKNOWN;
5854
5855 /* allocate memory resources again */
5856 if ((err = usbgem_alloc_memory(dp)) != USB_SUCCESS) {
5857 goto x;
5858 }
5859
5860 /* restart nic and recover state */
5861 (void) usbgem_restart_nic(dp);
5862
5863 usbgem_mii_init(dp);
5864
5865 /* kick potentially stopped house keeping thread */
5866 cv_signal(&dp->link_watcher_wait_cv);
5867 x:
5868 return (err);
5869 }
5870
5871 static int
5872 usbgem_reconnect_cb(dev_info_t *dip)
5873 {
5874 int err = USB_SUCCESS;
5875 struct usbgem_dev *dp;
5876
5877 dp = USBGEM_GET_DEV(dip);
5878 DPRINTF(0, (CE_CONT, "!%s: dp=%p", ddi_get_name(dip), dp));
5879 #ifdef notdef
5880 /* check device changes after disconnect */
5881 if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5882 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5883 cmn_err(CE_CONT,
5884 "!%s: no or different device installed", dp->name);
5885 return (DDI_SUCCESS);
5886 }
5887 #endif
5888 cmn_err(CE_NOTE, "%s: the usb device was reconnected", dp->name);
5889
5890 /* start serialize */
5891 rw_enter(&dp->dev_state_lock, RW_WRITER);
5892
5893 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5894 err = usbgem_recover_device(dp);
5895 }
5896
5897 /* end of serialize */
5898 rw_exit(&dp->dev_state_lock);
5899
5900 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5901 }
5902
5903 int
5904 usbgem_suspend(dev_info_t *dip)
5905 {
5906 int err = USB_SUCCESS;
5907 struct usbgem_dev *dp;
5908
5909 dp = USBGEM_GET_DEV(dip);
5910
5911 DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5912
5913 /* start serialize */
5914 rw_enter(&dp->dev_state_lock, RW_WRITER);
5915
5916 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5917 err = usbgem_freeze_device(dp, STOP_GRACEFUL);
5918 }
5919
5920 /* end of serialize */
5921 rw_exit(&dp->dev_state_lock);
5922
5923 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5924 }
5925
5926 int
5927 usbgem_resume(dev_info_t *dip)
5928 {
5929 int err = USB_SUCCESS;
5930 struct usbgem_dev *dp;
5931
5932 dp = USBGEM_GET_DEV(dip);
5933
5934 DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5935 #ifdef notdef
5936 /* check device changes after disconnect */
5937 if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5938 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5939 cmn_err(CE_CONT,
5940 "!%s: no or different device installed", dp->name);
5941 return (DDI_SUCCESS);
5942 }
5943 #endif
5944 /* start serialize */
5945 rw_enter(&dp->dev_state_lock, RW_WRITER);
5946
5947 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5948 err = usbgem_recover_device(dp);
5949 }
5950
5951 /* end of serialize */
5952 rw_exit(&dp->dev_state_lock);
5953
5954 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5955 }
5956
5957 #define USBGEM_LOCAL_DATA_SIZE(gc) \
5958 (sizeof (struct usbgem_dev) + USBGEM_MCALLOC)
5959
5960 struct usbgem_dev *
5961 usbgem_do_attach(dev_info_t *dip,
5962 struct usbgem_conf *gc, void *lp, int lmsize)
5963 {
5964 struct usbgem_dev *dp;
5965 int i;
5966 #ifdef USBGEM_CONFIG_GLDv3
5967 mac_register_t *macp = NULL;
5968 #else
5969 gld_mac_info_t *macinfo;
5970 void *tmp;
5971 #endif
5972 int ret;
5973 int unit;
5974 int err;
5975
5976 unit = ddi_get_instance(dip);
5977
5978 DPRINTF(2, (CE_CONT, "!usbgem%d: %s: called", unit, __func__));
5979
5980 /*
5981 * Allocate soft data structure
5982 */
5983 dp = kmem_zalloc(USBGEM_LOCAL_DATA_SIZE(gc), KM_SLEEP);
5984 if (dp == NULL) {
5985 #ifndef USBGEM_CONFIG_GLDv3
5986 gld_mac_free(macinfo);
5987 #endif
5988 return (NULL);
5989 }
5990 #ifdef USBGEM_CONFIG_GLDv3
5991 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5992 cmn_err(CE_WARN, "!gem%d: %s: mac_alloc failed",
5993 unit, __func__);
5994 return (NULL);
5995 }
5996 #else
5997 macinfo = gld_mac_alloc(dip);
5998 dp->macinfo = macinfo;
5999 #endif
6000
6001 /* link to private area */
6002 dp->private = lp;
6003 dp->priv_size = lmsize;
6004 dp->mc_list = (struct mcast_addr *)&dp[1];
6005
6006 dp->dip = dip;
6007 bcopy(gc->usbgc_name, dp->name, USBGEM_NAME_LEN);
6008
6009 /*
6010 * register with usb service
6011 */
6012 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6013 cmn_err(CE_WARN,
6014 "%s: %s: usb_client_attach failed",
6015 dp->name, __func__);
6016 goto err_free_private;
6017 }
6018
6019 if (usb_get_dev_data(dip, &dp->reg_data,
6020 USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
6021 dp->reg_data = NULL;
6022 goto err_unregister_client;
6023 }
6024 #ifdef USBGEM_DEBUG_LEVEL
6025 usb_print_descr_tree(dp->dip, dp->reg_data);
6026 #endif
6027
6028 if (usbgem_open_pipes(dp) != USB_SUCCESS) {
6029 /* failed to open pipes */
6030 cmn_err(CE_WARN, "!%s: %s: failed to open pipes",
6031 dp->name, __func__);
6032 goto err_unregister_client;
6033 }
6034
6035 /*
6036 * Initialize mutexs and condition variables
6037 */
6038 mutex_init(&dp->rxlock, NULL, MUTEX_DRIVER, NULL);
6039 mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
6040 cv_init(&dp->rx_drain_cv, NULL, CV_DRIVER, NULL);
6041 cv_init(&dp->tx_drain_cv, NULL, CV_DRIVER, NULL);
6042 rw_init(&dp->dev_state_lock, NULL, RW_DRIVER, NULL);
6043 mutex_init(&dp->link_watcher_lock, NULL, MUTEX_DRIVER, NULL);
6044 cv_init(&dp->link_watcher_wait_cv, NULL, CV_DRIVER, NULL);
6045 sema_init(&dp->hal_op_lock, 1, NULL, SEMA_DRIVER, NULL);
6046 sema_init(&dp->rxfilter_lock, 1, NULL, SEMA_DRIVER, NULL);
6047
6048 /*
6049 * Initialize configuration
6050 */
6051 dp->ugc = *gc;
6052
6053 dp->mtu = ETHERMTU;
6054 dp->rxmode = 0;
6055 dp->speed = USBGEM_SPD_10; /* default is 10Mbps */
6056 dp->full_duplex = B_FALSE; /* default is half */
6057 dp->flow_control = FLOW_CONTROL_NONE;
6058
6059 dp->nic_state = NIC_STATE_STOPPED;
6060 dp->mac_state = MAC_STATE_STOPPED;
6061 dp->mii_state = MII_STATE_UNKNOWN;
6062
6063 /* performance tuning parameters */
6064 dp->txthr = ETHERMAX; /* tx fifo threshoold */
6065 dp->txmaxdma = 16*4; /* tx max dma burst size */
6066 dp->rxthr = 128; /* rx fifo threshoold */
6067 dp->rxmaxdma = 16*4; /* rx max dma burst size */
6068
6069 /*
6070 * Get media mode infomation from .conf file
6071 */
6072 usbgem_read_conf(dp);
6073
6074 /* rx_buf_len depend on MTU */
6075 dp->rx_buf_len = MAXPKTBUF(dp) + dp->ugc.usbgc_rx_header_len;
6076
6077 /*
6078 * Reset the chip
6079 */
6080 if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
6081 cmn_err(CE_WARN,
6082 "!%s: %s: failed to reset the usb device",
6083 dp->name, __func__);
6084 goto err_destroy_locks;
6085 }
6086
6087 /*
6088 * HW dependant paremeter initialization
6089 */
6090 if (usbgem_hal_attach_chip(dp) != USB_SUCCESS) {
6091 cmn_err(CE_WARN,
6092 "!%s: %s: failed to attach the usb device",
6093 dp->name, __func__);
6094 goto err_destroy_locks;
6095 }
6096
6097 /* allocate resources */
6098 if (usbgem_alloc_memory(dp) != USB_SUCCESS) {
6099 goto err_destroy_locks;
6100 }
6101
6102 DPRINTF(0, (CE_CONT,
6103 "!%s: %02x:%02x:%02x:%02x:%02x:%02x",
6104 dp->name,
6105 dp->dev_addr.ether_addr_octet[0],
6106 dp->dev_addr.ether_addr_octet[1],
6107 dp->dev_addr.ether_addr_octet[2],
6108 dp->dev_addr.ether_addr_octet[3],
6109 dp->dev_addr.ether_addr_octet[4],
6110 dp->dev_addr.ether_addr_octet[5]));
6111
6112 /* copy mac address */
6113 dp->cur_addr = dp->dev_addr;
6114
6115 /* pre-calculated tx timeout in second for performance */
6116 dp->bulkout_timeout =
6117 dp->ugc.usbgc_tx_timeout / drv_usectohz(1000*1000);
6118
6119 #ifdef USBGEM_CONFIG_GLDv3
6120 usbgem_gld3_init(dp, macp);
6121 #else
6122 usbgem_gld_init(dp, macinfo, ident);
6123 #endif
6124
6125 /* Probe MII phy (scan phy) */
6126 dp->mii_lpable = 0;
6127 dp->mii_advert = 0;
6128 dp->mii_exp = 0;
6129 dp->mii_ctl1000 = 0;
6130 dp->mii_stat1000 = 0;
6131
6132 dp->mii_status_ro = 0;
6133 dp->mii_xstatus_ro = 0;
6134
6135 if (usbgem_mii_probe(dp) != USB_SUCCESS) {
6136 cmn_err(CE_WARN, "!%s: %s: mii_probe failed",
6137 dp->name, __func__);
6138 goto err_free_memory;
6139 }
6140
6141 /* mask unsupported abilities */
6142 dp->anadv_autoneg &= BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
6143 dp->anadv_1000fdx &=
6144 BOOLEAN(dp->mii_xstatus &
6145 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD));
6146 dp->anadv_1000hdx &=
6147 BOOLEAN(dp->mii_xstatus &
6148 (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET));
6149 dp->anadv_100t4 &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
6150 dp->anadv_100fdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
6151 dp->anadv_100hdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
6152 dp->anadv_10fdx &= BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
6153 dp->anadv_10hdx &= BOOLEAN(dp->mii_status & MII_STATUS_10);
6154
6155 if (usbgem_mii_init(dp) != USB_SUCCESS) {
6156 cmn_err(CE_WARN, "!%s: %s: mii_init failed",
6157 dp->name, __func__);
6158 goto err_free_memory;
6159 }
6160
6161 /*
6162 * initialize kstats including mii statistics
6163 */
6164 #ifdef USBGEM_CONFIG_GLDv3
6165 #ifdef USBGEM_CONFIG_ND
6166 usbgem_nd_setup(dp);
6167 #endif
6168 #else
6169 if (usbgem_kstat_init(dp) != USB_SUCCESS) {
6170 goto err_free_memory;
6171 }
6172 #endif
6173
6174 /*
6175 * Add interrupt to system.
6176 */
6177 #ifdef USBGEM_CONFIG_GLDv3
6178 if (ret = mac_register(macp, &dp->mh)) {
6179 cmn_err(CE_WARN, "!%s: mac_register failed, error:%d",
6180 dp->name, ret);
6181 goto err_release_stats;
6182 }
6183 mac_free(macp);
6184 macp = NULL;
6185 #else
6186 /* gld_register will corrupts driver_private */
6187 tmp = ddi_get_driver_private(dip);
6188 if (gld_register(dip,
6189 (char *)ddi_driver_name(dip), macinfo) != DDI_SUCCESS) {
6190 cmn_err(CE_WARN, "!%s: %s: gld_register failed",
6191 dp->name, __func__);
6192 ddi_set_driver_private(dip, tmp);
6193 goto err_release_stats;
6194 }
6195 /* restore driver private */
6196 ddi_set_driver_private(dip, tmp);
6197 #endif /* USBGEM_CONFIG_GLDv3 */
6198 if (usb_register_hotplug_cbs(dip,
6199 usbgem_suspend, usbgem_resume) != USB_SUCCESS) {
6200 cmn_err(CE_WARN,
6201 "!%s: %s: failed to register hotplug cbs",
6202 dp->name, __func__);
6203 goto err_unregister_gld;
6204 }
6205
6206 /* reset mii and start mii link watcher */
6207 if (usbgem_mii_start(dp) != USB_SUCCESS) {
6208 goto err_unregister_hotplug;
6209 }
6210
6211 /* start tx watchdow watcher */
6212 if (usbgem_tx_watcher_start(dp)) {
6213 goto err_usbgem_mii_stop;
6214 }
6215
6216 ddi_set_driver_private(dip, (caddr_t)dp);
6217
6218 DPRINTF(2, (CE_CONT, "!%s: %s: return: success", dp->name, __func__));
6219
6220 return (dp);
6221
6222 err_usbgem_mii_stop:
6223 usbgem_mii_stop(dp);
6224
6225 err_unregister_hotplug:
6226 usb_unregister_hotplug_cbs(dip);
6227
6228 err_unregister_gld:
6229 #ifdef USBGEM_CONFIG_GLDv3
6230 mac_unregister(dp->mh);
6231 #else
6232 gld_unregister(macinfo);
6233 #endif
6234
6235 err_release_stats:
6236 #ifdef USBGEM_CONFIG_GLDv3
6237 #ifdef USBGEM_CONFIG_ND
6238 /* release NDD resources */
6239 usbgem_nd_cleanup(dp);
6240 #endif
6241 #else
6242 kstat_delete(dp->ksp);
6243 #endif
6244
6245 err_free_memory:
6246 usbgem_free_memory(dp);
6247
6248 err_destroy_locks:
6249 cv_destroy(&dp->tx_drain_cv);
6250 cv_destroy(&dp->rx_drain_cv);
6251 mutex_destroy(&dp->txlock);
6252 mutex_destroy(&dp->rxlock);
6253 rw_destroy(&dp->dev_state_lock);
6254 mutex_destroy(&dp->link_watcher_lock);
6255 cv_destroy(&dp->link_watcher_wait_cv);
6256 sema_destroy(&dp->hal_op_lock);
6257 sema_destroy(&dp->rxfilter_lock);
6258
6259 err_close_pipes:
6260 (void) usbgem_close_pipes(dp);
6261
6262 err_unregister_client:
6263 usb_client_detach(dp->dip, dp->reg_data);
6264
6265 err_free_private:
6266 #ifdef USBGEM_CONFIG_GLDv3
6267 if (macp) {
6268 mac_free(macp);
6269 }
6270 #else
6271 gld_mac_free(macinfo);
6272 #endif
6273 kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(gc));
6274
6275 return (NULL);
6276 }
6277
6278 int
6279 usbgem_do_detach(dev_info_t *dip)
6280 {
6281 struct usbgem_dev *dp;
6282
6283 dp = USBGEM_GET_DEV(dip);
6284
6285 #ifdef USBGEM_CONFIG_GLDv3
6286 /* unregister with gld v3 */
6287 if (mac_unregister(dp->mh) != DDI_SUCCESS) {
6288 return (DDI_FAILURE);
6289 }
6290 #else
6291 /* unregister with gld v2 */
6292 if (gld_unregister(dp->macinfo) != DDI_SUCCESS) {
6293 return (DDI_FAILURE);
6294 }
6295 #endif
6296 /* unregister with hotplug service */
6297 usb_unregister_hotplug_cbs(dip);
6298
6299 /* stop tx watchdog watcher */
6300 usbgem_tx_watcher_stop(dp);
6301
6302 /* stop the link manager */
6303 usbgem_mii_stop(dp);
6304
6305 /* unregister with usb service */
6306 (void) usbgem_free_memory(dp);
6307 (void) usbgem_close_pipes(dp);
6308 usb_client_detach(dp->dip, dp->reg_data);
6309 dp->reg_data = NULL;
6310
6311 /* unregister with kernel statistics */
6312 #ifdef USBGEM_CONFIG_GLDv3
6313 #ifdef USBGEM_CONFIG_ND
6314 /* release ndd resources */
6315 usbgem_nd_cleanup(dp);
6316 #endif
6317 #else
6318 /* destroy kstat objects */
6319 kstat_delete(dp->ksp);
6320 #endif
6321
6322 /* release locks and condition variables */
6323 mutex_destroy(&dp->txlock);
6324 mutex_destroy(&dp->rxlock);
6325 cv_destroy(&dp->tx_drain_cv);
6326 cv_destroy(&dp->rx_drain_cv);
6327 rw_destroy(&dp->dev_state_lock);
6328 mutex_destroy(&dp->link_watcher_lock);
6329 cv_destroy(&dp->link_watcher_wait_cv);
6330 sema_destroy(&dp->hal_op_lock);
6331 sema_destroy(&dp->rxfilter_lock);
6332
6333 /* release basic memory resources */
6334 #ifndef USBGEM_CONFIG_GLDv3
6335 gld_mac_free(dp->macinfo);
6336 #endif
6337 kmem_free((caddr_t)(dp->private), dp->priv_size);
6338 kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(&dp->ugc));
6339
6340 DPRINTF(2, (CE_CONT, "!%s: %s: return: success",
6341 ddi_driver_name(dip), __func__));
6342
6343 return (DDI_SUCCESS);
6344 }
6345
6346 int
6347 usbgem_mod_init(struct dev_ops *dop, char *name)
6348 {
6349 #ifdef USBGEM_CONFIG_GLDv3
6350 major_t major;
6351 major = ddi_name_to_major(name);
6352 if (major == DDI_MAJOR_T_NONE) {
6353 return (DDI_FAILURE);
6354 }
6355 mac_init_ops(dop, name);
6356 #endif
6357 return (DDI_SUCCESS);
6358 }
6359
6360 void
6361 usbgem_mod_fini(struct dev_ops *dop)
6362 {
6363 #ifdef USBGEM_CONFIG_GLDv3
6364 mac_fini_ops(dop);
6365 #endif
6366 }
6367
6368 int
6369 usbgem_quiesce(dev_info_t *dip)
6370 {
6371 struct usbgem_dev *dp;
6372
6373 dp = USBGEM_GET_DEV(dip);
6374
6375 ASSERT(dp != NULL);
6376
6377 if (dp->mac_state != MAC_STATE_DISCONNECTED &&
6378 dp->mac_state != MAC_STATE_STOPPED) {
6379 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
6380 (void) usbgem_hal_reset_chip(dp);
6381 }
6382 }
6383
6384 /* devo_quiesce() must return DDI_SUCCESS always */
6385 return (DDI_SUCCESS);
6386 }