8789 usbgem: variable set but unused
[unleashed.git] / usr / src / uts / common / io / usbgem / usbgem.c
blob16310a6b396c349293ee216a165f9ed9abe8470c
1 /*
2 * usbgem.c: General USB to Fast Ethernet mac driver framework
4 * Copyright (c) 2002-2012 Masayuki Murayama. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
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.
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.
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.
35 * Change log
39 * TODO:
40 * implement DELAYED_START
44 * System Header files.
46 #include <sys/types.h>
47 #include <sys/conf.h>
48 #include <sys/debug.h>
49 #include <sys/kmem.h>
50 #include <sys/vtrace.h>
51 #include <sys/ethernet.h>
52 #include <sys/modctl.h>
53 #include <sys/errno.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56 #ifndef USBGEM_CONFIG_GLDv3
57 #include <sys/dlpi.h>
58 #include <sys/strsubr.h>
59 #endif
60 #include <sys/stream.h> /* required for MBLK* */
61 #include <sys/strsun.h> /* required for mionack() */
62 #include <sys/byteorder.h>
64 #include <sys/usb/usba.h>
65 #ifdef USBGEM_CONFIG_GLDv3
66 #include <inet/common.h>
67 #include <inet/led.h>
68 #include <inet/mi.h>
69 #include <inet/nd.h>
70 #endif
72 /* supplement definitions */
73 extern const char *usb_str_cr(usb_cr_t);
75 #ifndef USBGEM_CONFIG_GLDv3
76 #pragma weak gld_linkstate
77 #endif
78 #include <sys/note.h>
80 #include "usbgem_mii.h"
81 #include "usbgem.h"
83 #ifdef MODULE
84 char ident[] = "usb general ethernet mac driver v" VERSION;
85 #else
86 extern char ident[];
87 #endif
89 /* Debugging support */
90 #ifdef USBGEM_DEBUG_LEVEL
91 static int usbgem_debug = USBGEM_DEBUG_LEVEL;
92 #define DPRINTF(n, args) if (usbgem_debug > (n)) cmn_err args
93 #else
94 #define DPRINTF(n, args)
95 #endif
98 * Useful macros and typedefs
100 #define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
101 #define DEFAULT_PIPE(dp) ((dp)->reg_data->dev_default_ph)
102 #define VTAG_SIZE 4
103 #define BOOLEAN(x) ((x) != 0)
105 * configuration parameters
107 #define USBDRV_MAJOR_VER 2
108 #define USBDRV_MINOR_VER 0
110 #define ETHERHEADERL (sizeof (struct ether_header))
111 #define MAXPKTLEN(dp) ((dp)->mtu + ETHERHEADERL)
112 #define MAXPKTBUF(dp) ((dp)->mtu + ETHERHEADERL + ETHERFCSL)
114 #define WATCH_INTERVAL_FAST drv_usectohz(100*1000)
116 #define STOP_GRACEFUL B_TRUE
119 * Private functions
121 static int usbgem_open_pipes(struct usbgem_dev *dp);
122 static int usbgem_close_pipes(struct usbgem_dev *dp);
123 static void usbgem_intr_cb(usb_pipe_handle_t, usb_intr_req_t *);
124 static void usbgem_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
125 static void usbgem_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
127 static int usbgem_mii_start(struct usbgem_dev *);
128 static void usbgem_mii_stop(struct usbgem_dev *);
130 /* local buffer management */
131 static int usbgem_init_rx_buf(struct usbgem_dev *);
133 /* internal mac interfaces */
134 static void usbgem_tx_timeout(struct usbgem_dev *);
135 static void usbgem_mii_link_watcher(struct usbgem_dev *);
136 static int usbgem_mac_init(struct usbgem_dev *);
137 static int usbgem_mac_start(struct usbgem_dev *);
138 static int usbgem_mac_stop(struct usbgem_dev *, int, boolean_t);
139 static void usbgem_mac_ioctl(struct usbgem_dev *, queue_t *, mblk_t *);
141 int usbgem_speed_value[] = {10, 100, 1000};
143 static int usbgem_ctrl_retry = 5;
145 /* usb event support */
146 static int usbgem_disconnect_cb(dev_info_t *dip);
147 static int usbgem_reconnect_cb(dev_info_t *dip);
148 int usbgem_suspend(dev_info_t *dip);
149 int usbgem_resume(dev_info_t *dip);
151 static uint8_t usbgem_bcastaddr[] = {
152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
155 #ifdef MODULE
156 extern struct mod_ops mod_miscops;
158 static struct modlmisc modlmisc = {
159 &mod_miscops,
160 "usbgem v" VERSION,
163 static struct modlinkage modlinkage = {
164 MODREV_1, &modlmisc, NULL
168 * _init : done
171 _init(void)
173 int status;
175 DPRINTF(2, (CE_CONT, "!usbgem: _init: called"));
176 status = mod_install(&modlinkage);
178 return (status);
182 * _fini : done
185 _fini(void)
187 int status;
189 DPRINTF(2, (CE_CONT, "!usbgem: _fini: called"));
190 status = mod_remove(&modlinkage);
191 return (status);
195 _info(struct modinfo *modinfop)
197 return (mod_info(&modlinkage, modinfop));
199 #endif /* MODULE */
201 /* ============================================================== */
203 * Ether CRC calculation utilities
205 /* ============================================================== */
207 * Ether CRC calculation according to 21143 data sheet
209 #define CRC32_POLY_LE 0xedb88320
210 uint32_t
211 usbgem_ether_crc_le(const uint8_t *addr)
213 int idx;
214 int bit;
215 uint_t data;
216 uint32_t crc = 0xffffffff;
218 crc = 0xffffffff;
219 for (idx = 0; idx < ETHERADDRL; idx++) {
220 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
221 crc = (crc >> 1) ^
222 (((crc ^ data) & 1) ? CRC32_POLY_LE : 0);
225 return (crc);
228 #define CRC32_POLY_BE 0x04c11db7
229 uint32_t
230 usbgem_ether_crc_be(const uint8_t *addr)
232 int idx;
233 int bit;
234 uint_t data;
235 uint32_t crc;
237 crc = 0xffffffff;
238 for (idx = 0; idx < ETHERADDRL; idx++) {
239 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
240 crc = (crc << 1) ^
241 ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
244 return (crc);
248 usbgem_prop_get_int(struct usbgem_dev *dp, char *prop_template, int def_val)
250 char propname[32];
252 (void) sprintf(propname, prop_template, dp->name);
254 return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
255 DDI_PROP_DONTPASS, propname, def_val));
258 static int
259 usbgem_population(uint32_t x)
261 int i;
262 int cnt;
264 cnt = 0;
265 for (i = 0; i < 32; i++) {
266 if (x & (1 << i)) {
267 cnt++;
270 return (cnt);
273 static clock_t
274 usbgem_timestamp_nz()
276 clock_t now;
277 now = ddi_get_lbolt();
278 return (now ? now : (clock_t)1);
281 #ifdef USBGEM_DEBUG_LEVEL
282 #ifdef USBGEM_DEBUG_VLAN
283 #ifdef notdef
284 #include <netinet/in.h>
285 #endif
286 static void
287 usbgem_dump_packet(struct usbgem_dev *dp, char *title, mblk_t *mp,
288 boolean_t check_cksum)
290 char msg[180];
291 uint8_t buf[18+20+20];
292 uint8_t *p;
293 size_t offset;
294 uint_t ethertype;
295 uint_t proto;
296 uint_t ipproto = 0;
297 uint_t iplen;
298 uint_t iphlen;
299 uint_t tcplen;
300 uint_t udplen;
301 uint_t cksum;
302 int rest;
303 int len;
304 char *bp;
305 mblk_t *tp;
306 extern uint_t ip_cksum(mblk_t *, int, uint32_t);
308 msg[0] = 0;
309 bp = msg;
311 rest = sizeof (buf);
312 offset = 0;
313 for (tp = mp; tp; tp = tp->b_cont) {
314 len = tp->b_wptr - tp->b_rptr;
315 len = min(rest, len);
316 bcopy(tp->b_rptr, &buf[offset], len);
317 rest -= len;
318 offset += len;
319 if (rest == 0) {
320 break;
324 offset = 0;
325 p = &buf[offset];
327 /* ethernet address */
328 sprintf(bp,
329 "ether: %02x:%02x:%02x:%02x:%02x:%02x"
330 " -> %02x:%02x:%02x:%02x:%02x:%02x",
331 p[6], p[7], p[8], p[9], p[10], p[11],
332 p[0], p[1], p[2], p[3], p[4], p[5]);
333 bp = &msg[strlen(msg)];
335 /* vlag tag and etherrtype */
336 ethertype = GET_ETHERTYPE(p);
337 if (ethertype == VTAG_TPID) {
338 sprintf(bp, " vtag:0x%04x", GET_NET16(&p[14]));
339 bp = &msg[strlen(msg)];
341 offset += VTAG_SIZE;
342 p = &buf[offset];
343 ethertype = GET_ETHERTYPE(p);
345 sprintf(bp, " type:%04x", ethertype);
346 bp = &msg[strlen(msg)];
348 /* ethernet packet length */
349 sprintf(bp, " mblklen:%d", msgdsize(mp));
350 bp = &msg[strlen(msg)];
351 if (mp->b_cont) {
352 sprintf(bp, "(");
353 bp = &msg[strlen(msg)];
354 for (tp = mp; tp; tp = tp->b_cont) {
355 if (tp == mp) {
356 sprintf(bp, "%d", tp->b_wptr - tp->b_rptr);
357 } else {
358 sprintf(bp, "+%d", tp->b_wptr - tp->b_rptr);
360 bp = &msg[strlen(msg)];
362 sprintf(bp, ")");
363 bp = &msg[strlen(msg)];
366 if (ethertype != ETHERTYPE_IP) {
367 goto x;
370 /* ip address */
371 offset += sizeof (struct ether_header);
372 p = &buf[offset];
373 ipproto = p[9];
374 iplen = GET_NET16(&p[2]);
375 sprintf(bp, ", ip: %d.%d.%d.%d -> %d.%d.%d.%d proto:%d iplen:%d",
376 p[12], p[13], p[14], p[15],
377 p[16], p[17], p[18], p[19],
378 ipproto, iplen);
379 bp = (void *)&msg[strlen(msg)];
381 iphlen = (p[0] & 0xf) * 4;
383 /* cksum for psuedo header */
384 cksum = *(uint16_t *)&p[12];
385 cksum += *(uint16_t *)&p[14];
386 cksum += *(uint16_t *)&p[16];
387 cksum += *(uint16_t *)&p[18];
388 cksum += BE_16(ipproto);
390 /* tcp or udp protocol header */
391 offset += iphlen;
392 p = &buf[offset];
393 if (ipproto == IPPROTO_TCP) {
394 tcplen = iplen - iphlen;
395 sprintf(bp, ", tcp: len:%d cksum:%x",
396 tcplen, GET_NET16(&p[16]));
397 bp = (void *)&msg[strlen(msg)];
399 if (check_cksum) {
400 cksum += BE_16(tcplen);
401 cksum = (uint16_t)ip_cksum(mp, offset, cksum);
402 sprintf(bp, " (%s)",
403 (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
404 bp = (void *)&msg[strlen(msg)];
406 } else if (ipproto == IPPROTO_UDP) {
407 udplen = GET_NET16(&p[4]);
408 sprintf(bp, ", udp: len:%d cksum:%x",
409 udplen, GET_NET16(&p[6]));
410 bp = (void *)&msg[strlen(msg)];
412 if (GET_NET16(&p[6]) && check_cksum) {
413 cksum += *(uint16_t *)&p[4];
414 cksum = (uint16_t)ip_cksum(mp, offset, cksum);
415 sprintf(bp, " (%s)",
416 (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
417 bp = (void *)&msg[strlen(msg)];
421 cmn_err(CE_CONT, "!%s: %s: %s", dp->name, title, msg);
423 #endif /* USBGEM_DEBUG_VLAN */
424 #endif /* USBGEM_DEBUG_LEVEL */
426 #ifdef GEM_GCC_RUNTIME
428 * gcc3 runtime routines
430 #pragma weak memcmp
432 memcmp(const void *s1, const void *s2, size_t n)
434 int i;
435 int ret;
437 ret = 0;
438 for (i = 0; i < n; i++) {
439 ret = (int)((uint8_t *)s1)[i] - (int)((uint8_t *)s2)[i];
440 if (ret) {
441 return (ret);
444 return (0);
447 #pragma weak memset
448 void *
449 memset(void *s, int c, size_t n)
451 if ((c & 0xff) == 0) {
452 bzero(s, n);
453 } else {
454 while (n--) {
455 ((uint8_t *)s)[n] = c;
458 return (s);
461 #pragma weak _memcpy = memcpy
462 #pragma weak memcpy
463 void *
464 memcpy(void *s1, const void *s2, size_t n)
466 bcopy(s2, s1, n);
467 return (s1);
469 #endif /* GEM_GCC_RUNTIME */
470 /* ============================================================== */
472 * hardware operations
474 /* ============================================================== */
475 static int
476 usbgem_hal_reset_chip(struct usbgem_dev *dp)
478 int err;
480 sema_p(&dp->hal_op_lock);
481 err = (*dp->ugc.usbgc_reset_chip)(dp);
482 sema_v(&dp->hal_op_lock);
483 return (err);
486 static int
487 usbgem_hal_init_chip(struct usbgem_dev *dp)
489 int err;
491 sema_p(&dp->hal_op_lock);
492 err = (*dp->ugc.usbgc_init_chip)(dp);
493 sema_v(&dp->hal_op_lock);
494 return (err);
497 static int
498 usbgem_hal_attach_chip(struct usbgem_dev *dp)
500 int err;
502 sema_p(&dp->hal_op_lock);
503 err = (*dp->ugc.usbgc_attach_chip)(dp);
504 sema_v(&dp->hal_op_lock);
505 return (err);
508 static int
509 usbgem_hal_set_rx_filter(struct usbgem_dev *dp)
511 int err;
513 sema_p(&dp->hal_op_lock);
514 err = (*dp->ugc.usbgc_set_rx_filter)(dp);
515 sema_v(&dp->hal_op_lock);
516 return (err);
519 static int
520 usbgem_hal_set_media(struct usbgem_dev *dp)
522 int err;
524 sema_p(&dp->hal_op_lock);
525 err = (*dp->ugc.usbgc_set_media)(dp);
526 sema_v(&dp->hal_op_lock);
527 return (err);
530 static int
531 usbgem_hal_start_chip(struct usbgem_dev *dp)
533 int err;
535 sema_p(&dp->hal_op_lock);
536 err = (*dp->ugc.usbgc_start_chip)(dp);
537 sema_v(&dp->hal_op_lock);
538 return (err);
541 static int
542 usbgem_hal_stop_chip(struct usbgem_dev *dp)
544 int err;
546 sema_p(&dp->hal_op_lock);
547 err = (*dp->ugc.usbgc_stop_chip)(dp);
548 sema_v(&dp->hal_op_lock);
549 return (err);
552 static int
553 usbgem_hal_get_stats(struct usbgem_dev *dp)
555 int err;
557 sema_p(&dp->hal_op_lock);
558 err = (*dp->ugc.usbgc_get_stats)(dp);
559 sema_v(&dp->hal_op_lock);
560 return (err);
564 /* ============================================================== */
566 * USB pipe management
568 /* ============================================================== */
569 static boolean_t
570 usbgem_rx_start_unit(struct usbgem_dev *dp, usb_bulk_req_t *req)
572 mblk_t *mp;
573 int err;
574 usb_flags_t flags;
576 ASSERT(req);
578 mp = allocb(dp->rx_buf_len, BPRI_MED);
579 if (mp == NULL) {
580 cmn_err(CE_WARN, "!%s: %s: failed to allocate mblk",
581 dp->name, __func__);
582 goto err;
585 req->bulk_len = dp->rx_buf_len;
586 req->bulk_data = mp;
587 req->bulk_client_private = (usb_opaque_t)dp;
588 req->bulk_timeout = 0;
589 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
590 req->bulk_cb = usbgem_bulkin_cb;
591 req->bulk_exc_cb = usbgem_bulkin_cb;
592 req->bulk_completion_reason = 0;
593 req->bulk_cb_flags = 0;
595 flags = 0;
596 err = usb_pipe_bulk_xfer(dp->bulkin_pipe, req, flags);
598 if (err != USB_SUCCESS) {
599 cmn_err(CE_WARN, "%s: failed to bulk_xfer for rx, err:%d",
600 dp->name, err);
602 /* free req and mp */
603 usb_free_bulk_req(req);
604 goto err;
606 return (B_TRUE);
607 err:
608 return (B_FALSE);
611 /* ============================================================== */
613 * Rx/Tx buffer management
615 /* ============================================================== */
616 static int
617 usbgem_init_rx_buf(struct usbgem_dev *dp)
619 int i;
620 usb_bulk_req_t *req;
622 ASSERT(dp->mac_state == MAC_STATE_ONLINE);
624 for (i = 0; i < dp->ugc.usbgc_rx_list_max; i++) {
625 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
626 if (req == NULL) {
627 cmn_err(CE_WARN,
628 "!%s: %s: failed to allocate bulkreq for rx",
629 dp->name, __func__);
630 return (USB_FAILURE);
632 if (!usbgem_rx_start_unit(dp, req)) {
633 return (USB_FAILURE);
635 mutex_enter(&dp->rxlock);
636 dp->rx_busy_cnt++;
637 mutex_exit(&dp->rxlock);
639 return (USB_SUCCESS);
642 /* ============================================================== */
644 * memory resource management
646 /* ============================================================== */
647 static int
648 usbgem_free_memory(struct usbgem_dev *dp)
650 usb_bulk_req_t *req;
652 /* free all tx requst structure */
653 while ((req = dp->tx_free_list) != NULL) {
654 dp->tx_free_list =
655 (usb_bulk_req_t *)req->bulk_client_private;
656 req->bulk_data = NULL;
657 usb_free_bulk_req(req);
659 return (USB_SUCCESS);
662 static int
663 usbgem_alloc_memory(struct usbgem_dev *dp)
665 int i;
666 usb_bulk_req_t *req;
668 /* allocate tx requests */
669 dp->tx_free_list = NULL;
670 for (i = 0; i < dp->ugc.usbgc_tx_list_max; i++) {
671 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
672 if (req == NULL) {
673 cmn_err(CE_WARN,
674 "%s:%s failed to allocate tx requests",
675 dp->name, __func__);
677 /* free partially allocated tx requests */
678 (void) usbgem_free_memory(dp);
679 return (USB_FAILURE);
682 /* add the new one allocated into tx free list */
683 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
684 dp->tx_free_list = req;
687 return (USB_SUCCESS);
690 /* ========================================================== */
692 * Start transmission.
693 * Return zero on success,
695 /* ========================================================== */
697 #ifdef TXTIMEOUT_TEST
698 static int usbgem_send_cnt = 0;
699 #endif
702 * usbgem_send is used only to send data packet into ethernet line.
704 static mblk_t *
705 usbgem_send_common(struct usbgem_dev *dp, mblk_t *mp, uint32_t flags)
707 int err;
708 mblk_t *new;
709 usb_bulk_req_t *req;
710 int mcast;
711 int bcast;
712 int len;
713 boolean_t intr;
714 usb_flags_t usb_flags = 0;
715 #ifdef USBGEM_DEBUG_LEVEL
716 usb_pipe_state_t p_state;
717 #endif
718 DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
720 intr = (flags & 1) != 0;
721 len = msgdsize(mp);
722 bcast = 0;
723 mcast = 0;
724 if (mp->b_rptr[0] & 1) {
725 if (bcmp(mp->b_rptr, &usbgem_bcastaddr, ETHERADDRL) == 0) {
726 bcast = 1;
727 } else {
728 mcast = 1;
731 new = (*dp->ugc.usbgc_tx_make_packet)(dp, mp);
732 if (new == NULL) {
734 * no memory resource. we don't stop downstream,
735 * we just discard the packet.
737 DPRINTF(0, (CE_CONT, "!%s: %s: no memory",
738 dp->name, __func__));
739 freemsg(mp);
741 mutex_enter(&dp->txlock);
742 dp->stats.noxmtbuf++;
743 dp->stats.errxmt++;
744 mutex_exit(&dp->txlock);
746 return (NULL);
749 ASSERT(new->b_cont == NULL);
751 mutex_enter(&dp->txlock);
752 if (dp->tx_free_list == NULL) {
754 * no tx free slot
756 ASSERT(dp->tx_busy_cnt == dp->ugc.usbgc_tx_list_max);
757 mutex_exit(&dp->txlock);
759 DPRINTF(4, (CE_CONT, "!%s: %s: no free slot",
760 dp->name, __func__));
761 if (new && new != mp) {
762 /* free reallocated message */
763 freemsg(new);
765 return (mp);
767 req = dp->tx_free_list;
768 dp->tx_free_list = (usb_bulk_req_t *)req->bulk_client_private;
769 dp->tx_busy_cnt++;
771 if (dp->tx_free_list == NULL) {
772 intr = B_TRUE;
774 if (intr) {
775 dp->tx_intr_pended++;
777 DB_TCI(new) = intr;
778 #ifdef USBGEM_DEBUG_LEVEL
779 new->b_datap->db_cksum32 = dp->tx_seq_num;
780 dp->tx_seq_num++;
781 #endif
782 dp->stats.obytes += len;
783 dp->stats.opackets++;
784 if (bcast | mcast) {
785 dp->stats.obcast += bcast;
786 dp->stats.omcast += mcast;
788 mutex_exit(&dp->txlock);
790 DPRINTF(2, (CE_CONT, "!%s: %s: sending", dp->name, __func__));
792 req->bulk_len = (long)new->b_wptr - (long)new->b_rptr;
793 req->bulk_data = new;
794 req->bulk_client_private = (usb_opaque_t)dp;
795 req->bulk_timeout = dp->bulkout_timeout; /* in second */
796 req->bulk_attributes = 0;
797 req->bulk_cb = usbgem_bulkout_cb;
798 req->bulk_exc_cb = usbgem_bulkout_cb;
799 req->bulk_completion_reason = 0;
800 req->bulk_cb_flags = 0;
802 if (intr) {
803 usb_flags = USB_FLAGS_SLEEP;
805 if ((err = usb_pipe_bulk_xfer(dp->bulkout_pipe, req, usb_flags))
806 != USB_SUCCESS) {
808 /* failed to transfer the packet, discard it. */
809 freemsg(new);
810 req->bulk_data = NULL;
812 /* recycle the request block */
813 mutex_enter(&dp->txlock);
814 dp->tx_busy_cnt--;
815 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
816 dp->tx_free_list = req;
817 mutex_exit(&dp->txlock);
819 cmn_err(CE_NOTE,
820 "%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
821 dp->name, __func__, err);
823 /* we use another flag to indicate error state. */
824 if (dp->fatal_error == (clock_t)0) {
825 dp->fatal_error = usbgem_timestamp_nz();
827 } else {
828 /* record the start time */
829 dp->tx_start_time = ddi_get_lbolt();
832 if (err == USB_SUCCESS && (usb_flags & USB_FLAGS_SLEEP)) {
833 usbgem_bulkout_cb(dp->bulkout_pipe, req);
836 if (new != mp) {
837 freemsg(mp);
839 return (NULL);
843 usbgem_restart_nic(struct usbgem_dev *dp)
845 int ret;
846 int flags = 0;
848 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
850 ASSERT(dp->mac_state != MAC_STATE_DISCONNECTED);
853 * ensure to stop the nic
855 if (dp->mac_state == MAC_STATE_ONLINE) {
856 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
859 /* now the nic become quiescent, reset the chip */
860 if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
861 cmn_err(CE_WARN, "%s: %s: failed to reset chip",
862 dp->name, __func__);
863 goto err;
867 * restore the nic state step by step
869 if (dp->nic_state < NIC_STATE_INITIALIZED) {
870 goto done;
873 if (usbgem_mac_init(dp) != USB_SUCCESS) {
874 cmn_err(CE_WARN, "%s: %s: failed to initialize chip",
875 dp->name, __func__);
876 goto err;
879 /* setup mac address and enable rx filter */
880 sema_p(&dp->rxfilter_lock);
881 dp->rxmode |= RXMODE_ENABLE;
882 ret = usbgem_hal_set_rx_filter(dp);
883 sema_v(&dp->rxfilter_lock);
884 if (ret != USB_SUCCESS) {
885 goto err;
889 * update the link state asynchronously
891 cv_signal(&dp->link_watcher_wait_cv);
894 * XXX - a panic happened because of linkdown.
895 * We must check mii_state here, because the link can be down just
896 * before the restart event happen. If the link is down now,
897 * gem_mac_start() will be called from gem_mii_link_check() when
898 * the link become up later.
900 if (dp->mii_state == MII_STATE_LINKUP) {
901 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
902 goto err;
904 if (dp->nic_state < NIC_STATE_ONLINE) {
905 goto done;
908 (void) usbgem_mac_start(dp);
911 done:
912 return (USB_SUCCESS);
913 err:
914 #ifdef GEM_CONFIG_FMA
915 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
916 #endif
917 return (USB_FAILURE);
920 static void
921 usbgem_tx_timeout(struct usbgem_dev *dp)
923 uint_t rwlock;
924 clock_t now;
926 for (; ; ) {
927 mutex_enter(&dp->tx_watcher_lock);
928 (void) cv_timedwait(&dp->tx_watcher_cv, &dp->tx_watcher_lock,
929 dp->tx_watcher_interval + ddi_get_lbolt());
930 mutex_exit(&dp->tx_watcher_lock);
932 if (dp->tx_watcher_stop) {
933 break;
936 now = ddi_get_lbolt();
938 rwlock = RW_READER;
939 again:
940 rw_enter(&dp->dev_state_lock, rwlock);
942 if ((dp->mac_state != MAC_STATE_DISCONNECTED &&
943 dp->fatal_error &&
944 now - dp->fatal_error >= dp->ugc.usbgc_tx_timeout) ||
945 (dp->mac_state == MAC_STATE_ONLINE &&
946 dp->mii_state == MII_STATE_LINKUP &&
947 dp->tx_busy_cnt != 0 &&
948 now - dp->tx_start_time >= dp->ugc.usbgc_tx_timeout)) {
949 if (rwlock == RW_READER) {
951 * Upgrade dev_state_lock from shared mode
952 * to exclusive mode to restart nic
954 rwlock = RW_WRITER;
955 rw_exit(&dp->dev_state_lock);
956 goto again;
958 cmn_err(CE_WARN, "%s: %s: restarting the nic:"
959 " fatal_error:%ld nic_state:%d"
960 " mac_state:%d starttime:%ld",
961 dp->name, __func__,
962 dp->fatal_error ? now - dp->fatal_error: 0,
963 dp->nic_state, dp->mac_state,
964 dp->tx_busy_cnt ? now - dp->tx_start_time : 0);
966 (void) usbgem_restart_nic(dp);
969 rw_exit(&dp->dev_state_lock);
973 static int
974 usbgem_tx_watcher_start(struct usbgem_dev *dp)
976 int err;
977 kthread_t *wdth;
979 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
981 /* make a first call of uwgem_lw_link_check() */
982 dp->tx_watcher_stop = 0;
983 dp->tx_watcher_interval = drv_usectohz(1000*1000);
985 wdth = thread_create(NULL, 0, usbgem_tx_timeout, dp, 0, &p0,
986 TS_RUN, minclsyspri);
987 if (wdth == NULL) {
988 cmn_err(CE_WARN,
989 "!%s: %s: failed to create a tx_watcher thread",
990 dp->name, __func__);
991 return (USB_FAILURE);
993 dp->tx_watcher_did = wdth->t_did;
995 return (USB_SUCCESS);
998 static void
999 usbgem_tx_watcher_stop(struct usbgem_dev *dp)
1001 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1002 if (dp->tx_watcher_did) {
1003 /* Ensure timer routine stopped */
1004 dp->tx_watcher_stop = 1;
1005 cv_signal(&dp->tx_watcher_cv);
1006 thread_join(dp->tx_watcher_did);
1007 dp->tx_watcher_did = NULL;
1011 /* ================================================================== */
1013 * Callback handlers
1015 /* ================================================================== */
1016 static void
1017 usbgem_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1019 mblk_t *newmp;
1020 mblk_t *mp;
1021 mblk_t *tp;
1022 uint64_t len = 0;
1023 int pkts = 0;
1024 int bcast = 0;
1025 int mcast = 0;
1026 boolean_t busy;
1027 struct usbgem_dev *dp;
1029 dp = (struct usbgem_dev *)req->bulk_client_private;
1030 mp = req->bulk_data;
1031 req->bulk_data = NULL;
1033 DPRINTF(2, (CE_CONT, "!%s: %s: mp:%p, cr:%s(%d)",
1034 dp->name, __func__, mp,
1035 usb_str_cr(req->bulk_completion_reason),
1036 req->bulk_completion_reason));
1039 * we cannot acquire dev_state_lock because the routine
1040 * must be executed during usbgem_mac_stop() to avoid
1041 * dead lock.
1042 * we use a simle membar operation to get the state correctly.
1044 membar_consumer();
1046 if (req->bulk_completion_reason == USB_CR_OK &&
1047 dp->nic_state == NIC_STATE_ONLINE) {
1048 newmp = (*dp->ugc.usbgc_rx_make_packet)(dp, mp);
1050 if (newmp != mp) {
1051 /* the message has been reallocated, free old one */
1052 freemsg(mp);
1055 /* the message may includes one or more ethernet packets */
1056 for (tp = newmp; tp; tp = tp->b_next) {
1057 len += (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
1058 pkts++;
1059 if (tp->b_rptr[0] & 1) {
1060 if (bcmp(tp->b_rptr, &usbgem_bcastaddr,
1061 ETHERADDRL) == 0) {
1062 bcast++;
1063 } else {
1064 mcast++;
1069 /* send up if it is a valid packet */
1070 #ifdef USBGEM_CONFIG_GLDv3
1071 mac_rx(dp->mh, NULL, newmp);
1072 #else
1073 while (newmp) {
1074 tp = newmp;
1075 newmp = newmp->b_next;
1076 tp->b_next = NULL;
1077 gld_recv(dp->macinfo, tp);
1079 #endif
1080 } else {
1081 freemsg(mp);
1082 len = 0;
1085 mutex_enter(&dp->rxlock);
1086 /* update rx_active */
1087 if (dp->rx_active) {
1088 dp->rx_active = dp->mac_state == MAC_STATE_ONLINE;
1091 dp->stats.rbytes += len;
1092 dp->stats.rpackets += pkts;
1093 if (bcast | mcast) {
1094 dp->stats.rbcast += bcast;
1095 dp->stats.rmcast += mcast;
1097 mutex_exit(&dp->rxlock);
1099 if (dp->rx_active) {
1100 /* prepare to receive the next packets */
1101 if (usbgem_rx_start_unit(dp, req)) {
1102 /* we successed */
1103 goto done;
1105 cmn_err(CE_WARN,
1106 "!%s: %s: failed to fill next rx packet",
1107 dp->name, __func__);
1109 * we use another flag to indicate error state.
1110 * if we acquire dev_state_lock for RW_WRITER here,
1111 * usbgem_mac_stop() may hang.
1113 if (dp->fatal_error == (clock_t)0) {
1114 dp->fatal_error = usbgem_timestamp_nz();
1116 } else {
1117 /* no need to prepare the next packets */
1118 usb_free_bulk_req(req);
1121 mutex_enter(&dp->rxlock);
1122 dp->rx_active = B_FALSE;
1123 dp->rx_busy_cnt--;
1124 if (dp->rx_busy_cnt == 0) {
1125 /* wake up someone waits for me */
1126 cv_broadcast(&dp->rx_drain_cv);
1128 mutex_exit(&dp->rxlock);
1129 done:
1133 static void
1134 usbgem_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1136 boolean_t intr;
1137 boolean_t tx_sched;
1138 struct usbgem_dev *dp;
1140 dp = (struct usbgem_dev *)req->bulk_client_private;
1141 tx_sched = B_FALSE;
1143 DPRINTF(2, (CE_CONT,
1144 "!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
1145 dp->name, __func__,
1146 usb_str_cr(req->bulk_completion_reason),
1147 req->bulk_completion_reason,
1148 req->bulk_cb_flags,
1149 dp->tx_busy_cnt));
1151 /* we have finished to transfer the packet into tx fifo */
1152 intr = DB_TCI(req->bulk_data);
1153 freemsg(req->bulk_data);
1155 if (req->bulk_completion_reason != USB_CR_OK &&
1156 dp->fatal_error == (clock_t)0) {
1157 dp->fatal_error = usbgem_timestamp_nz();
1160 mutex_enter(&dp->txlock);
1162 if (intr) {
1163 ASSERT(dp->tx_intr_pended > 0);
1164 /* find the last interrupt we have scheduled */
1165 if (--(dp->tx_intr_pended) == 0) {
1166 tx_sched = B_TRUE;
1170 ASSERT(dp->tx_busy_cnt > 0);
1171 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
1172 dp->tx_free_list = req;
1173 dp->tx_busy_cnt--;
1175 #ifdef CONFIG_TX_LIMITER
1176 if (tx_sched) {
1177 dp->tx_max_packets =
1178 min(dp->tx_max_packets + 1, dp->ugc.usbgc_tx_list_max);
1180 #endif
1181 if (dp->mac_state != MAC_STATE_ONLINE && dp->tx_busy_cnt == 0) {
1182 cv_broadcast(&dp->tx_drain_cv);
1185 mutex_exit(&dp->txlock);
1187 if (tx_sched) {
1188 #ifdef USBGEM_CONFIG_GLDv3
1189 mac_tx_update(dp->mh);
1190 #else
1191 gld_sched(dp->macinfo);
1192 #endif
1196 static void
1197 usbgem_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1199 struct usbgem_dev *dp;
1201 dp = (struct usbgem_dev *)req->intr_client_private;
1202 dp->stats.intr++;
1204 if (req->intr_completion_reason == USB_CR_OK) {
1205 (*dp->ugc.usbgc_interrupt)(dp, req->intr_data);
1208 /* free the request and data */
1209 usb_free_intr_req(req);
1212 /* ======================================================================== */
1214 * MII support routines
1216 /* ======================================================================== */
1217 static void
1218 usbgem_choose_forcedmode(struct usbgem_dev *dp)
1220 /* choose media mode */
1221 if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
1222 dp->speed = USBGEM_SPD_1000;
1223 dp->full_duplex = dp->anadv_1000fdx;
1224 } else if (dp->anadv_100fdx || dp->anadv_100t4) {
1225 dp->speed = USBGEM_SPD_100;
1226 dp->full_duplex = B_TRUE;
1227 } else if (dp->anadv_100hdx) {
1228 dp->speed = USBGEM_SPD_100;
1229 dp->full_duplex = B_FALSE;
1230 } else {
1231 dp->speed = USBGEM_SPD_10;
1232 dp->full_duplex = dp->anadv_10fdx;
1236 static uint16_t
1237 usbgem_mii_read(struct usbgem_dev *dp, uint_t reg, int *errp)
1239 uint16_t val;
1241 sema_p(&dp->hal_op_lock);
1242 val = (*dp->ugc.usbgc_mii_read)(dp, reg, errp);
1243 sema_v(&dp->hal_op_lock);
1245 return (val);
1248 static void
1249 usbgem_mii_write(struct usbgem_dev *dp, uint_t reg, uint16_t val, int *errp)
1251 sema_p(&dp->hal_op_lock);
1252 (*dp->ugc.usbgc_mii_write)(dp, reg, val, errp);
1253 sema_v(&dp->hal_op_lock);
1256 static int
1257 usbgem_mii_probe(struct usbgem_dev *dp)
1259 int err;
1261 err = (*dp->ugc.usbgc_mii_probe)(dp);
1262 return (err);
1265 static int
1266 usbgem_mii_init(struct usbgem_dev *dp)
1268 int err;
1270 err = (*dp->ugc.usbgc_mii_init)(dp);
1271 return (err);
1274 #define fc_cap_decode(x) \
1275 ((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) | \
1276 (((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
1279 usbgem_mii_config_default(struct usbgem_dev *dp, int *errp)
1281 uint16_t mii_stat;
1282 uint16_t val;
1284 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1287 * Configure bits in advertisement register
1289 mii_stat = dp->mii_status;
1291 DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
1292 dp->name, __func__, mii_stat, MII_STATUS_BITS));
1294 if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
1295 /* it's funny */
1296 cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
1297 dp->name, mii_stat, MII_STATUS_BITS);
1298 return (USB_FAILURE);
1301 /* Do not change the rest of ability bits in advert reg */
1302 val = usbgem_mii_read(dp, MII_AN_ADVERT, errp) & ~MII_ABILITY_ALL;
1303 if (*errp != USB_SUCCESS) {
1304 goto usberr;
1307 DPRINTF(0, (CE_CONT,
1308 "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
1309 dp->name, __func__,
1310 dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
1311 dp->anadv_10fdx, dp->anadv_10hdx));
1313 /* set technology bits */
1314 if (dp->anadv_100t4) {
1315 val |= MII_ABILITY_100BASE_T4;
1317 if (dp->anadv_100fdx) {
1318 val |= MII_ABILITY_100BASE_TX_FD;
1320 if (dp->anadv_100hdx) {
1321 val |= MII_ABILITY_100BASE_TX;
1323 if (dp->anadv_10fdx) {
1324 val |= MII_ABILITY_10BASE_T_FD;
1326 if (dp->anadv_10hdx) {
1327 val |= MII_ABILITY_10BASE_T;
1330 /* set flow control capabilities */
1331 if (dp->anadv_pause) {
1332 val |= MII_ABILITY_PAUSE;
1334 if (dp->anadv_asmpause) {
1335 val |= MII_ABILITY_ASM_DIR;
1338 DPRINTF(0, (CE_CONT,
1339 "!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
1340 dp->name, __func__, val, MII_ABILITY_BITS,
1341 dp->anadv_pause, dp->anadv_asmpause));
1343 usbgem_mii_write(dp, MII_AN_ADVERT, val, errp);
1344 if (*errp != USB_SUCCESS) {
1345 goto usberr;
1348 if (dp->mii_status & MII_STATUS_XSTATUS) {
1350 * 1000Base-T GMII support
1352 if (!dp->anadv_autoneg) {
1353 /* enable manual configuration */
1354 val = MII_1000TC_CFG_EN;
1355 if (dp->anadv_1000t_ms == 2) {
1356 val |= MII_1000TC_CFG_VAL;
1358 } else {
1359 val = 0;
1360 if (dp->anadv_1000fdx) {
1361 val |= MII_1000TC_ADV_FULL;
1363 if (dp->anadv_1000hdx) {
1364 val |= MII_1000TC_ADV_HALF;
1366 switch (dp->anadv_1000t_ms) {
1367 case 1:
1368 /* slave */
1369 val |= MII_1000TC_CFG_EN;
1370 break;
1372 case 2:
1373 /* master */
1374 val |= MII_1000TC_CFG_EN | MII_1000TC_CFG_VAL;
1375 break;
1377 default:
1378 /* auto: do nothing */
1379 break;
1382 DPRINTF(0, (CE_CONT,
1383 "!%s: %s: setting MII_1000TC reg:%b",
1384 dp->name, __func__, val, MII_1000TC_BITS));
1386 usbgem_mii_write(dp, MII_1000TC, val, errp);
1387 if (*errp != USB_SUCCESS) {
1388 goto usberr;
1391 return (USB_SUCCESS);
1393 usberr:
1394 return (*errp);
1397 static char *usbgem_fc_type[] = {
1398 "without",
1399 "with symmetric",
1400 "with tx",
1401 "with rx",
1404 #ifdef USBGEM_CONFIG_GLDv3
1405 #define USBGEM_LINKUP(dp) mac_link_update((dp)->mh, LINK_STATE_UP)
1406 #define USBGEM_LINKDOWN(dp) mac_link_update((dp)->mh, LINK_STATE_DOWN)
1407 #else
1408 #define USBGEM_LINKUP(dp) \
1409 if (gld_linkstate) { \
1410 gld_linkstate((dp)->macinfo, GLD_LINKSTATE_UP); \
1412 #define USBGEM_LINKDOWN(dp) \
1413 if (gld_linkstate) { \
1414 gld_linkstate((dp)->macinfo, GLD_LINKSTATE_DOWN); \
1416 #endif
1418 static uint8_t usbgem_fc_result[4 /* my cap */][4 /* lp cap */] = {
1419 /* none symm tx rx/symm */
1420 /* none */
1421 {FLOW_CONTROL_NONE,
1422 FLOW_CONTROL_NONE,
1423 FLOW_CONTROL_NONE,
1424 FLOW_CONTROL_NONE},
1425 /* sym */
1426 {FLOW_CONTROL_NONE,
1427 FLOW_CONTROL_SYMMETRIC,
1428 FLOW_CONTROL_NONE,
1429 FLOW_CONTROL_SYMMETRIC},
1430 /* tx */
1431 {FLOW_CONTROL_NONE,
1432 FLOW_CONTROL_NONE,
1433 FLOW_CONTROL_NONE,
1434 FLOW_CONTROL_TX_PAUSE},
1435 /* rx/symm */
1436 {FLOW_CONTROL_NONE,
1437 FLOW_CONTROL_SYMMETRIC,
1438 FLOW_CONTROL_RX_PAUSE,
1439 FLOW_CONTROL_SYMMETRIC},
1442 static boolean_t
1443 usbgem_mii_link_check(struct usbgem_dev *dp, int *oldstatep, int *newstatep)
1445 boolean_t tx_sched = B_FALSE;
1446 uint16_t status;
1447 uint16_t advert;
1448 uint16_t lpable;
1449 uint16_t exp;
1450 uint16_t ctl1000;
1451 uint16_t stat1000;
1452 uint16_t val;
1453 clock_t now;
1454 clock_t diff;
1455 int linkdown_action;
1456 boolean_t fix_phy = B_FALSE;
1457 int err;
1458 uint_t rwlock;
1460 DPRINTF(4, (CE_CONT, "!%s: %s: time:%d state:%d",
1461 dp->name, __func__, ddi_get_lbolt(), dp->mii_state));
1463 if (dp->mii_state != MII_STATE_LINKUP) {
1464 rwlock = RW_WRITER;
1465 } else {
1466 rwlock = RW_READER;
1468 again:
1469 rw_enter(&dp->dev_state_lock, rwlock);
1471 /* save old mii state */
1472 *oldstatep = dp->mii_state;
1474 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
1475 /* stop periodic execution of the link watcher */
1476 dp->mii_interval = 0;
1477 tx_sched = B_FALSE;
1478 goto next;
1481 now = ddi_get_lbolt();
1482 diff = now - dp->mii_last_check;
1483 dp->mii_last_check = now;
1486 * For NWAM, don't show linkdown state right
1487 * when the device is attached.
1489 if (dp->linkup_delay > 0) {
1490 if (dp->linkup_delay > diff) {
1491 dp->linkup_delay -= diff;
1492 } else {
1493 /* link up timeout */
1494 dp->linkup_delay = -1;
1498 next_nowait:
1499 switch (dp->mii_state) {
1500 case MII_STATE_UNKNOWN:
1501 goto reset_phy;
1503 case MII_STATE_RESETTING:
1504 dp->mii_timer -= diff;
1505 if (dp->mii_timer > 0) {
1506 /* don't read phy registers in resetting */
1507 dp->mii_interval = WATCH_INTERVAL_FAST;
1508 goto next;
1511 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1512 if (err != USB_SUCCESS) {
1513 goto usberr;
1515 if (val & MII_CONTROL_RESET) {
1516 cmn_err(CE_NOTE,
1517 "!%s: time:%ld resetting phy not complete."
1518 " mii_control:0x%b",
1519 dp->name, ddi_get_lbolt(),
1520 val, MII_CONTROL_BITS);
1523 /* ensure neither isolated nor pwrdown nor auto-nego mode */
1524 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1525 if (err != USB_SUCCESS) {
1526 goto usberr;
1528 #if USBGEM_DEBUG_LEVEL > 10
1529 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1530 cmn_err(CE_CONT, "!%s: readback control %b",
1531 dp->name, val, MII_CONTROL_BITS);
1532 #endif
1533 /* As resetting PHY has completed, configure PHY registers */
1534 if ((*dp->ugc.usbgc_mii_config)(dp, &err) != USB_SUCCESS) {
1535 /* we failed to configure PHY */
1536 goto usberr;
1539 /* prepare for forced mode */
1540 usbgem_choose_forcedmode(dp);
1542 dp->mii_lpable = 0;
1543 dp->mii_advert = 0;
1544 dp->mii_exp = 0;
1545 dp->mii_ctl1000 = 0;
1546 dp->mii_stat1000 = 0;
1548 dp->flow_control = FLOW_CONTROL_NONE;
1550 if (!dp->anadv_autoneg) {
1551 /* skip auto-negotiation phase */
1552 dp->mii_state = MII_STATE_MEDIA_SETUP;
1553 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1554 goto next_nowait;
1557 /* issue an auto-negotiation command */
1558 goto autonego;
1560 case MII_STATE_AUTONEGOTIATING:
1562 * Autonegotiation in progress
1564 dp->mii_timer -= diff;
1565 if (dp->mii_timer -
1566 (dp->ugc.usbgc_mii_an_timeout - dp->ugc.usbgc_mii_an_wait)
1567 > 0) {
1568 /* wait for minimum time (2.3 - 2.5 sec) */
1569 dp->mii_interval = WATCH_INTERVAL_FAST;
1570 goto next;
1573 /* read PHY status */
1574 status = usbgem_mii_read(dp, MII_STATUS, &err);
1575 if (err != USB_SUCCESS) {
1576 goto usberr;
1578 DPRINTF(4, (CE_CONT,
1579 "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
1580 dp->name, __func__, dp->mii_state,
1581 status, MII_STATUS_BITS));
1583 if (status & MII_STATUS_REMFAULT) {
1585 * The link parnert told me something wrong happend.
1586 * What do we do ?
1588 cmn_err(CE_CONT,
1589 "!%s: auto-negotiation failed: remote fault",
1590 dp->name);
1591 goto autonego;
1594 if ((status & MII_STATUS_ANDONE) == 0) {
1595 if (dp->mii_timer <= 0) {
1597 * Auto-negotiation has been timed out,
1598 * Reset PHY and try again.
1600 if (!dp->mii_supress_msg) {
1601 cmn_err(CE_WARN,
1602 "!%s: auto-negotiation failed:"
1603 " timeout",
1604 dp->name);
1605 dp->mii_supress_msg = B_TRUE;
1607 goto autonego;
1610 * Auto-negotiation is in progress. Wait for a while.
1612 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1613 goto next;
1617 * Auto-negotiation has been completed. Let's go to AN_DONE.
1619 dp->mii_state = MII_STATE_AN_DONE;
1620 dp->mii_supress_msg = B_FALSE;
1621 DPRINTF(0, (CE_CONT,
1622 "!%s: auto-negotiation completed, MII_STATUS:%b",
1623 dp->name, status, MII_STATUS_BITS));
1625 if (dp->ugc.usbgc_mii_an_delay > 0) {
1626 dp->mii_timer = dp->ugc.usbgc_mii_an_delay;
1627 dp->mii_interval = drv_usectohz(20*1000);
1628 goto next;
1631 dp->mii_timer = 0;
1632 diff = 0;
1633 goto next_nowait;
1635 case MII_STATE_AN_DONE:
1637 * Auto-negotiation has done. Now we can set up media.
1639 dp->mii_timer -= diff;
1640 if (dp->mii_timer > 0) {
1641 /* wait for a while */
1642 dp->mii_interval = WATCH_INTERVAL_FAST;
1643 goto next;
1647 * Setup speed and duplex mode according with
1648 * the result of auto negotiation.
1652 * Read registers required to determin current
1653 * duplex mode and media speed.
1655 if (dp->ugc.usbgc_mii_an_delay > 0) {
1656 /* the 'status' variable is not initialized yet */
1657 status = usbgem_mii_read(dp, MII_STATUS, &err);
1658 if (err != USB_SUCCESS) {
1659 goto usberr;
1662 advert = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
1663 if (err != USB_SUCCESS) {
1664 goto usberr;
1666 lpable = usbgem_mii_read(dp, MII_AN_LPABLE, &err);
1667 if (err != USB_SUCCESS) {
1668 goto usberr;
1670 exp = usbgem_mii_read(dp, MII_AN_EXPANSION, &err);
1671 if (err != USB_SUCCESS) {
1672 goto usberr;
1674 if (exp == 0xffff) {
1675 /* some phys don't have exp register */
1676 exp = 0;
1679 ctl1000 = 0;
1680 stat1000 = 0;
1681 if (dp->mii_status & MII_STATUS_XSTATUS) {
1682 ctl1000 = usbgem_mii_read(dp, MII_1000TC, &err);
1683 if (err != USB_SUCCESS) {
1684 goto usberr;
1686 stat1000 = usbgem_mii_read(dp, MII_1000TS, &err);
1687 if (err != USB_SUCCESS) {
1688 goto usberr;
1691 dp->mii_lpable = lpable;
1692 dp->mii_advert = advert;
1693 dp->mii_exp = exp;
1694 dp->mii_ctl1000 = ctl1000;
1695 dp->mii_stat1000 = stat1000;
1697 cmn_err(CE_CONT,
1698 "!%s: auto-negotiation done: "
1699 "status:%b, advert:%b, lpable:%b, exp:%b",
1700 dp->name,
1701 status, MII_STATUS_BITS,
1702 advert, MII_ABILITY_BITS,
1703 lpable, MII_ABILITY_BITS,
1704 exp, MII_AN_EXP_BITS);
1706 DPRINTF(0, (CE_CONT, "!%s: MII_STATUS:%b",
1707 dp->name, status, MII_STATUS_BITS));
1709 if (dp->mii_status & MII_STATUS_XSTATUS) {
1710 cmn_err(CE_CONT,
1711 "! MII_1000TC reg:%b, MII_1000TS reg:%b",
1712 ctl1000, MII_1000TC_BITS,
1713 stat1000, MII_1000TS_BITS);
1716 if (usbgem_population(lpable) <= 1 &&
1717 (exp & MII_AN_EXP_LPCANAN) == 0) {
1718 if ((advert & MII_ABILITY_TECH) != lpable) {
1719 cmn_err(CE_WARN,
1720 "!%s: but the link partner doesn't seem"
1721 " to have auto-negotiation capability."
1722 " please check the link configuration.",
1723 dp->name);
1726 * it should be a result of pararell detection,
1727 * which cannot detect duplex mode.
1729 if ((advert & lpable) == 0 &&
1730 lpable & MII_ABILITY_10BASE_T) {
1731 /* no common technology, try 10M half mode */
1732 lpable |= advert & MII_ABILITY_10BASE_T;
1733 fix_phy = B_TRUE;
1735 } else if (lpable == 0) {
1736 cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
1737 goto reset_phy;
1740 * configure current link mode according to AN priority.
1742 val = advert & lpable;
1743 if ((ctl1000 & MII_1000TC_ADV_FULL) &&
1744 (stat1000 & MII_1000TS_LP_FULL)) {
1745 /* 1000BaseT & full duplex */
1746 dp->speed = USBGEM_SPD_1000;
1747 dp->full_duplex = B_TRUE;
1748 } else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
1749 (stat1000 & MII_1000TS_LP_HALF)) {
1750 /* 1000BaseT & half duplex */
1751 dp->speed = USBGEM_SPD_1000;
1752 dp->full_duplex = B_FALSE;
1753 } else if ((val & MII_ABILITY_100BASE_TX_FD)) {
1754 /* 100BaseTx & fullduplex */
1755 dp->speed = USBGEM_SPD_100;
1756 dp->full_duplex = B_TRUE;
1757 } else if ((val & MII_ABILITY_100BASE_T4)) {
1758 /* 100BaseTx & fullduplex */
1759 dp->speed = USBGEM_SPD_100;
1760 dp->full_duplex = B_TRUE;
1761 } else if ((val & MII_ABILITY_100BASE_TX)) {
1762 /* 100BaseTx & half duplex */
1763 dp->speed = USBGEM_SPD_100;
1764 dp->full_duplex = B_FALSE;
1765 } else if ((val & MII_ABILITY_10BASE_T_FD)) {
1766 /* 10BaseT & full duplex */
1767 dp->speed = USBGEM_SPD_10;
1768 dp->full_duplex = B_TRUE;
1769 } else if ((val & MII_ABILITY_10BASE_T)) {
1770 /* 10BaseT & half duplex */
1771 dp->speed = USBGEM_SPD_10;
1772 dp->full_duplex = B_FALSE;
1773 } else {
1775 * the link partner doesn't seem to have
1776 * auto-negotiation capability and our PHY
1777 * could not report current mode correctly.
1778 * We guess current mode by mii_control register.
1780 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1781 if (err != USB_SUCCESS) {
1782 goto usberr;
1785 /* select 100m half or 10m half */
1786 dp->speed = (val & MII_CONTROL_100MB) ?
1787 USBGEM_SPD_100 : USBGEM_SPD_10;
1788 dp->full_duplex = B_FALSE;
1789 fix_phy = B_TRUE;
1791 cmn_err(CE_NOTE,
1792 "!%s: auto-negotiation done but "
1793 "common ability not found.\n"
1794 "PHY state: control:%b advert:%b lpable:%b\n"
1795 "guessing %d Mbps %s duplex mode",
1796 dp->name,
1797 val, MII_CONTROL_BITS,
1798 advert, MII_ABILITY_BITS,
1799 lpable, MII_ABILITY_BITS,
1800 usbgem_speed_value[dp->speed],
1801 dp->full_duplex ? "full" : "half");
1804 if (dp->full_duplex) {
1805 dp->flow_control =
1806 usbgem_fc_result[fc_cap_decode(advert)]
1807 [fc_cap_decode(lpable)];
1808 } else {
1809 dp->flow_control = FLOW_CONTROL_NONE;
1811 dp->mii_state = MII_STATE_MEDIA_SETUP;
1812 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1813 goto next_nowait;
1815 case MII_STATE_MEDIA_SETUP:
1816 DPRINTF(2, (CE_CONT, "!%s: setup midia mode", dp->name));
1818 /* assume the link state is down */
1819 dp->mii_state = MII_STATE_LINKDOWN;
1820 dp->mii_supress_msg = B_FALSE;
1822 /* use short interval */
1823 dp->mii_interval = WATCH_INTERVAL_FAST;
1825 if ((!dp->anadv_autoneg) ||
1826 dp->ugc.usbgc_mii_an_oneshot || fix_phy) {
1829 * write the result of auto negotiation back.
1831 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1832 if (err != USB_SUCCESS) {
1833 goto usberr;
1835 val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
1836 MII_CONTROL_ANE | MII_CONTROL_RSAN);
1838 if (dp->full_duplex) {
1839 val |= MII_CONTROL_FDUPLEX;
1842 switch (dp->speed) {
1843 case USBGEM_SPD_1000:
1844 val |= MII_CONTROL_1000MB;
1845 break;
1847 case USBGEM_SPD_100:
1848 val |= MII_CONTROL_100MB;
1849 break;
1851 default:
1852 cmn_err(CE_WARN, "%s: unknown speed:%d",
1853 dp->name, dp->speed);
1854 /* FALLTHROUGH */
1856 case USBGEM_SPD_10:
1857 /* for USBGEM_SPD_10, do nothing */
1858 break;
1861 if (dp->mii_status & MII_STATUS_XSTATUS) {
1862 usbgem_mii_write(dp,
1863 MII_1000TC, MII_1000TC_CFG_EN, &err);
1864 if (err != USB_SUCCESS) {
1865 goto usberr;
1868 usbgem_mii_write(dp, MII_CONTROL, val, &err);
1869 if (err != USB_SUCCESS) {
1870 goto usberr;
1874 * XXX -- nic state should be one of
1875 * NIC_STATE_DISCONNECTED
1876 * NIC_STATE_STOPPED
1877 * NIC_STATE_INITIALIZED
1878 * NIC_STATE_ONLINE
1880 if (dp->nic_state >= NIC_STATE_INITIALIZED) {
1881 /* notify the result of autonegotiation to mac */
1882 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
1883 goto usberr;
1886 goto next_nowait;
1888 case MII_STATE_LINKDOWN:
1889 status = usbgem_mii_read(dp, MII_STATUS, &err);
1890 if (err != USB_SUCCESS) {
1891 goto usberr;
1893 if (status & MII_STATUS_LINKUP) {
1895 * Link is going up
1897 dp->mii_state = MII_STATE_LINKUP;
1898 dp->mii_supress_msg = B_FALSE;
1900 DPRINTF(0, (CE_CONT,
1901 "!%s: link up detected: status:%b",
1902 dp->name, status, MII_STATUS_BITS));
1905 * MII_CONTROL_100MB and MII_CONTROL_FDUPLEX are
1906 * ignored when MII_CONTROL_ANE is set.
1908 cmn_err(CE_CONT,
1909 "!%s: Link up: %d Mbps %s duplex %s flow control",
1910 dp->name,
1911 usbgem_speed_value[dp->speed],
1912 dp->full_duplex ? "full" : "half",
1913 usbgem_fc_type[dp->flow_control]);
1915 dp->mii_interval =
1916 dp->ugc.usbgc_mii_link_watch_interval;
1918 if (dp->ugc.usbgc_mii_hw_link_detection &&
1919 dp->nic_state == NIC_STATE_ONLINE) {
1920 dp->mii_interval = 0;
1923 if (dp->nic_state == NIC_STATE_ONLINE) {
1924 if (dp->mac_state == MAC_STATE_INITIALIZED) {
1925 (void) usbgem_mac_start(dp);
1927 tx_sched = B_TRUE;
1930 goto next;
1933 dp->mii_supress_msg = B_TRUE;
1934 if (dp->anadv_autoneg) {
1935 dp->mii_timer -= diff;
1936 if (dp->mii_timer <= 0) {
1938 * the link down timer expired.
1939 * need to restart auto-negotiation.
1941 linkdown_action =
1942 dp->ugc.usbgc_mii_linkdown_timeout_action;
1943 goto restart_autonego;
1946 /* don't change mii_state */
1947 goto next;
1949 case MII_STATE_LINKUP:
1950 if (rwlock == RW_READER) {
1951 /* first pass, read mii status */
1952 status = usbgem_mii_read(dp, MII_STATUS, &err);
1953 if (err != USB_SUCCESS) {
1954 goto usberr;
1957 if ((status & MII_STATUS_LINKUP) == 0) {
1959 * Link is going down
1961 cmn_err(CE_NOTE,
1962 "!%s: link down detected: status:%b",
1963 dp->name, status, MII_STATUS_BITS);
1965 * Acquire exclusive lock to change mii_state
1967 if (rwlock == RW_READER) {
1968 rwlock = RW_WRITER;
1969 rw_exit(&dp->dev_state_lock);
1970 goto again;
1973 dp->mii_state = MII_STATE_LINKDOWN;
1974 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1977 * As we may change the state of the device,
1978 * let us acquire exclusive lock for the state.
1980 if (dp->nic_state == NIC_STATE_ONLINE &&
1981 dp->mac_state == MAC_STATE_ONLINE &&
1982 dp->ugc.usbgc_mii_stop_mac_on_linkdown) {
1983 (void) usbgem_restart_nic(dp);
1984 /* drain tx */
1985 tx_sched = B_TRUE;
1988 if (dp->anadv_autoneg) {
1989 /* need to restart auto-negotiation */
1990 linkdown_action =
1991 dp->ugc.usbgc_mii_linkdown_action;
1992 goto restart_autonego;
1995 * don't use hw link down detection until the link
1996 * status become stable for a while.
1998 dp->mii_interval =
1999 dp->ugc.usbgc_mii_link_watch_interval;
2001 goto next;
2005 * still link up, no need to change mii_state
2007 if (dp->ugc.usbgc_mii_hw_link_detection &&
2008 dp->nic_state == NIC_STATE_ONLINE) {
2010 * no need to check link status periodicly
2011 * if nic can generate interrupts when link go down.
2013 dp->mii_interval = 0;
2015 goto next;
2017 /* NOTREACHED */
2018 cmn_err(CE_PANIC, "!%s: %s: not reached", dp->name, __func__);
2021 * Actions for new state.
2023 restart_autonego:
2024 switch (linkdown_action) {
2025 case MII_ACTION_RESET:
2026 if (!dp->mii_supress_msg) {
2027 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2029 dp->mii_supress_msg = B_TRUE;
2030 goto reset_phy;
2032 case MII_ACTION_NONE:
2033 dp->mii_supress_msg = B_TRUE;
2034 if (dp->ugc.usbgc_mii_an_oneshot) {
2035 goto autonego;
2037 /* PHY will restart autonego automatically */
2038 dp->mii_state = MII_STATE_AUTONEGOTIATING;
2039 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2040 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2041 goto next;
2043 case MII_ACTION_RSA:
2044 if (!dp->mii_supress_msg) {
2045 cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
2046 dp->name);
2048 dp->mii_supress_msg = B_TRUE;
2049 goto autonego;
2051 default:
2052 cmn_err(CE_PANIC, "!%s: unknowm linkdown action: %d",
2053 dp->name, dp->ugc.usbgc_mii_linkdown_action);
2054 dp->mii_supress_msg = B_TRUE;
2056 /* NOTREACHED */
2058 reset_phy:
2059 if (!dp->mii_supress_msg) {
2060 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2062 dp->mii_state = MII_STATE_RESETTING;
2063 dp->mii_timer = dp->ugc.usbgc_mii_reset_timeout;
2064 if (!dp->ugc.usbgc_mii_dont_reset) {
2065 usbgem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET, &err);
2066 if (err != USB_SUCCESS) {
2067 goto usberr;
2070 dp->mii_interval = WATCH_INTERVAL_FAST;
2071 goto next;
2073 autonego:
2074 if (!dp->mii_supress_msg) {
2075 cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
2077 dp->mii_state = MII_STATE_AUTONEGOTIATING;
2078 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2080 /* start/restart autoneg */
2081 val = usbgem_mii_read(dp, MII_CONTROL, &err) &
2082 ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
2083 if (err != USB_SUCCESS) {
2084 goto usberr;
2086 if (val & MII_CONTROL_ANE) {
2087 val |= MII_CONTROL_RSAN;
2089 usbgem_mii_write(dp, MII_CONTROL,
2090 val | dp->ugc.usbgc_mii_an_cmd | MII_CONTROL_ANE, &err);
2091 if (err != USB_SUCCESS) {
2092 goto usberr;
2095 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2096 goto next;
2098 usberr:
2099 dp->mii_state = MII_STATE_UNKNOWN;
2100 dp->mii_interval = dp->ugc.usbgc_mii_link_watch_interval;
2101 tx_sched = B_TRUE;
2103 next:
2104 *newstatep = dp->mii_state;
2105 rw_exit(&dp->dev_state_lock);
2106 return (tx_sched);
2109 static void
2110 usbgem_mii_link_watcher(struct usbgem_dev *dp)
2112 int old_mii_state;
2113 int new_mii_state;
2114 boolean_t tx_sched;
2116 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2118 for (; ; ) {
2120 mutex_enter(&dp->link_watcher_lock);
2121 if (dp->mii_interval) {
2122 (void) cv_timedwait(&dp->link_watcher_wait_cv,
2123 &dp->link_watcher_lock,
2124 dp->mii_interval + ddi_get_lbolt());
2125 } else {
2126 cv_wait(&dp->link_watcher_wait_cv,
2127 &dp->link_watcher_lock);
2129 mutex_exit(&dp->link_watcher_lock);
2131 if (dp->link_watcher_stop) {
2132 break;
2135 /* we block callbacks from disconnect/suspend and restart */
2136 tx_sched = usbgem_mii_link_check(dp,
2137 &old_mii_state, &new_mii_state);
2140 * gld v2 notifier functions are not able to
2141 * be called with any locks in this layer.
2143 if (tx_sched) {
2144 /* kick potentially stopped downstream */
2145 #ifdef USBGEM_CONFIG_GLDv3
2146 mac_tx_update(dp->mh);
2147 #else
2148 gld_sched(dp->macinfo);
2149 #endif
2152 if (old_mii_state != new_mii_state) {
2153 /* notify new mii link state */
2154 if (new_mii_state == MII_STATE_LINKUP) {
2155 dp->linkup_delay = 0;
2156 USBGEM_LINKUP(dp);
2157 } else if (dp->linkup_delay <= 0) {
2158 USBGEM_LINKDOWN(dp);
2160 } else if (dp->linkup_delay < 0) {
2161 /* first linkup timeout */
2162 dp->linkup_delay = 0;
2163 USBGEM_LINKDOWN(dp);
2167 thread_exit();
2170 void
2171 usbgem_mii_update_link(struct usbgem_dev *dp)
2173 cv_signal(&dp->link_watcher_wait_cv);
2177 usbgem_mii_probe_default(struct usbgem_dev *dp)
2179 int phy;
2180 uint16_t status;
2181 uint16_t xstatus;
2182 int err;
2183 uint16_t adv;
2184 uint16_t adv_org;
2186 DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2189 * Scan PHY
2191 dp->mii_status = 0;
2193 /* Try default phy first */
2194 if (dp->mii_phy_addr) {
2195 status = usbgem_mii_read(dp, MII_STATUS, &err);
2196 if (err != USB_SUCCESS) {
2197 goto usberr;
2199 if (status != 0xffff && status != 0x0000) {
2200 goto PHY_found;
2203 if (dp->mii_phy_addr < 0) {
2204 cmn_err(CE_NOTE,
2205 "!%s: failed to probe default internal and/or non-MII PHY",
2206 dp->name);
2207 return (USB_FAILURE);
2210 cmn_err(CE_NOTE,
2211 "!%s: failed to probe default MII PHY at %d",
2212 dp->name, dp->mii_phy_addr);
2215 /* Try all possible address */
2216 for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2217 dp->mii_phy_addr = phy;
2218 status = usbgem_mii_read(dp, MII_STATUS, &err);
2219 if (err != USB_SUCCESS) {
2220 DPRINTF(0, (CE_CONT,
2221 "!%s: %s: mii_read(status) failed",
2222 dp->name, __func__));
2223 goto usberr;
2226 if (status != 0xffff && status != 0x0000) {
2227 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2228 if (err != USB_SUCCESS) {
2229 DPRINTF(0, (CE_CONT,
2230 "!%s: %s: mii_write(control) failed",
2231 dp->name, __func__));
2232 goto usberr;
2234 goto PHY_found;
2237 for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2238 dp->mii_phy_addr = phy;
2239 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2240 if (err != USB_SUCCESS) {
2241 DPRINTF(0, (CE_CONT,
2242 "!%s: %s: mii_write(control) failed",
2243 dp->name, __func__));
2244 goto usberr;
2246 status = usbgem_mii_read(dp, MII_STATUS, &err);
2247 if (err != USB_SUCCESS) {
2248 DPRINTF(0, (CE_CONT,
2249 "!%s: %s: mii_read(status) failed",
2250 dp->name, __func__));
2251 goto usberr;
2254 if (status != 0xffff && status != 0) {
2255 goto PHY_found;
2259 cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
2260 return (USB_FAILURE);
2262 PHY_found:
2263 dp->mii_status = status;
2264 dp->mii_status_ro = ~status;
2265 dp->mii_phy_id = usbgem_mii_read(dp, MII_PHYIDH, &err) << 16;
2266 if (err != USB_SUCCESS) {
2267 DPRINTF(0, (CE_CONT,
2268 "!%s: %s: mii_read(PHYIDH) failed",
2269 dp->name, __func__));
2270 goto usberr;
2272 dp->mii_phy_id |= usbgem_mii_read(dp, MII_PHYIDL, &err);
2273 if (err != USB_SUCCESS) {
2274 DPRINTF(0, (CE_CONT,
2275 "!%s: %s: mii_read(PHYIDL) failed",
2276 dp->name, __func__));
2277 goto usberr;
2280 if (dp->mii_phy_addr < 0) {
2281 cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
2282 dp->name, dp->mii_phy_id);
2283 } else {
2284 cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
2285 dp->name, dp->mii_phy_id, dp->mii_phy_addr);
2288 cmn_err(CE_CONT,
2289 "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
2290 dp->name,
2291 usbgem_mii_read(dp, MII_CONTROL, &err), MII_CONTROL_BITS,
2292 status, MII_STATUS_BITS,
2293 usbgem_mii_read(dp, MII_AN_ADVERT, &err), MII_ABILITY_BITS,
2294 usbgem_mii_read(dp, MII_AN_LPABLE, &err), MII_ABILITY_BITS,
2295 usbgem_mii_read(dp, MII_AN_EXPANSION, &err), MII_AN_EXP_BITS);
2297 dp->mii_xstatus = 0;
2298 if (status & MII_STATUS_XSTATUS) {
2299 dp->mii_xstatus = usbgem_mii_read(dp, MII_XSTATUS, &err);
2301 cmn_err(CE_CONT, "!%s: xstatus:%b",
2302 dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
2304 dp->mii_xstatus_ro = ~dp->mii_xstatus;
2306 /* check if the phy can advertize pause abilities */
2307 adv_org = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2308 if (err != USB_SUCCESS) {
2309 goto usberr;
2312 usbgem_mii_write(dp, MII_AN_ADVERT,
2313 MII_ABILITY_PAUSE | MII_ABILITY_ASM_DIR, &err);
2314 if (err != USB_SUCCESS) {
2315 goto usberr;
2318 adv = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2319 if (err != USB_SUCCESS) {
2320 goto usberr;
2323 if ((adv & MII_ABILITY_PAUSE) == 0) {
2324 dp->ugc.usbgc_flow_control &= ~1;
2327 if ((adv & MII_ABILITY_ASM_DIR) == 0) {
2328 dp->ugc.usbgc_flow_control &= ~2;
2331 usbgem_mii_write(dp, MII_AN_ADVERT, adv_org, &err);
2332 if (err != USB_SUCCESS) {
2333 goto usberr;
2335 return (USB_SUCCESS);
2337 usberr:
2338 return (USB_FAILURE);
2342 usbgem_mii_init_default(struct usbgem_dev *dp)
2344 /* ENPTY */
2345 return (USB_SUCCESS);
2348 static int
2349 usbgem_mii_start(struct usbgem_dev *dp)
2351 int err;
2352 kthread_t *lwth;
2354 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2356 /* make a first call of usbgem_mii_link_check() */
2357 dp->link_watcher_stop = 0;
2358 dp->mii_state = MII_STATE_UNKNOWN;
2359 dp->mii_interval = drv_usectohz(1000*1000); /* 1sec */
2360 dp->mii_last_check = ddi_get_lbolt();
2361 dp->linkup_delay = 600 * drv_usectohz(1000*1000); /* 10 minutes */
2363 lwth = thread_create(NULL, 0, usbgem_mii_link_watcher, dp, 0, &p0,
2364 TS_RUN, minclsyspri);
2365 if (lwth == NULL) {
2366 cmn_err(CE_WARN,
2367 "!%s: %s: failed to create a link watcher thread",
2368 dp->name, __func__);
2369 return (USB_FAILURE);
2371 dp->link_watcher_did = lwth->t_did;
2373 return (USB_SUCCESS);
2376 static void
2377 usbgem_mii_stop(struct usbgem_dev *dp)
2379 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2381 /* Ensure timer routine stopped */
2382 dp->link_watcher_stop = 1;
2383 cv_signal(&dp->link_watcher_wait_cv);
2384 thread_join(dp->link_watcher_did);
2387 /* ============================================================== */
2389 * internal mac register operation interface
2391 /* ============================================================== */
2393 * usbgem_mac_init: cold start
2395 static int
2396 usbgem_mac_init(struct usbgem_dev *dp)
2398 int err;
2400 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2402 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2403 /* pretend we succeeded */
2404 return (USB_SUCCESS);
2407 ASSERT(dp->mac_state == MAC_STATE_STOPPED);
2409 /* reset fatal error timestamp */
2410 dp->fatal_error = (clock_t)0;
2412 /* reset tx side state */
2413 mutex_enter(&dp->txlock);
2414 dp->tx_busy_cnt = 0;
2415 dp->tx_max_packets = dp->ugc.usbgc_tx_list_max;
2416 mutex_exit(&dp->txlock);
2418 /* reset rx side state */
2419 mutex_enter(&dp->rxlock);
2420 dp->rx_busy_cnt = 0;
2421 mutex_exit(&dp->rxlock);
2423 err = usbgem_hal_init_chip(dp);
2424 if (err == USB_SUCCESS) {
2425 dp->mac_state = MAC_STATE_INITIALIZED;
2428 return (err);
2432 * usbgem_mac_start: warm start
2434 static int
2435 usbgem_mac_start(struct usbgem_dev *dp)
2437 int err;
2438 int i;
2439 usb_flags_t flags = 0;
2440 usb_intr_req_t *req;
2441 #ifdef USBGEM_DEBUG_LEVEL
2442 usb_pipe_state_t p_state;
2443 #endif
2444 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2446 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2447 /* do nothing but don't return failure */
2448 return (USB_SUCCESS);
2451 if (dp->mac_state != MAC_STATE_INITIALIZED) {
2452 /* don't return failer */
2453 DPRINTF(0, (CE_CONT,
2454 "!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
2455 dp->name, __func__, dp->mac_state));
2456 goto x;
2459 dp->mac_state = MAC_STATE_ONLINE;
2461 if (usbgem_hal_start_chip(dp) != USB_SUCCESS) {
2462 cmn_err(CE_NOTE,
2463 "!%s: %s: usb error was detected during start_chip",
2464 dp->name, __func__);
2465 goto x;
2468 #ifdef USBGEM_DEBUG_LEVEL
2469 usb_pipe_get_state(dp->intr_pipe, &p_state, 0);
2470 ASSERT(p_state == USB_PIPE_STATE_IDLE);
2471 #endif /* USBGEM_DEBUG_LEVEL */
2473 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2475 /* make a request for interrupt */
2477 req = usb_alloc_intr_req(dp->dip, 0, USB_FLAGS_SLEEP);
2478 if (req == NULL) {
2479 cmn_err(CE_WARN, "!%s: %s: failed to allocate intreq",
2480 dp->name, __func__);
2481 goto x;
2483 req->intr_data = NULL;
2484 req->intr_client_private = (usb_opaque_t)dp;
2485 req->intr_timeout = 0;
2486 req->intr_attributes =
2487 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
2488 req->intr_len = dp->ep_intr->wMaxPacketSize;
2489 req->intr_cb = usbgem_intr_cb;
2490 req->intr_exc_cb = usbgem_intr_cb;
2491 req->intr_completion_reason = 0;
2492 req->intr_cb_flags = 0;
2494 err = usb_pipe_intr_xfer(dp->intr_pipe, req, flags);
2495 if (err != USB_SUCCESS) {
2496 cmn_err(CE_WARN,
2497 "%s: err:%d failed to start polling of intr pipe",
2498 dp->name, err);
2499 goto x;
2503 /* kick to receive the first packet */
2504 if (usbgem_init_rx_buf(dp) != USB_SUCCESS) {
2505 goto err_stop_intr;
2507 dp->rx_active = B_TRUE;
2509 return (USB_SUCCESS);
2511 err_stop_intr:
2512 /* stop the interrupt pipe */
2513 DPRINTF(0, (CE_CONT, "!%s: %s: FAULURE", dp->name, __func__));
2514 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2515 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2518 ASSERT(dp->mac_state == MAC_STATE_ONLINE);
2519 /* we use another flag to indicate error state. */
2520 if (dp->fatal_error == (clock_t)0) {
2521 dp->fatal_error = usbgem_timestamp_nz();
2523 return (USB_FAILURE);
2526 static int
2527 usbgem_mac_stop(struct usbgem_dev *dp, int new_state, boolean_t graceful)
2529 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2532 * we must have writer lock for dev_state_lock
2534 ASSERT(new_state == MAC_STATE_STOPPED ||
2535 new_state == MAC_STATE_DISCONNECTED);
2537 /* stop polling interrupt pipe */
2538 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2539 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2542 if (new_state == MAC_STATE_STOPPED || graceful) {
2543 /* stop the nic hardware completely */
2544 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
2545 (void) usbgem_hal_reset_chip(dp);
2549 /* stop preparing new rx packets and sending new packets */
2550 dp->mac_state = new_state;
2552 /* other processors must get mac_state correctly after here */
2553 membar_producer();
2555 /* cancel all requests we have sent */
2556 usb_pipe_reset(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
2557 usb_pipe_reset(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
2559 DPRINTF(0, (CE_CONT,
2560 "!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
2561 dp->name, __func__, dp->rx_busy_cnt, dp->tx_busy_cnt));
2564 * Here all rx packets has been cancelled and their call back
2565 * function has been exeuted, because we called usb_pipe_reset
2566 * synchronously.
2567 * So actually we just ensure rx_busy_cnt == 0.
2569 mutex_enter(&dp->rxlock);
2570 while (dp->rx_busy_cnt > 0) {
2571 cv_wait(&dp->rx_drain_cv, &dp->rxlock);
2573 mutex_exit(&dp->rxlock);
2575 DPRINTF(0, (CE_CONT, "!%s: %s: rx_busy_cnt is %d now",
2576 dp->name, __func__, dp->rx_busy_cnt));
2578 mutex_enter(&dp->txlock);
2579 while (dp->tx_busy_cnt > 0) {
2580 cv_wait(&dp->tx_drain_cv, &dp->txlock);
2582 mutex_exit(&dp->txlock);
2584 DPRINTF(0, (CE_CONT, "!%s: %s: tx_busy_cnt is %d now",
2585 dp->name, __func__, dp->tx_busy_cnt));
2587 return (USB_SUCCESS);
2590 static int
2591 usbgem_add_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2593 int cnt;
2594 int err;
2596 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2598 sema_p(&dp->rxfilter_lock);
2599 if (dp->mc_count_req++ < USBGEM_MAXMC) {
2600 /* append the new address at the end of the mclist */
2601 cnt = dp->mc_count;
2602 bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
2603 ETHERADDRL);
2604 if (dp->ugc.usbgc_multicast_hash) {
2605 dp->mc_list[cnt].hash =
2606 (*dp->ugc.usbgc_multicast_hash)(dp, ep);
2608 dp->mc_count = cnt + 1;
2611 if (dp->mc_count_req != dp->mc_count) {
2612 /* multicast address list overflow */
2613 dp->rxmode |= RXMODE_MULTI_OVF;
2614 } else {
2615 dp->rxmode &= ~RXMODE_MULTI_OVF;
2618 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2619 /* tell new multicast list to the hardware */
2620 err = usbgem_hal_set_rx_filter(dp);
2622 sema_v(&dp->rxfilter_lock);
2624 return (err);
2627 static int
2628 usbgem_remove_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2630 size_t len;
2631 int i;
2632 int cnt;
2633 int err;
2635 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2637 sema_p(&dp->rxfilter_lock);
2638 dp->mc_count_req--;
2639 cnt = dp->mc_count;
2640 for (i = 0; i < cnt; i++) {
2641 if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
2642 continue;
2644 /* shrink the mclist by copying forward */
2645 len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
2646 if (len > 0) {
2647 bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
2649 dp->mc_count--;
2650 break;
2653 if (dp->mc_count_req != dp->mc_count) {
2654 /* multicast address list overflow */
2655 dp->rxmode |= RXMODE_MULTI_OVF;
2656 } else {
2657 dp->rxmode &= ~RXMODE_MULTI_OVF;
2660 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2661 err = usbgem_hal_set_rx_filter(dp);
2663 sema_v(&dp->rxfilter_lock);
2665 return (err);
2669 /* ============================================================== */
2671 * ioctl
2673 /* ============================================================== */
2674 enum ioc_reply {
2675 IOC_INVAL = -1, /* bad, NAK with EINVAL */
2676 IOC_DONE, /* OK, reply sent */
2677 IOC_ACK, /* OK, just send ACK */
2678 IOC_REPLY, /* OK, just send reply */
2679 IOC_RESTART_ACK, /* OK, restart & ACK */
2680 IOC_RESTART_REPLY /* OK, restart & reply */
2684 #ifdef USBGEM_CONFIG_MAC_PROP
2685 static int
2686 usbgem_get_def_val(struct usbgem_dev *dp, mac_prop_id_t pr_num,
2687 uint_t pr_valsize, void *pr_val)
2689 link_flowctrl_t fl;
2690 int err = 0;
2692 ASSERT(pr_valsize > 0);
2693 switch (pr_num) {
2694 case MAC_PROP_AUTONEG:
2695 *(uint8_t *)pr_val =
2696 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
2697 break;
2699 case MAC_PROP_FLOWCTRL:
2700 if (pr_valsize < sizeof (link_flowctrl_t)) {
2701 return (EINVAL);
2703 switch (dp->ugc.usbgc_flow_control) {
2704 case FLOW_CONTROL_NONE:
2705 fl = LINK_FLOWCTRL_NONE;
2706 break;
2707 case FLOW_CONTROL_SYMMETRIC:
2708 fl = LINK_FLOWCTRL_BI;
2709 break;
2710 case FLOW_CONTROL_TX_PAUSE:
2711 fl = LINK_FLOWCTRL_TX;
2712 break;
2713 case FLOW_CONTROL_RX_PAUSE:
2714 fl = LINK_FLOWCTRL_RX;
2715 break;
2717 bcopy(&fl, pr_val, sizeof (fl));
2718 break;
2720 case MAC_PROP_ADV_1000FDX_CAP:
2721 case MAC_PROP_EN_1000FDX_CAP:
2722 *(uint8_t *)pr_val =
2723 (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
2724 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
2725 break;
2727 case MAC_PROP_ADV_1000HDX_CAP:
2728 case MAC_PROP_EN_1000HDX_CAP:
2729 *(uint8_t *)pr_val =
2730 (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
2731 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
2732 break;
2734 case MAC_PROP_ADV_100T4_CAP:
2735 case MAC_PROP_EN_100T4_CAP:
2736 *(uint8_t *)pr_val =
2737 BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
2738 break;
2740 case MAC_PROP_ADV_100FDX_CAP:
2741 case MAC_PROP_EN_100FDX_CAP:
2742 *(uint8_t *)pr_val =
2743 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
2744 break;
2746 case MAC_PROP_ADV_100HDX_CAP:
2747 case MAC_PROP_EN_100HDX_CAP:
2748 *(uint8_t *)pr_val =
2749 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
2750 break;
2752 case MAC_PROP_ADV_10FDX_CAP:
2753 case MAC_PROP_EN_10FDX_CAP:
2754 *(uint8_t *)pr_val =
2755 BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
2756 break;
2758 case MAC_PROP_ADV_10HDX_CAP:
2759 case MAC_PROP_EN_10HDX_CAP:
2760 *(uint8_t *)pr_val =
2761 BOOLEAN(dp->mii_status & MII_STATUS_10);
2762 break;
2764 default:
2765 err = ENOTSUP;
2766 break;
2768 return (err);
2771 #ifdef MAC_VERSION_V1
2772 static void
2773 usbgem_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2774 mac_prop_info_handle_t prh)
2776 struct usbgem_dev *dp = arg;
2777 link_flowctrl_t fl;
2780 * By default permissions are read/write unless specified
2781 * otherwise by the driver.
2784 switch (pr_num) {
2785 case MAC_PROP_DUPLEX:
2786 case MAC_PROP_SPEED:
2787 case MAC_PROP_STATUS:
2788 case MAC_PROP_ADV_1000FDX_CAP:
2789 case MAC_PROP_ADV_1000HDX_CAP:
2790 case MAC_PROP_ADV_100FDX_CAP:
2791 case MAC_PROP_ADV_100HDX_CAP:
2792 case MAC_PROP_ADV_10FDX_CAP:
2793 case MAC_PROP_ADV_10HDX_CAP:
2794 case MAC_PROP_ADV_100T4_CAP:
2795 case MAC_PROP_EN_100T4_CAP:
2796 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2797 break;
2799 case MAC_PROP_EN_1000FDX_CAP:
2800 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0) {
2801 mac_prop_info_set_default_uint8(prh,
2802 BOOLEAN(
2803 dp->mii_xstatus & MII_XSTATUS_1000BASET_FD));
2804 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)
2805 == 0) {
2806 mac_prop_info_set_default_uint8(prh,
2807 BOOLEAN(
2808 dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD));
2809 } else {
2810 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2812 break;
2814 case MAC_PROP_EN_1000HDX_CAP:
2815 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0) {
2816 mac_prop_info_set_default_uint8(prh,
2817 BOOLEAN(
2818 dp->mii_xstatus & MII_XSTATUS_1000BASET));
2819 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2820 mac_prop_info_set_default_uint8(prh,
2821 BOOLEAN(
2822 dp->mii_xstatus & MII_XSTATUS_1000BASEX));
2823 } else {
2824 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2826 break;
2828 case MAC_PROP_EN_100FDX_CAP:
2829 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2830 mac_prop_info_set_default_uint8(prh,
2831 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD));
2832 } else {
2833 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2835 break;
2837 case MAC_PROP_EN_100HDX_CAP:
2838 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2839 mac_prop_info_set_default_uint8(prh,
2840 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX));
2841 } else {
2842 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2844 break;
2846 case MAC_PROP_EN_10FDX_CAP:
2847 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2848 mac_prop_info_set_default_uint8(prh,
2849 BOOLEAN(dp->mii_status & MII_STATUS_10_FD));
2850 } else {
2851 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2853 break;
2855 case MAC_PROP_EN_10HDX_CAP:
2856 if ((dp->mii_status_ro & MII_STATUS_10) == 0) {
2857 mac_prop_info_set_default_uint8(prh,
2858 BOOLEAN(dp->mii_status & MII_STATUS_10));
2859 } else {
2860 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2862 break;
2864 case MAC_PROP_AUTONEG:
2865 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2866 mac_prop_info_set_default_uint8(prh,
2867 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG));
2868 } else {
2869 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2871 break;
2873 case MAC_PROP_FLOWCTRL:
2874 switch (dp->ugc.usbgc_flow_control) {
2875 case FLOW_CONTROL_NONE:
2876 fl = LINK_FLOWCTRL_NONE;
2877 break;
2878 case FLOW_CONTROL_SYMMETRIC:
2879 fl = LINK_FLOWCTRL_BI;
2880 break;
2881 case FLOW_CONTROL_TX_PAUSE:
2882 fl = LINK_FLOWCTRL_TX;
2883 break;
2884 case FLOW_CONTROL_RX_PAUSE:
2885 fl = LINK_FLOWCTRL_RX;
2886 break;
2888 mac_prop_info_set_default_link_flowctrl(prh, fl);
2889 break;
2891 case MAC_PROP_MTU:
2892 mac_prop_info_set_range_uint32(prh,
2893 dp->ugc.usbgc_min_mtu, dp->ugc.usbgc_max_mtu);
2894 break;
2896 case MAC_PROP_PRIVATE:
2897 break;
2900 #endif
2902 static int
2903 usbgem_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2904 uint_t pr_valsize, const void *pr_val)
2906 struct usbgem_dev *dp = arg;
2907 int err = 0;
2908 boolean_t update = B_FALSE;
2909 link_flowctrl_t flowctrl;
2910 uint32_t cur_mtu, new_mtu;
2912 rw_enter(&dp->dev_state_lock, RW_WRITER);
2913 switch (pr_num) {
2914 case MAC_PROP_EN_1000FDX_CAP:
2915 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0 ||
2916 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD) == 0) {
2917 if (dp->anadv_1000fdx != *(uint8_t *)pr_val) {
2918 dp->anadv_1000fdx = *(uint8_t *)pr_val;
2919 update = B_TRUE;
2921 } else {
2922 err = ENOTSUP;
2924 break;
2926 case MAC_PROP_EN_1000HDX_CAP:
2927 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0 ||
2928 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2929 if (dp->anadv_1000hdx != *(uint8_t *)pr_val) {
2930 dp->anadv_1000hdx = *(uint8_t *)pr_val;
2931 update = B_TRUE;
2933 } else {
2934 err = ENOTSUP;
2936 break;
2938 case MAC_PROP_EN_100FDX_CAP:
2939 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2940 if (dp->anadv_100fdx != *(uint8_t *)pr_val) {
2941 dp->anadv_100fdx = *(uint8_t *)pr_val;
2942 update = B_TRUE;
2944 } else {
2945 err = ENOTSUP;
2947 break;
2949 case MAC_PROP_EN_100HDX_CAP:
2950 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2951 if (dp->anadv_100hdx != *(uint8_t *)pr_val) {
2952 dp->anadv_100hdx = *(uint8_t *)pr_val;
2953 update = B_TRUE;
2955 } else {
2956 err = ENOTSUP;
2958 break;
2960 case MAC_PROP_EN_10FDX_CAP:
2961 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2962 if (dp->anadv_10fdx != *(uint8_t *)pr_val) {
2963 dp->anadv_10fdx = *(uint8_t *)pr_val;
2964 update = B_TRUE;
2966 } else {
2967 err = ENOTSUP;
2969 break;
2971 case MAC_PROP_EN_10HDX_CAP:
2972 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2973 if (dp->anadv_10hdx != *(uint8_t *)pr_val) {
2974 dp->anadv_10hdx = *(uint8_t *)pr_val;
2975 update = B_TRUE;
2977 } else {
2978 err = ENOTSUP;
2980 break;
2982 case MAC_PROP_AUTONEG:
2983 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2984 if (dp->anadv_autoneg != *(uint8_t *)pr_val) {
2985 dp->anadv_autoneg = *(uint8_t *)pr_val;
2986 update = B_TRUE;
2988 } else {
2989 err = ENOTSUP;
2991 break;
2993 case MAC_PROP_FLOWCTRL:
2994 bcopy(pr_val, &flowctrl, sizeof (flowctrl));
2996 switch (flowctrl) {
2997 default:
2998 err = EINVAL;
2999 break;
3001 case LINK_FLOWCTRL_NONE:
3002 if (dp->flow_control != FLOW_CONTROL_NONE) {
3003 dp->flow_control = FLOW_CONTROL_NONE;
3004 update = B_TRUE;
3006 break;
3008 case LINK_FLOWCTRL_RX:
3009 if (dp->flow_control != FLOW_CONTROL_RX_PAUSE) {
3010 dp->flow_control = FLOW_CONTROL_RX_PAUSE;
3011 update = B_TRUE;
3013 break;
3015 case LINK_FLOWCTRL_TX:
3016 if (dp->flow_control != FLOW_CONTROL_TX_PAUSE) {
3017 dp->flow_control = FLOW_CONTROL_TX_PAUSE;
3018 update = B_TRUE;
3020 break;
3022 case LINK_FLOWCTRL_BI:
3023 if (dp->flow_control != FLOW_CONTROL_SYMMETRIC) {
3024 dp->flow_control = FLOW_CONTROL_SYMMETRIC;
3025 update = B_TRUE;
3027 break;
3029 break;
3031 case MAC_PROP_ADV_1000FDX_CAP:
3032 case MAC_PROP_ADV_1000HDX_CAP:
3033 case MAC_PROP_ADV_100FDX_CAP:
3034 case MAC_PROP_ADV_100HDX_CAP:
3035 case MAC_PROP_ADV_10FDX_CAP:
3036 case MAC_PROP_ADV_10HDX_CAP:
3037 case MAC_PROP_STATUS:
3038 case MAC_PROP_SPEED:
3039 case MAC_PROP_DUPLEX:
3040 err = ENOTSUP; /* read-only prop. Can't set this. */
3041 break;
3043 case MAC_PROP_MTU:
3044 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
3045 if (new_mtu != dp->mtu) {
3046 err = EINVAL;
3048 break;
3050 case MAC_PROP_PRIVATE:
3051 err = ENOTSUP;
3052 break;
3054 default:
3055 err = ENOTSUP;
3056 break;
3059 if (update) {
3060 /* sync with PHY */
3061 usbgem_choose_forcedmode(dp);
3062 dp->mii_state = MII_STATE_UNKNOWN;
3063 cv_signal(&dp->link_watcher_wait_cv);
3065 rw_exit(&dp->dev_state_lock);
3066 return (err);
3069 static int
3070 #ifdef MAC_VERSION_V1
3071 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3072 uint_t pr_valsize, void *pr_val)
3073 #else
3074 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3075 uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
3076 #endif
3078 struct usbgem_dev *dp = arg;
3079 int err = 0;
3080 link_flowctrl_t flowctrl;
3081 uint64_t tmp = 0;
3083 if (pr_valsize == 0) {
3084 return (EINVAL);
3086 #ifndef MAC_VERSION_V1
3087 *perm = MAC_PROP_PERM_RW;
3088 #endif
3089 bzero(pr_val, pr_valsize);
3090 #ifndef MAC_VERSION_V1
3091 if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE)) {
3092 return (usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val));
3094 #endif
3095 rw_enter(&dp->dev_state_lock, RW_READER);
3096 switch (pr_num) {
3097 case MAC_PROP_DUPLEX:
3098 #ifndef MAC_VERSION_V1
3099 *perm = MAC_PROP_PERM_READ;
3100 #endif
3101 if (pr_valsize >= sizeof (link_duplex_t)) {
3102 if (dp->mii_state != MII_STATE_LINKUP) {
3103 *(link_duplex_t *)pr_val = LINK_DUPLEX_UNKNOWN;
3104 } else if (dp->full_duplex) {
3105 *(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
3106 } else {
3107 *(link_duplex_t *)pr_val = LINK_DUPLEX_HALF;
3109 } else {
3110 err = EINVAL;
3112 break;
3113 case MAC_PROP_SPEED:
3114 #ifndef MAC_VERSION_V1
3115 *perm = MAC_PROP_PERM_READ;
3116 #endif
3117 if (pr_valsize >= sizeof (uint64_t)) {
3118 switch (dp->speed) {
3119 case USBGEM_SPD_1000:
3120 tmp = 1000000000;
3121 break;
3122 case USBGEM_SPD_100:
3123 tmp = 100000000;
3124 break;
3125 case USBGEM_SPD_10:
3126 tmp = 10000000;
3127 break;
3128 default:
3129 tmp = 0;
3131 bcopy(&tmp, pr_val, sizeof (tmp));
3132 } else {
3133 err = EINVAL;
3135 break;
3137 case MAC_PROP_AUTONEG:
3138 #ifndef MAC_VERSION_V1
3139 if (dp->mii_status_ro & MII_STATUS_CANAUTONEG) {
3140 *perm = MAC_PROP_PERM_READ;
3142 #endif
3143 *(uint8_t *)pr_val = dp->anadv_autoneg;
3144 break;
3146 case MAC_PROP_FLOWCTRL:
3147 if (pr_valsize >= sizeof (link_flowctrl_t)) {
3148 switch (dp->flow_control) {
3149 case FLOW_CONTROL_NONE:
3150 flowctrl = LINK_FLOWCTRL_NONE;
3151 break;
3152 case FLOW_CONTROL_RX_PAUSE:
3153 flowctrl = LINK_FLOWCTRL_RX;
3154 break;
3155 case FLOW_CONTROL_TX_PAUSE:
3156 flowctrl = LINK_FLOWCTRL_TX;
3157 break;
3158 case FLOW_CONTROL_SYMMETRIC:
3159 flowctrl = LINK_FLOWCTRL_BI;
3160 break;
3162 bcopy(&flowctrl, pr_val, sizeof (flowctrl));
3163 } else {
3164 err = EINVAL;
3166 break;
3168 case MAC_PROP_ADV_1000FDX_CAP:
3169 case MAC_PROP_ADV_1000HDX_CAP:
3170 case MAC_PROP_ADV_100FDX_CAP:
3171 case MAC_PROP_ADV_100HDX_CAP:
3172 case MAC_PROP_ADV_10FDX_CAP:
3173 case MAC_PROP_ADV_10HDX_CAP:
3174 case MAC_PROP_ADV_100T4_CAP:
3175 usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val);
3176 break;
3178 case MAC_PROP_EN_1000FDX_CAP:
3179 #ifndef MAC_VERSION_V1
3180 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) &&
3181 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)) {
3182 *perm = MAC_PROP_PERM_READ;
3184 #endif
3185 *(uint8_t *)pr_val = dp->anadv_1000fdx;
3186 break;
3188 case MAC_PROP_EN_1000HDX_CAP:
3189 #ifndef MAC_VERSION_V1
3190 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) &&
3191 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX)) {
3192 *perm = MAC_PROP_PERM_READ;
3194 #endif
3195 *(uint8_t *)pr_val = dp->anadv_1000hdx;
3196 break;
3198 case MAC_PROP_EN_100FDX_CAP:
3199 #ifndef MAC_VERSION_V1
3200 if (dp->mii_status_ro & MII_STATUS_100_BASEX_FD) {
3201 *perm = MAC_PROP_PERM_READ;
3203 #endif
3204 *(uint8_t *)pr_val = dp->anadv_100fdx;
3205 break;
3207 case MAC_PROP_EN_100HDX_CAP:
3208 #ifndef MAC_VERSION_V1
3209 if (dp->mii_status_ro & MII_STATUS_100_BASEX) {
3210 *perm = MAC_PROP_PERM_READ;
3212 #endif
3213 *(uint8_t *)pr_val = dp->anadv_100hdx;
3214 break;
3216 case MAC_PROP_EN_10FDX_CAP:
3217 #ifndef MAC_VERSION_V1
3218 if (dp->mii_status_ro & MII_STATUS_10_FD) {
3219 *perm = MAC_PROP_PERM_READ;
3221 #endif
3222 *(uint8_t *)pr_val = dp->anadv_10fdx;
3223 break;
3225 case MAC_PROP_EN_10HDX_CAP:
3226 #ifndef MAC_VERSION_V1
3227 if (dp->mii_status_ro & MII_STATUS_10) {
3228 *perm = MAC_PROP_PERM_READ;
3230 #endif
3231 *(uint8_t *)pr_val = dp->anadv_10hdx;
3232 break;
3234 case MAC_PROP_EN_100T4_CAP:
3235 #ifndef MAC_VERSION_V1
3236 if (dp->mii_status_ro & MII_STATUS_100_BASE_T4) {
3237 *perm = MAC_PROP_PERM_READ;
3239 #endif
3240 *(uint8_t *)pr_val = dp->anadv_100t4;
3241 break;
3243 case MAC_PROP_PRIVATE:
3244 err = ENOTSUP;
3245 break;
3247 #ifndef MAC_VERSION_V1
3248 case MAC_PROP_MTU: {
3249 mac_propval_range_t range;
3250 if (!(pr_flags & MAC_PROP_POSSIBLE)) {
3251 err = ENOTSUP;
3252 break;
3254 if (pr_valsize < sizeof (mac_propval_range_t)) {
3255 err = EINVAL;
3256 break;
3258 range.mpr_count = 1;
3259 range.mpr_type = MAC_PROPVAL_UINT32;
3260 range.range_uint32[0].mpur_min = ETHERMTU;
3261 range.range_uint32[0].mpur_max = dp->mtu;
3262 bcopy(&range, pr_val, sizeof (range));
3263 break;
3265 #endif
3266 default:
3267 err = ENOTSUP;
3268 break;
3271 rw_exit(&dp->dev_state_lock);
3272 return (err);
3274 #endif /* USBGEM_CONFIG_MAC_PROP */
3276 #ifdef USBGEM_CONFIG_ND
3277 /* ============================================================== */
3279 * ND interface
3281 /* ============================================================== */
3282 enum {
3283 PARAM_AUTONEG_CAP,
3284 PARAM_PAUSE_CAP,
3285 PARAM_ASYM_PAUSE_CAP,
3286 PARAM_1000FDX_CAP,
3287 PARAM_1000HDX_CAP,
3288 PARAM_100T4_CAP,
3289 PARAM_100FDX_CAP,
3290 PARAM_100HDX_CAP,
3291 PARAM_10FDX_CAP,
3292 PARAM_10HDX_CAP,
3294 PARAM_ADV_AUTONEG_CAP,
3295 PARAM_ADV_PAUSE_CAP,
3296 PARAM_ADV_ASYM_PAUSE_CAP,
3297 PARAM_ADV_1000FDX_CAP,
3298 PARAM_ADV_1000HDX_CAP,
3299 PARAM_ADV_100T4_CAP,
3300 PARAM_ADV_100FDX_CAP,
3301 PARAM_ADV_100HDX_CAP,
3302 PARAM_ADV_10FDX_CAP,
3303 PARAM_ADV_10HDX_CAP,
3304 PARAM_ADV_1000T_MS,
3306 PARAM_LP_AUTONEG_CAP,
3307 PARAM_LP_PAUSE_CAP,
3308 PARAM_LP_ASYM_PAUSE_CAP,
3309 PARAM_LP_1000FDX_CAP,
3310 PARAM_LP_1000HDX_CAP,
3311 PARAM_LP_100T4_CAP,
3312 PARAM_LP_100FDX_CAP,
3313 PARAM_LP_100HDX_CAP,
3314 PARAM_LP_10FDX_CAP,
3315 PARAM_LP_10HDX_CAP,
3317 PARAM_LINK_STATUS,
3318 PARAM_LINK_SPEED,
3319 PARAM_LINK_DUPLEX,
3321 PARAM_LINK_AUTONEG,
3322 PARAM_LINK_RX_PAUSE,
3323 PARAM_LINK_TX_PAUSE,
3325 PARAM_LOOP_MODE,
3326 PARAM_MSI_CNT,
3327 #ifdef DEBUG_RESUME
3328 PARAM_RESUME_TEST,
3329 #endif
3331 PARAM_COUNT
3334 struct usbgem_nd_arg {
3335 struct usbgem_dev *dp;
3336 int item;
3339 static int
3340 usbgem_param_get(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
3342 struct usbgem_dev *dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3343 int item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3344 long val;
3346 DPRINTF(1, (CE_CONT, "!%s: %s: called, item:%d",
3347 dp->name, __func__, item));
3349 switch (item) {
3350 case PARAM_AUTONEG_CAP:
3351 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
3352 DPRINTF(1, (CE_CONT, "autoneg_cap:%d", val));
3353 break;
3355 case PARAM_PAUSE_CAP:
3356 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
3357 break;
3359 case PARAM_ASYM_PAUSE_CAP:
3360 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
3361 break;
3363 case PARAM_1000FDX_CAP:
3364 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
3365 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
3366 break;
3368 case PARAM_1000HDX_CAP:
3369 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
3370 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
3371 break;
3373 case PARAM_100T4_CAP:
3374 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
3375 break;
3377 case PARAM_100FDX_CAP:
3378 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
3379 break;
3381 case PARAM_100HDX_CAP:
3382 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
3383 break;
3385 case PARAM_10FDX_CAP:
3386 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
3387 break;
3389 case PARAM_10HDX_CAP:
3390 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
3391 break;
3393 case PARAM_ADV_AUTONEG_CAP:
3394 val = dp->anadv_autoneg;
3395 break;
3397 case PARAM_ADV_PAUSE_CAP:
3398 val = dp->anadv_pause;
3399 break;
3401 case PARAM_ADV_ASYM_PAUSE_CAP:
3402 val = dp->anadv_asmpause;
3403 break;
3405 case PARAM_ADV_1000FDX_CAP:
3406 val = dp->anadv_1000fdx;
3407 break;
3409 case PARAM_ADV_1000HDX_CAP:
3410 val = dp->anadv_1000hdx;
3411 break;
3413 case PARAM_ADV_100T4_CAP:
3414 val = dp->anadv_100t4;
3415 break;
3417 case PARAM_ADV_100FDX_CAP:
3418 val = dp->anadv_100fdx;
3419 break;
3421 case PARAM_ADV_100HDX_CAP:
3422 val = dp->anadv_100hdx;
3423 break;
3425 case PARAM_ADV_10FDX_CAP:
3426 val = dp->anadv_10fdx;
3427 break;
3429 case PARAM_ADV_10HDX_CAP:
3430 val = dp->anadv_10hdx;
3431 break;
3433 case PARAM_ADV_1000T_MS:
3434 val = dp->anadv_1000t_ms;
3435 break;
3437 case PARAM_LP_AUTONEG_CAP:
3438 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3439 break;
3441 case PARAM_LP_PAUSE_CAP:
3442 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
3443 break;
3445 case PARAM_LP_ASYM_PAUSE_CAP:
3446 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
3447 break;
3449 case PARAM_LP_1000FDX_CAP:
3450 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
3451 break;
3453 case PARAM_LP_1000HDX_CAP:
3454 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
3455 break;
3457 case PARAM_LP_100T4_CAP:
3458 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
3459 break;
3461 case PARAM_LP_100FDX_CAP:
3462 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
3463 break;
3465 case PARAM_LP_100HDX_CAP:
3466 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
3467 break;
3469 case PARAM_LP_10FDX_CAP:
3470 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
3471 break;
3473 case PARAM_LP_10HDX_CAP:
3474 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
3475 break;
3477 case PARAM_LINK_STATUS:
3478 val = (dp->mii_state == MII_STATE_LINKUP);
3479 break;
3481 case PARAM_LINK_SPEED:
3482 val = usbgem_speed_value[dp->speed];
3483 break;
3485 case PARAM_LINK_DUPLEX:
3486 val = 0;
3487 if (dp->mii_state == MII_STATE_LINKUP) {
3488 val = dp->full_duplex ? 2 : 1;
3490 break;
3492 case PARAM_LINK_AUTONEG:
3493 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3494 break;
3496 case PARAM_LINK_RX_PAUSE:
3497 val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3498 (dp->flow_control == FLOW_CONTROL_RX_PAUSE);
3499 break;
3501 case PARAM_LINK_TX_PAUSE:
3502 val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3503 (dp->flow_control == FLOW_CONTROL_TX_PAUSE);
3504 break;
3506 #ifdef DEBUG_RESUME
3507 case PARAM_RESUME_TEST:
3508 val = 0;
3509 break;
3510 #endif
3511 default:
3512 cmn_err(CE_WARN, "%s: unimplemented ndd control (%d)",
3513 dp->name, item);
3514 break;
3517 (void) mi_mpprintf(mp, "%ld", val);
3519 return (0);
3522 static int
3523 usbgem_param_set(queue_t *q,
3524 mblk_t *mp, char *value, caddr_t arg, cred_t *credp)
3526 struct usbgem_dev *dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3527 int item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3528 long val;
3529 char *end;
3531 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3532 if (ddi_strtol(value, &end, 10, &val)) {
3533 return (EINVAL);
3535 if (end == value) {
3536 return (EINVAL);
3539 switch (item) {
3540 case PARAM_ADV_AUTONEG_CAP:
3541 if (val != 0 && val != 1) {
3542 goto err;
3544 if (val && (dp->mii_status & MII_STATUS_CANAUTONEG) == 0) {
3545 goto err;
3547 dp->anadv_autoneg = (int)val;
3548 break;
3550 case PARAM_ADV_PAUSE_CAP:
3551 if (val != 0 && val != 1) {
3552 goto err;
3554 if (val && dp->ugc.usbgc_flow_control == FLOW_CONTROL_NONE) {
3555 goto err;
3557 dp->anadv_pause = (int)val;
3558 break;
3560 case PARAM_ADV_ASYM_PAUSE_CAP:
3561 if (val != 0 && val != 1) {
3562 goto err;
3564 if (val &&
3565 dp->ugc.usbgc_flow_control <= FLOW_CONTROL_SYMMETRIC) {
3566 goto err;
3568 dp->anadv_asmpause = (int)val;
3569 break;
3571 case PARAM_ADV_1000FDX_CAP:
3572 if (val != 0 && val != 1) {
3573 goto err;
3575 if (val && (dp->mii_xstatus &
3576 (MII_XSTATUS_1000BASET_FD |
3577 MII_XSTATUS_1000BASEX_FD)) == 0) {
3578 goto err;
3580 dp->anadv_1000fdx = (int)val;
3581 break;
3583 case PARAM_ADV_1000HDX_CAP:
3584 if (val != 0 && val != 1) {
3585 goto err;
3587 if (val && (dp->mii_xstatus &
3588 (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASEX)) == 0) {
3589 goto err;
3591 dp->anadv_1000hdx = (int)val;
3592 break;
3594 case PARAM_ADV_100T4_CAP:
3595 if (val != 0 && val != 1) {
3596 goto err;
3598 if (val && (dp->mii_status & MII_STATUS_100_BASE_T4) == 0) {
3599 goto err;
3601 dp->anadv_100t4 = (int)val;
3602 break;
3604 case PARAM_ADV_100FDX_CAP:
3605 if (val != 0 && val != 1) {
3606 goto err;
3608 if (val && (dp->mii_status & MII_STATUS_100_BASEX_FD) == 0) {
3609 goto err;
3611 dp->anadv_100fdx = (int)val;
3612 break;
3614 case PARAM_ADV_100HDX_CAP:
3615 if (val != 0 && val != 1) {
3616 goto err;
3618 if (val && (dp->mii_status & MII_STATUS_100_BASEX) == 0) {
3619 goto err;
3621 dp->anadv_100hdx = (int)val;
3622 break;
3624 case PARAM_ADV_10FDX_CAP:
3625 if (val != 0 && val != 1) {
3626 goto err;
3628 if (val && (dp->mii_status & MII_STATUS_10_FD) == 0) {
3629 goto err;
3631 dp->anadv_10fdx = (int)val;
3632 break;
3634 case PARAM_ADV_10HDX_CAP:
3635 if (val != 0 && val != 1) {
3636 goto err;
3638 if (val && (dp->mii_status & MII_STATUS_10) == 0) {
3639 goto err;
3641 dp->anadv_10hdx = (int)val;
3642 break;
3644 case PARAM_ADV_1000T_MS:
3645 if (val != 0 && val != 1 && val != 2) {
3646 goto err;
3648 if (val && (dp->mii_xstatus &
3649 (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASET_FD)) == 0) {
3650 goto err;
3652 dp->anadv_1000t_ms = (int)val;
3653 break;
3655 #ifdef DEBUG_RESUME
3656 case PARAM_RESUME_TEST:
3657 mutex_exit(&dp->xmitlock);
3658 mutex_exit(&dp->intrlock);
3659 gem_suspend(dp->dip);
3660 gem_resume(dp->dip);
3661 mutex_enter(&dp->intrlock);
3662 mutex_enter(&dp->xmitlock);
3663 break;
3664 #endif
3667 /* sync with PHY */
3668 usbgem_choose_forcedmode(dp);
3670 dp->mii_state = MII_STATE_UNKNOWN;
3671 if (dp->ugc.usbgc_mii_hw_link_detection) {
3672 /* wake up link watcher possiblely sleeps */
3673 cv_signal(&dp->link_watcher_wait_cv);
3676 return (0);
3677 err:
3678 return (EINVAL);
3681 static void
3682 usbgem_nd_load(struct usbgem_dev *dp,
3683 char *name, ndgetf_t gf, ndsetf_t sf, int item)
3685 struct usbgem_nd_arg *arg;
3687 ASSERT(item >= 0);
3688 ASSERT(item < PARAM_COUNT);
3690 arg = &((struct usbgem_nd_arg *)(void *)dp->nd_arg_p)[item];
3691 arg->dp = dp;
3692 arg->item = item;
3694 DPRINTF(2, (CE_CONT, "!%s: %s: name:%s, item:%d",
3695 dp->name, __func__, name, item));
3696 (void) nd_load(&dp->nd_data_p, name, gf, sf, (caddr_t)arg);
3699 static void
3700 usbgem_nd_setup(struct usbgem_dev *dp)
3702 DPRINTF(1, (CE_CONT, "!%s: %s: called, mii_status:0x%b",
3703 dp->name, __func__, dp->mii_status, MII_STATUS_BITS));
3705 ASSERT(dp->nd_arg_p == NULL);
3707 dp->nd_arg_p =
3708 kmem_zalloc(sizeof (struct usbgem_nd_arg) * PARAM_COUNT, KM_SLEEP);
3710 #define SETFUNC(x) ((x) ? usbgem_param_set : NULL)
3712 usbgem_nd_load(dp, "autoneg_cap",
3713 usbgem_param_get, NULL, PARAM_AUTONEG_CAP);
3714 usbgem_nd_load(dp, "pause_cap",
3715 usbgem_param_get, NULL, PARAM_PAUSE_CAP);
3716 usbgem_nd_load(dp, "asym_pause_cap",
3717 usbgem_param_get, NULL, PARAM_ASYM_PAUSE_CAP);
3718 usbgem_nd_load(dp, "1000fdx_cap",
3719 usbgem_param_get, NULL, PARAM_1000FDX_CAP);
3720 usbgem_nd_load(dp, "1000hdx_cap",
3721 usbgem_param_get, NULL, PARAM_1000HDX_CAP);
3722 usbgem_nd_load(dp, "100T4_cap",
3723 usbgem_param_get, NULL, PARAM_100T4_CAP);
3724 usbgem_nd_load(dp, "100fdx_cap",
3725 usbgem_param_get, NULL, PARAM_100FDX_CAP);
3726 usbgem_nd_load(dp, "100hdx_cap",
3727 usbgem_param_get, NULL, PARAM_100HDX_CAP);
3728 usbgem_nd_load(dp, "10fdx_cap",
3729 usbgem_param_get, NULL, PARAM_10FDX_CAP);
3730 usbgem_nd_load(dp, "10hdx_cap",
3731 usbgem_param_get, NULL, PARAM_10HDX_CAP);
3733 /* Our advertised capabilities */
3734 usbgem_nd_load(dp, "adv_autoneg_cap", usbgem_param_get,
3735 SETFUNC(dp->mii_status & MII_STATUS_CANAUTONEG),
3736 PARAM_ADV_AUTONEG_CAP);
3737 usbgem_nd_load(dp, "adv_pause_cap", usbgem_param_get,
3738 SETFUNC(dp->ugc.usbgc_flow_control & 1),
3739 PARAM_ADV_PAUSE_CAP);
3740 usbgem_nd_load(dp, "adv_asym_pause_cap", usbgem_param_get,
3741 SETFUNC(dp->ugc.usbgc_flow_control & 2),
3742 PARAM_ADV_ASYM_PAUSE_CAP);
3743 usbgem_nd_load(dp, "adv_1000fdx_cap", usbgem_param_get,
3744 SETFUNC(dp->mii_xstatus &
3745 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD)),
3746 PARAM_ADV_1000FDX_CAP);
3747 usbgem_nd_load(dp, "adv_1000hdx_cap", usbgem_param_get,
3748 SETFUNC(dp->mii_xstatus &
3749 (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET)),
3750 PARAM_ADV_1000HDX_CAP);
3751 usbgem_nd_load(dp, "adv_100T4_cap", usbgem_param_get,
3752 SETFUNC((dp->mii_status & MII_STATUS_100_BASE_T4) &&
3753 !dp->mii_advert_ro),
3754 PARAM_ADV_100T4_CAP);
3755 usbgem_nd_load(dp, "adv_100fdx_cap", usbgem_param_get,
3756 SETFUNC((dp->mii_status & MII_STATUS_100_BASEX_FD) &&
3757 !dp->mii_advert_ro),
3758 PARAM_ADV_100FDX_CAP);
3759 usbgem_nd_load(dp, "adv_100hdx_cap", usbgem_param_get,
3760 SETFUNC((dp->mii_status & MII_STATUS_100_BASEX) &&
3761 !dp->mii_advert_ro),
3762 PARAM_ADV_100HDX_CAP);
3763 usbgem_nd_load(dp, "adv_10fdx_cap", usbgem_param_get,
3764 SETFUNC((dp->mii_status & MII_STATUS_10_FD) &&
3765 !dp->mii_advert_ro),
3766 PARAM_ADV_10FDX_CAP);
3767 usbgem_nd_load(dp, "adv_10hdx_cap", usbgem_param_get,
3768 SETFUNC((dp->mii_status & MII_STATUS_10) &&
3769 !dp->mii_advert_ro),
3770 PARAM_ADV_10HDX_CAP);
3771 usbgem_nd_load(dp, "adv_1000t_ms", usbgem_param_get,
3772 SETFUNC(dp->mii_xstatus &
3773 (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)),
3774 PARAM_ADV_1000T_MS);
3777 /* Partner's advertised capabilities */
3778 usbgem_nd_load(dp, "lp_autoneg_cap",
3779 usbgem_param_get, NULL, PARAM_LP_AUTONEG_CAP);
3780 usbgem_nd_load(dp, "lp_pause_cap",
3781 usbgem_param_get, NULL, PARAM_LP_PAUSE_CAP);
3782 usbgem_nd_load(dp, "lp_asym_pause_cap",
3783 usbgem_param_get, NULL, PARAM_LP_ASYM_PAUSE_CAP);
3784 usbgem_nd_load(dp, "lp_1000fdx_cap",
3785 usbgem_param_get, NULL, PARAM_LP_1000FDX_CAP);
3786 usbgem_nd_load(dp, "lp_1000hdx_cap",
3787 usbgem_param_get, NULL, PARAM_LP_1000HDX_CAP);
3788 usbgem_nd_load(dp, "lp_100T4_cap",
3789 usbgem_param_get, NULL, PARAM_LP_100T4_CAP);
3790 usbgem_nd_load(dp, "lp_100fdx_cap",
3791 usbgem_param_get, NULL, PARAM_LP_100FDX_CAP);
3792 usbgem_nd_load(dp, "lp_100hdx_cap",
3793 usbgem_param_get, NULL, PARAM_LP_100HDX_CAP);
3794 usbgem_nd_load(dp, "lp_10fdx_cap",
3795 usbgem_param_get, NULL, PARAM_LP_10FDX_CAP);
3796 usbgem_nd_load(dp, "lp_10hdx_cap",
3797 usbgem_param_get, NULL, PARAM_LP_10HDX_CAP);
3799 /* Current operating modes */
3800 usbgem_nd_load(dp, "link_status",
3801 usbgem_param_get, NULL, PARAM_LINK_STATUS);
3802 usbgem_nd_load(dp, "link_speed",
3803 usbgem_param_get, NULL, PARAM_LINK_SPEED);
3804 usbgem_nd_load(dp, "link_duplex",
3805 usbgem_param_get, NULL, PARAM_LINK_DUPLEX);
3806 usbgem_nd_load(dp, "link_autoneg",
3807 usbgem_param_get, NULL, PARAM_LINK_AUTONEG);
3808 usbgem_nd_load(dp, "link_rx_pause",
3809 usbgem_param_get, NULL, PARAM_LINK_RX_PAUSE);
3810 usbgem_nd_load(dp, "link_tx_pause",
3811 usbgem_param_get, NULL, PARAM_LINK_TX_PAUSE);
3812 #ifdef DEBUG_RESUME
3813 usbgem_nd_load(dp, "resume_test",
3814 usbgem_param_get, usbgem_param_set, PARAM_RESUME_TEST);
3815 #endif
3816 #undef SETFUNC
3819 static
3820 enum ioc_reply
3821 usbgem_nd_ioctl(struct usbgem_dev *dp,
3822 queue_t *wq, mblk_t *mp, struct iocblk *iocp)
3824 boolean_t ok;
3826 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3828 switch (iocp->ioc_cmd) {
3829 case ND_GET:
3830 ok = nd_getset(wq, dp->nd_data_p, mp);
3831 DPRINTF(1, (CE_CONT,
3832 "%s: get %s", dp->name, ok ? "OK" : "FAIL"));
3833 return (ok ? IOC_REPLY : IOC_INVAL);
3835 case ND_SET:
3836 ok = nd_getset(wq, dp->nd_data_p, mp);
3838 DPRINTF(1, (CE_CONT, "%s: set %s err %d",
3839 dp->name, ok ? "OK" : "FAIL", iocp->ioc_error));
3841 if (!ok) {
3842 return (IOC_INVAL);
3845 if (iocp->ioc_error) {
3846 return (IOC_REPLY);
3849 return (IOC_RESTART_REPLY);
3852 cmn_err(CE_WARN, "%s: invalid cmd 0x%x", dp->name, iocp->ioc_cmd);
3854 return (IOC_INVAL);
3857 static void
3858 usbgem_nd_cleanup(struct usbgem_dev *dp)
3860 ASSERT(dp->nd_data_p != NULL);
3861 ASSERT(dp->nd_arg_p != NULL);
3863 nd_free(&dp->nd_data_p);
3865 kmem_free(dp->nd_arg_p, sizeof (struct usbgem_nd_arg) * PARAM_COUNT);
3866 dp->nd_arg_p = NULL;
3868 #endif /* USBGEM_CONFIG_ND */
3870 static void
3871 usbgem_mac_ioctl(struct usbgem_dev *dp, queue_t *wq, mblk_t *mp)
3873 struct iocblk *iocp;
3874 enum ioc_reply status;
3876 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3879 * Validate the command before bothering with the mutex ...
3881 iocp = (void *)mp->b_rptr;
3882 iocp->ioc_error = 0;
3884 DPRINTF(1, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__,
3885 iocp->ioc_cmd));
3887 #ifdef USBGEM_CONFIG_ND
3888 switch (iocp->ioc_cmd) {
3889 default:
3890 _NOTE(NOTREACHED)
3891 status = IOC_INVAL;
3892 break;
3894 case ND_GET:
3895 case ND_SET:
3896 status = usbgem_nd_ioctl(dp, wq, mp, iocp);
3897 break;
3901 * Finally, decide how to reply
3903 switch (status) {
3904 default:
3905 case IOC_INVAL:
3907 * Error, reply with a NAK and EINVAL or the specified error
3909 miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
3910 EINVAL : iocp->ioc_error);
3911 break;
3913 case IOC_DONE:
3915 * OK, reply already sent
3917 break;
3919 case IOC_RESTART_ACK:
3920 case IOC_ACK:
3922 * OK, reply with an ACK
3924 miocack(wq, mp, 0, 0);
3925 break;
3927 case IOC_RESTART_REPLY:
3928 case IOC_REPLY:
3930 * OK, send prepared reply as ACK or NAK
3932 mp->b_datap->db_type =
3933 iocp->ioc_error == 0 ? M_IOCACK : M_IOCNAK;
3934 qreply(wq, mp);
3935 break;
3937 #else
3938 miocnak(wq, mp, 0, EINVAL);
3939 return;
3940 #endif /* USBGEM_CONFIG_GLDv3 */
3943 #ifndef SYS_MAC_H
3944 #define XCVR_UNDEFINED 0
3945 #define XCVR_NONE 1
3946 #define XCVR_10 2
3947 #define XCVR_100T4 3
3948 #define XCVR_100X 4
3949 #define XCVR_100T2 5
3950 #define XCVR_1000X 6
3951 #define XCVR_1000T 7
3952 #endif
3953 static int
3954 usbgem_mac_xcvr_inuse(struct usbgem_dev *dp)
3956 int val = XCVR_UNDEFINED;
3958 if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
3959 if (dp->mii_status & MII_STATUS_100_BASE_T4) {
3960 val = XCVR_100T4;
3961 } else if (dp->mii_status &
3962 (MII_STATUS_100_BASEX_FD |
3963 MII_STATUS_100_BASEX)) {
3964 val = XCVR_100X;
3965 } else if (dp->mii_status &
3966 (MII_STATUS_100_BASE_T2_FD |
3967 MII_STATUS_100_BASE_T2)) {
3968 val = XCVR_100T2;
3969 } else if (dp->mii_status &
3970 (MII_STATUS_10_FD | MII_STATUS_10)) {
3971 val = XCVR_10;
3973 } else if (dp->mii_xstatus &
3974 (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
3975 val = XCVR_1000T;
3976 } else if (dp->mii_xstatus &
3977 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
3978 val = XCVR_1000X;
3981 return (val);
3984 #ifdef USBGEM_CONFIG_GLDv3
3985 /* ============================================================== */
3987 * GLDv3 interface
3989 /* ============================================================== */
3990 static int usbgem_m_getstat(void *, uint_t, uint64_t *);
3991 static int usbgem_m_start(void *);
3992 static void usbgem_m_stop(void *);
3993 static int usbgem_m_setpromisc(void *, boolean_t);
3994 static int usbgem_m_multicst(void *, boolean_t, const uint8_t *);
3995 static int usbgem_m_unicst(void *, const uint8_t *);
3996 static mblk_t *usbgem_m_tx(void *, mblk_t *);
3997 static void usbgem_m_ioctl(void *, queue_t *, mblk_t *);
3998 #ifdef GEM_CONFIG_MAC_PROP
3999 static int usbgem_m_setprop(void *, const char *, mac_prop_id_t,
4000 uint_t, const void *);
4001 #ifdef MAC_VERSION_V1
4002 static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4003 uint_t, void *);
4004 #else
4005 static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4006 uint_t, uint_t, void *, uint_t *);
4007 #endif
4008 #endif
4010 #ifdef _SYS_MAC_PROVIDER_H
4011 #define GEM_M_CALLBACK_FLAGS (MC_IOCTL)
4012 #else
4013 #define GEM_M_CALLBACK_FLAGS (MC_IOCTL)
4014 #endif
4016 static mac_callbacks_t gem_m_callbacks = {
4017 #ifdef USBGEM_CONFIG_MAC_PROP
4018 #ifdef MAC_VERSION_V1
4019 GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
4020 #else
4021 GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP,
4022 #endif
4023 #else
4024 GEM_M_CALLBACK_FLAGS,
4025 #endif
4026 usbgem_m_getstat,
4027 usbgem_m_start,
4028 usbgem_m_stop,
4029 usbgem_m_setpromisc,
4030 usbgem_m_multicst,
4031 usbgem_m_unicst,
4032 usbgem_m_tx,
4033 #ifdef _SYS_MAC_PROVIDER_H
4034 #ifdef MAC_VERSION_V1
4035 NULL,
4036 #endif
4037 #else
4038 NULL, /* m_resources */
4039 #endif
4040 usbgem_m_ioctl,
4041 NULL, /* m_getcapab */
4042 #ifdef USBGEM_CONFIG_MAC_PROP
4043 NULL,
4044 NULL,
4045 usbgem_m_setprop,
4046 usbgem_m_getprop,
4047 #endif
4048 #ifdef MAC_VERSION_V1
4049 usbgem_m_propinfo,
4050 #endif
4053 static int
4054 usbgem_m_start(void *arg)
4056 int ret;
4057 int err;
4058 struct usbgem_dev *dp = arg;
4060 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4062 err = EIO;
4064 rw_enter(&dp->dev_state_lock, RW_WRITER);
4065 dp->nic_state = NIC_STATE_ONLINE;
4067 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4068 err = 0;
4069 goto x;
4071 if (usbgem_mac_init(dp) != USB_SUCCESS) {
4072 goto x;
4075 /* initialize rx filter state */
4076 sema_p(&dp->rxfilter_lock);
4077 dp->mc_count = 0;
4078 dp->mc_count_req = 0;
4080 bcopy(dp->dev_addr.ether_addr_octet,
4081 dp->cur_addr.ether_addr_octet, ETHERADDRL);
4082 dp->rxmode |= RXMODE_ENABLE;
4084 ret = usbgem_hal_set_rx_filter(dp);
4085 sema_v(&dp->rxfilter_lock);
4087 if (ret != USB_SUCCESS) {
4088 goto x;
4091 if (dp->mii_state == MII_STATE_LINKUP) {
4092 /* setup media mode if the link have been up */
4093 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
4094 goto x;
4096 if (usbgem_mac_start(dp) != USB_SUCCESS) {
4097 goto x;
4101 err = 0;
4103 rw_exit(&dp->dev_state_lock);
4104 return (err);
4107 static void
4108 usbgem_m_stop(void *arg)
4110 struct usbgem_dev *dp = arg;
4112 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4114 /* stop rx gracefully */
4115 rw_enter(&dp->dev_state_lock, RW_READER);
4116 sema_p(&dp->rxfilter_lock);
4117 dp->rxmode &= ~RXMODE_ENABLE;
4119 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4120 (void) usbgem_hal_set_rx_filter(dp);
4122 sema_v(&dp->rxfilter_lock);
4123 rw_exit(&dp->dev_state_lock);
4125 /* make the nic state inactive */
4126 rw_enter(&dp->dev_state_lock, RW_WRITER);
4127 dp->nic_state = NIC_STATE_STOPPED;
4129 /* stop mac completely */
4130 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4131 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
4133 rw_exit(&dp->dev_state_lock);
4136 static int
4137 usbgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
4139 int err;
4140 int ret;
4141 struct usbgem_dev *dp = arg;
4143 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4145 rw_enter(&dp->dev_state_lock, RW_READER);
4146 if (add) {
4147 ret = usbgem_add_multicast(dp, ep);
4148 } else {
4149 ret = usbgem_remove_multicast(dp, ep);
4151 rw_exit(&dp->dev_state_lock);
4153 err = 0;
4154 if (ret != USB_SUCCESS) {
4155 #ifdef GEM_CONFIG_FMA
4156 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4157 #endif
4158 err = EIO;
4161 return (err);
4164 static int
4165 usbgem_m_setpromisc(void *arg, boolean_t on)
4167 int err;
4168 struct usbgem_dev *dp = arg;
4170 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4172 rw_enter(&dp->dev_state_lock, RW_READER);
4174 sema_p(&dp->rxfilter_lock);
4175 if (on) {
4176 dp->rxmode |= RXMODE_PROMISC;
4177 } else {
4178 dp->rxmode &= ~RXMODE_PROMISC;
4181 err = 0;
4182 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4183 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4184 err = EIO;
4187 sema_v(&dp->rxfilter_lock);
4189 rw_exit(&dp->dev_state_lock);
4191 #ifdef GEM_CONFIG_FMA
4192 if (err != 0) {
4193 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4195 #endif
4196 return (err);
4200 usbgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
4202 uint64_t val;
4203 struct usbgem_dev *dp = arg;
4204 struct usbgem_stats *gstp = &dp->stats;
4206 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4208 rw_enter(&dp->dev_state_lock, RW_READER);
4209 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4210 rw_exit(&dp->dev_state_lock);
4211 return (0);
4214 /* LINTED */
4215 if (usbgem_hal_get_stats(dp) != USB_SUCCESS) {
4216 #ifdef GEM_CONFIG_FMA
4217 rw_exit(&dp->dev_state_lock);
4218 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4219 return (EIO);
4220 #endif
4222 rw_exit(&dp->dev_state_lock);
4224 switch (stat) {
4225 case MAC_STAT_IFSPEED:
4226 val = usbgem_speed_value[dp->speed] *1000000ull;
4227 break;
4229 case MAC_STAT_MULTIRCV:
4230 val = gstp->rmcast;
4231 break;
4233 case MAC_STAT_BRDCSTRCV:
4234 val = gstp->rbcast;
4235 break;
4237 case MAC_STAT_MULTIXMT:
4238 val = gstp->omcast;
4239 break;
4241 case MAC_STAT_BRDCSTXMT:
4242 val = gstp->obcast;
4243 break;
4245 case MAC_STAT_NORCVBUF:
4246 val = gstp->norcvbuf + gstp->missed;
4247 break;
4249 case MAC_STAT_IERRORS:
4250 val = gstp->errrcv;
4251 break;
4253 case MAC_STAT_NOXMTBUF:
4254 val = gstp->noxmtbuf;
4255 break;
4257 case MAC_STAT_OERRORS:
4258 val = gstp->errxmt;
4259 break;
4261 case MAC_STAT_COLLISIONS:
4262 val = gstp->collisions;
4263 break;
4265 case MAC_STAT_RBYTES:
4266 val = gstp->rbytes;
4267 break;
4269 case MAC_STAT_IPACKETS:
4270 val = gstp->rpackets;
4271 break;
4273 case MAC_STAT_OBYTES:
4274 val = gstp->obytes;
4275 break;
4277 case MAC_STAT_OPACKETS:
4278 val = gstp->opackets;
4279 break;
4281 case MAC_STAT_UNDERFLOWS:
4282 val = gstp->underflow;
4283 break;
4285 case MAC_STAT_OVERFLOWS:
4286 val = gstp->overflow;
4287 break;
4289 case ETHER_STAT_ALIGN_ERRORS:
4290 val = gstp->frame;
4291 break;
4293 case ETHER_STAT_FCS_ERRORS:
4294 val = gstp->crc;
4295 break;
4297 case ETHER_STAT_FIRST_COLLISIONS:
4298 val = gstp->first_coll;
4299 break;
4301 case ETHER_STAT_MULTI_COLLISIONS:
4302 val = gstp->multi_coll;
4303 break;
4305 case ETHER_STAT_SQE_ERRORS:
4306 val = gstp->sqe;
4307 break;
4309 case ETHER_STAT_DEFER_XMTS:
4310 val = gstp->defer;
4311 break;
4313 case ETHER_STAT_TX_LATE_COLLISIONS:
4314 val = gstp->xmtlatecoll;
4315 break;
4317 case ETHER_STAT_EX_COLLISIONS:
4318 val = gstp->excoll;
4319 break;
4321 case ETHER_STAT_MACXMT_ERRORS:
4322 val = gstp->xmit_internal_err;
4323 break;
4325 case ETHER_STAT_CARRIER_ERRORS:
4326 val = gstp->nocarrier;
4327 break;
4329 case ETHER_STAT_TOOLONG_ERRORS:
4330 val = gstp->frame_too_long;
4331 break;
4333 case ETHER_STAT_MACRCV_ERRORS:
4334 val = gstp->rcv_internal_err;
4335 break;
4337 case ETHER_STAT_XCVR_ADDR:
4338 val = dp->mii_phy_addr;
4339 break;
4341 case ETHER_STAT_XCVR_ID:
4342 val = dp->mii_phy_id;
4343 break;
4345 case ETHER_STAT_XCVR_INUSE:
4346 val = usbgem_mac_xcvr_inuse(dp);
4347 break;
4349 case ETHER_STAT_CAP_1000FDX:
4350 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
4351 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
4352 break;
4354 case ETHER_STAT_CAP_1000HDX:
4355 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
4356 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
4357 break;
4359 case ETHER_STAT_CAP_100FDX:
4360 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
4361 break;
4363 case ETHER_STAT_CAP_100HDX:
4364 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
4365 break;
4367 case ETHER_STAT_CAP_10FDX:
4368 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
4369 break;
4371 case ETHER_STAT_CAP_10HDX:
4372 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
4373 break;
4375 case ETHER_STAT_CAP_ASMPAUSE:
4376 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
4377 break;
4379 case ETHER_STAT_CAP_PAUSE:
4380 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
4381 break;
4383 case ETHER_STAT_CAP_AUTONEG:
4384 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
4385 break;
4387 case ETHER_STAT_ADV_CAP_1000FDX:
4388 val = dp->anadv_1000fdx;
4389 break;
4391 case ETHER_STAT_ADV_CAP_1000HDX:
4392 val = dp->anadv_1000hdx;
4393 break;
4395 case ETHER_STAT_ADV_CAP_100FDX:
4396 val = dp->anadv_100fdx;
4397 break;
4399 case ETHER_STAT_ADV_CAP_100HDX:
4400 val = dp->anadv_100hdx;
4401 break;
4403 case ETHER_STAT_ADV_CAP_10FDX:
4404 val = dp->anadv_10fdx;
4405 break;
4407 case ETHER_STAT_ADV_CAP_10HDX:
4408 val = dp->anadv_10hdx;
4409 break;
4411 case ETHER_STAT_ADV_CAP_ASMPAUSE:
4412 val = dp->anadv_asmpause;
4413 break;
4415 case ETHER_STAT_ADV_CAP_PAUSE:
4416 val = dp->anadv_pause;
4417 break;
4419 case ETHER_STAT_ADV_CAP_AUTONEG:
4420 val = dp->anadv_autoneg;
4421 break;
4423 case ETHER_STAT_LP_CAP_1000FDX:
4424 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
4425 break;
4427 case ETHER_STAT_LP_CAP_1000HDX:
4428 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
4429 break;
4431 case ETHER_STAT_LP_CAP_100FDX:
4432 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
4433 break;
4435 case ETHER_STAT_LP_CAP_100HDX:
4436 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
4437 break;
4439 case ETHER_STAT_LP_CAP_10FDX:
4440 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
4441 break;
4443 case ETHER_STAT_LP_CAP_10HDX:
4444 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
4445 break;
4447 case ETHER_STAT_LP_CAP_ASMPAUSE:
4448 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
4449 break;
4451 case ETHER_STAT_LP_CAP_PAUSE:
4452 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
4453 break;
4455 case ETHER_STAT_LP_CAP_AUTONEG:
4456 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4457 break;
4459 case ETHER_STAT_LINK_ASMPAUSE:
4460 val = BOOLEAN(dp->flow_control & 2);
4461 break;
4463 case ETHER_STAT_LINK_PAUSE:
4464 val = BOOLEAN(dp->flow_control & 1);
4465 break;
4467 case ETHER_STAT_LINK_AUTONEG:
4468 val = dp->anadv_autoneg &&
4469 BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4470 break;
4472 case ETHER_STAT_LINK_DUPLEX:
4473 val = (dp->mii_state == MII_STATE_LINKUP) ?
4474 (dp->full_duplex ? 2 : 1) : 0;
4475 break;
4477 case ETHER_STAT_TOOSHORT_ERRORS:
4478 val = gstp->runt;
4479 break;
4480 #ifdef NEVER /* it doesn't make sense */
4481 case ETHER_STAT_CAP_REMFAULT:
4482 val = B_TRUE;
4483 break;
4485 case ETHER_STAT_ADV_REMFAULT:
4486 val = dp->anadv_remfault;
4487 break;
4488 #endif
4489 case ETHER_STAT_LP_REMFAULT:
4490 val = BOOLEAN(dp->mii_lpable & MII_AN_ADVERT_REMFAULT);
4491 break;
4493 case ETHER_STAT_JABBER_ERRORS:
4494 val = gstp->jabber;
4495 break;
4497 case ETHER_STAT_CAP_100T4:
4498 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
4499 break;
4501 case ETHER_STAT_ADV_CAP_100T4:
4502 val = dp->anadv_100t4;
4503 break;
4505 case ETHER_STAT_LP_CAP_100T4:
4506 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
4507 break;
4509 default:
4510 #if GEM_DEBUG_LEVEL > 2
4511 cmn_err(CE_WARN,
4512 "%s: unrecognized parameter value = %d",
4513 __func__, stat);
4514 #endif
4515 *valp = 0;
4516 return (ENOTSUP);
4519 *valp = val;
4521 return (0);
4524 static int
4525 usbgem_m_unicst(void *arg, const uint8_t *mac)
4527 int err;
4528 struct usbgem_dev *dp = arg;
4530 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4532 rw_enter(&dp->dev_state_lock, RW_READER);
4534 sema_p(&dp->rxfilter_lock);
4535 bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4536 dp->rxmode |= RXMODE_ENABLE;
4538 err = 0;
4539 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4540 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4541 err = EIO;
4544 sema_v(&dp->rxfilter_lock);
4545 rw_exit(&dp->dev_state_lock);
4547 #ifdef GEM_CONFIG_FMA
4548 if (err != 0) {
4549 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4551 #endif
4552 return (err);
4556 * usbgem_m_tx is used only for sending data packets into ethernet wire.
4558 static mblk_t *
4559 usbgem_m_tx(void *arg, mblk_t *mp_head)
4561 int limit;
4562 mblk_t *mp;
4563 mblk_t *nmp;
4564 struct usbgem_dev *dp = arg;
4566 DPRINTF(4, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4568 mp = mp_head;
4570 rw_enter(&dp->dev_state_lock, RW_READER);
4572 if (dp->mii_state != MII_STATE_LINKUP ||
4573 dp->mac_state != MAC_STATE_ONLINE) {
4574 /* some nics hate to send packets during the link is down */
4575 for (; mp; mp = nmp) {
4576 nmp = mp->b_next;
4577 mp->b_next = NULL;
4578 freemsg(mp);
4580 goto x;
4583 ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4585 limit = dp->tx_max_packets;
4586 for (; limit-- && mp; mp = nmp) {
4587 nmp = mp->b_next;
4588 mp->b_next = NULL;
4589 if (usbgem_send_common(dp, mp,
4590 (limit == 0 && nmp) ? 1 : 0)) {
4591 mp->b_next = nmp;
4592 break;
4595 #ifdef CONFIG_TX_LIMITER
4596 if (mp == mp_head) {
4597 /* no packets were sent, descrease allocation limit */
4598 mutex_enter(&dp->txlock);
4599 dp->tx_max_packets = max(dp->tx_max_packets - 1, 1);
4600 mutex_exit(&dp->txlock);
4602 #endif
4604 rw_exit(&dp->dev_state_lock);
4606 return (mp);
4609 static void
4610 usbgem_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4612 struct usbgem_dev *dp = arg;
4614 DPRINTF(1, (CE_CONT, "!%s: %s: called",
4615 ((struct usbgem_dev *)arg)->name, __func__));
4617 rw_enter(&dp->dev_state_lock, RW_READER);
4618 usbgem_mac_ioctl((struct usbgem_dev *)arg, wq, mp);
4619 rw_exit(&dp->dev_state_lock);
4622 static void
4623 usbgem_gld3_init(struct usbgem_dev *dp, mac_register_t *macp)
4625 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4626 macp->m_driver = dp;
4627 macp->m_dip = dp->dip;
4628 macp->m_src_addr = dp->dev_addr.ether_addr_octet;
4629 macp->m_callbacks = &gem_m_callbacks;
4630 macp->m_min_sdu = 0;
4631 macp->m_max_sdu = dp->mtu;
4633 if (dp->misc_flag & USBGEM_VLAN) {
4634 macp->m_margin = VTAG_SIZE;
4637 #else
4638 /* ============================================================== */
4640 * GLDv2 interface
4642 /* ============================================================== */
4643 static int usbgem_gld_reset(gld_mac_info_t *);
4644 static int usbgem_gld_start(gld_mac_info_t *);
4645 static int usbgem_gld_stop(gld_mac_info_t *);
4646 static int usbgem_gld_set_mac_address(gld_mac_info_t *, uint8_t *);
4647 static int usbgem_gld_set_multicast(gld_mac_info_t *, uint8_t *, int);
4648 static int usbgem_gld_set_promiscuous(gld_mac_info_t *, int);
4649 static int usbgem_gld_get_stats(gld_mac_info_t *, struct gld_stats *);
4650 static int usbgem_gld_send(gld_mac_info_t *, mblk_t *);
4651 static int usbgem_gld_send_tagged(gld_mac_info_t *, mblk_t *, uint32_t);
4653 static int
4654 usbgem_gld_reset(gld_mac_info_t *macinfo)
4656 int err;
4657 struct usbgem_dev *dp;
4659 err = GLD_SUCCESS;
4660 dp = (struct usbgem_dev *)macinfo->gldm_private;
4662 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4664 rw_enter(&dp->dev_state_lock, RW_WRITER);
4665 if (usbgem_mac_init(dp) != USB_SUCCESS) {
4666 err = GLD_FAILURE;
4667 goto x;
4670 dp->nic_state = NIC_STATE_INITIALIZED;
4672 /* setup media mode if the link have been up */
4673 if (dp->mii_state == MII_STATE_LINKUP) {
4674 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4675 (void) usbgem_hal_set_media(dp);
4679 rw_exit(&dp->dev_state_lock);
4680 return (err);
4683 static int
4684 usbgem_gld_start(gld_mac_info_t *macinfo)
4686 int err;
4687 struct usbgem_dev *dp;
4689 dp = (struct usbgem_dev *)macinfo->gldm_private;
4691 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4693 rw_enter(&dp->dev_state_lock, RW_WRITER);
4695 dp->nic_state = NIC_STATE_ONLINE;
4697 if (dp->mii_state == MII_STATE_LINKUP) {
4698 if (usbgem_mac_start(dp) != USB_SUCCESS) {
4699 /* sema_v(&dp->mii_lock); */
4700 err = GLD_FAILURE;
4701 goto x;
4706 * XXX - don't call gld_linkstate() here,
4707 * otherwise it cause recursive mutex call.
4709 err = GLD_SUCCESS;
4711 rw_exit(&dp->dev_state_lock);
4713 return (err);
4716 static int
4717 usbgem_gld_stop(gld_mac_info_t *macinfo)
4719 int err = GLD_SUCCESS;
4720 struct usbgem_dev *dp;
4722 dp = (struct usbgem_dev *)macinfo->gldm_private;
4724 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4726 /* try to stop rx gracefully */
4727 rw_enter(&dp->dev_state_lock, RW_READER);
4728 sema_p(&dp->rxfilter_lock);
4729 dp->rxmode &= ~RXMODE_ENABLE;
4731 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4732 (void) usbgem_hal_set_rx_filter(dp);
4734 sema_v(&dp->rxfilter_lock);
4735 rw_exit(&dp->dev_state_lock);
4737 /* make the nic state inactive */
4738 rw_enter(&dp->dev_state_lock, RW_WRITER);
4739 dp->nic_state = NIC_STATE_STOPPED;
4741 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4742 if (usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL)
4743 != USB_SUCCESS) {
4744 err = GLD_FAILURE;
4747 rw_exit(&dp->dev_state_lock);
4749 return (err);
4752 static int
4753 usbgem_gld_set_multicast(gld_mac_info_t *macinfo, uint8_t *ep, int flag)
4755 int err;
4756 int ret;
4757 struct usbgem_dev *dp;
4759 dp = (struct usbgem_dev *)macinfo->gldm_private;
4761 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4763 rw_enter(&dp->dev_state_lock, RW_READER);
4764 if (flag == GLD_MULTI_ENABLE) {
4765 ret = usbgem_add_multicast(dp, ep);
4766 } else {
4767 ret = usbgem_remove_multicast(dp, ep);
4769 rw_exit(&dp->dev_state_lock);
4771 err = GLD_SUCCESS;
4772 if (ret != USB_SUCCESS) {
4773 #ifdef GEM_CONFIG_FMA
4774 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4775 #endif
4776 err = GLD_FAILURE;
4778 return (err);
4781 static int
4782 usbgem_gld_set_promiscuous(gld_mac_info_t *macinfo, int flag)
4784 boolean_t need_to_change = B_TRUE;
4785 struct usbgem_dev *dp;
4787 dp = (struct usbgem_dev *)macinfo->gldm_private;
4789 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4791 sema_p(&dp->rxfilter_lock);
4792 if (flag == GLD_MAC_PROMISC_NONE) {
4793 dp->rxmode &= ~(RXMODE_PROMISC | RXMODE_ALLMULTI_REQ);
4794 } else if (flag == GLD_MAC_PROMISC_MULTI) {
4795 dp->rxmode |= RXMODE_ALLMULTI_REQ;
4796 } else if (flag == GLD_MAC_PROMISC_PHYS) {
4797 dp->rxmode |= RXMODE_PROMISC;
4798 } else {
4799 /* mode unchanged */
4800 need_to_change = B_FALSE;
4803 if (need_to_change) {
4804 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4805 (void) usbgem_hal_set_rx_filter(dp);
4808 sema_v(&dp->rxfilter_lock);
4810 return (GLD_SUCCESS);
4813 static int
4814 usbgem_gld_set_mac_address(gld_mac_info_t *macinfo, uint8_t *mac)
4816 struct usbgem_dev *dp;
4817 dp = (struct usbgem_dev *)macinfo->gldm_private;
4819 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4821 sema_p(&dp->rxfilter_lock);
4822 bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4823 dp->rxmode |= RXMODE_ENABLE;
4825 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4826 (void) usbgem_hal_set_rx_filter(dp);
4828 sema_v(&dp->rxfilter_lock);
4830 return (GLD_SUCCESS);
4833 static int
4834 usbgem_gld_get_stats(gld_mac_info_t *macinfo, struct gld_stats *gs)
4836 struct usbgem_dev *dp;
4837 struct usbgem_stats *vs;
4839 dp = (struct usbgem_dev *)macinfo->gldm_private;
4841 if ((*dp->ugc.usbgc_get_stats)(dp) != USB_SUCCESS) {
4842 #ifdef GEM_CONFIG_FMA
4843 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4844 #endif
4845 return (USB_FAILURE);
4848 vs = &dp->stats;
4850 gs->glds_errxmt = vs->errxmt;
4851 gs->glds_errrcv = vs->errrcv;
4852 gs->glds_collisions = vs->collisions;
4854 gs->glds_excoll = vs->excoll;
4855 gs->glds_defer = vs->defer;
4856 gs->glds_frame = vs->frame;
4857 gs->glds_crc = vs->crc;
4859 gs->glds_overflow = vs->overflow; /* fifo err,underrun,rbufovf */
4860 gs->glds_underflow = vs->underflow;
4861 gs->glds_short = vs->runt;
4862 gs->glds_missed = vs->missed; /* missed pkts while rbuf ovf */
4863 gs->glds_xmtlatecoll = vs->xmtlatecoll;
4864 gs->glds_nocarrier = vs->nocarrier;
4865 gs->glds_norcvbuf = vs->norcvbuf; /* OS resource exaust */
4866 gs->glds_intr = vs->intr;
4868 /* all before here must be kept in place for v0 compatibility */
4869 gs->glds_speed = usbgem_speed_value[dp->speed] * 1000000;
4870 gs->glds_media = GLDM_PHYMII;
4871 gs->glds_duplex = dp->full_duplex ? GLD_DUPLEX_FULL : GLD_DUPLEX_HALF;
4873 /* gs->glds_media_specific */
4874 gs->glds_dot3_first_coll = vs->first_coll;
4875 gs->glds_dot3_multi_coll = vs->multi_coll;
4876 gs->glds_dot3_sqe_error = 0;
4877 gs->glds_dot3_mac_xmt_error = 0;
4878 gs->glds_dot3_mac_rcv_error = 0;
4879 gs->glds_dot3_frame_too_long = vs->frame_too_long;
4881 return (GLD_SUCCESS);
4884 static int
4885 usbgem_gld_ioctl(gld_mac_info_t *macinfo, queue_t *wq, mblk_t *mp)
4887 struct usbgem_dev *dp;
4889 dp = (struct usbgem_dev *)macinfo->gldm_private;
4890 usbgem_mac_ioctl(dp, wq, mp);
4892 return (GLD_SUCCESS);
4896 * gem_gld_send is used only for sending data packets into ethernet wire.
4898 static int
4899 usbgem_gld_send(gld_mac_info_t *macinfo, mblk_t *mp)
4901 int ret;
4902 uint32_t flags = 0;
4903 struct usbgem_dev *dp;
4905 dp = (struct usbgem_dev *)macinfo->gldm_private;
4907 /* nic state must be online of suspended */
4908 rw_enter(&dp->dev_state_lock, RW_READER);
4910 ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4911 ASSERT(mp->b_next == NULL);
4913 if (dp->mii_state != MII_STATE_LINKUP) {
4914 /* Some nics hate to send packets while the link is down. */
4915 /* we discard the untransmitted packets silently */
4916 rw_exit(&dp->dev_state_lock);
4918 freemsg(mp);
4919 #ifdef GEM_CONFIG_FMA
4920 /* FIXME - should we ignore the error? */
4921 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4922 #endif
4923 return (GLD_SUCCESS);
4926 ret = (usbgem_send_common(dp, mp, flags) == NULL)
4927 ? GLD_SUCCESS : GLD_NORESOURCES;
4928 rw_exit(&dp->dev_state_lock);
4930 return (ret);
4934 * usbgem_gld_send is used only for sending data packets into ethernet wire.
4936 static int
4937 usbgem_gld_send_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
4939 uint32_t flags;
4940 struct usbgem_dev *dp;
4942 dp = (struct usbgem_dev *)macinfo->gldm_private;
4945 * Some nics hate to send packets while the link is down.
4947 if (dp->mii_state != MII_STATE_LINKUP) {
4948 /* we dicard the untransmitted packets silently */
4949 freemsg(mp);
4950 #ifdef GEM_CONFIG_FMA
4951 /* FIXME - should we ignore the error? */
4952 ddi_fm_service_impact(dp->dip, DDI_SERVICE_UNAFFECTED);
4953 #endif
4954 return (GLD_SUCCESS);
4956 #ifdef notyet
4957 flags = GLD_VTAG_TCI(vtag) << GEM_SEND_VTAG_SHIFT;
4958 #endif
4959 return ((usbgem_send_common(dp, mp, 0) == NULL) ?
4960 GLD_SUCCESS : GLD_NORESOURCES);
4963 static void
4964 usbgem_gld_init(struct usbgem_dev *dp, gld_mac_info_t *macinfo, char *ident)
4967 * configure GLD
4969 macinfo->gldm_devinfo = dp->dip;
4970 macinfo->gldm_private = (caddr_t)dp;
4972 macinfo->gldm_reset = usbgem_gld_reset;
4973 macinfo->gldm_start = usbgem_gld_start;
4974 macinfo->gldm_stop = usbgem_gld_stop;
4975 macinfo->gldm_set_mac_addr = usbgem_gld_set_mac_address;
4976 macinfo->gldm_send = usbgem_gld_send;
4977 macinfo->gldm_set_promiscuous = usbgem_gld_set_promiscuous;
4978 macinfo->gldm_get_stats = usbgem_gld_get_stats;
4979 macinfo->gldm_ioctl = usbgem_gld_ioctl;
4980 macinfo->gldm_set_multicast = usbgem_gld_set_multicast;
4981 macinfo->gldm_intr = NULL;
4982 macinfo->gldm_mctl = NULL;
4984 macinfo->gldm_ident = ident;
4985 macinfo->gldm_type = DL_ETHER;
4986 macinfo->gldm_minpkt = 0;
4987 macinfo->gldm_maxpkt = dp->mtu;
4988 macinfo->gldm_addrlen = ETHERADDRL;
4989 macinfo->gldm_saplen = -2;
4990 macinfo->gldm_ppa = ddi_get_instance(dp->dip);
4991 #ifdef GLD_CAP_LINKSTATE
4992 macinfo->gldm_capabilities = GLD_CAP_LINKSTATE;
4993 #endif
4994 macinfo->gldm_vendor_addr = dp->dev_addr.ether_addr_octet;
4995 macinfo->gldm_broadcast_addr = usbgem_bcastaddr;
4997 #endif /* USBGEM_CONFIG_GLDv3 */
5000 /* ======================================================================== */
5002 * .conf interface
5004 /* ======================================================================== */
5005 void
5006 usbgem_generate_macaddr(struct usbgem_dev *dp, uint8_t *mac)
5008 extern char hw_serial[];
5009 char *hw_serial_p;
5010 int i;
5011 uint64_t val;
5012 uint64_t key;
5014 cmn_err(CE_NOTE,
5015 "!%s: using temp ether address,"
5016 " do not use this for long time",
5017 dp->name);
5019 /* prefer a fixed address for DHCP */
5020 hw_serial_p = &hw_serial[0];
5021 val = stoi(&hw_serial_p);
5023 key = 0;
5024 for (i = 0; i < USBGEM_NAME_LEN; i++) {
5025 if (dp->name[i] == 0) {
5026 break;
5028 key ^= dp->name[i];
5030 key ^= ddi_get_instance(dp->dip);
5031 val ^= key << 32;
5033 /* generate a local address */
5034 mac[0] = 0x02;
5035 mac[1] = (uint8_t)(val >> 32);
5036 mac[2] = (uint8_t)(val >> 24);
5037 mac[3] = (uint8_t)(val >> 16);
5038 mac[4] = (uint8_t)(val >> 8);
5039 mac[5] = (uint8_t)val;
5042 boolean_t
5043 usbgem_get_mac_addr_conf(struct usbgem_dev *dp)
5045 char propname[32];
5046 char *valstr;
5047 uint8_t mac[ETHERADDRL];
5048 char *cp;
5049 int c;
5050 int i;
5051 int j;
5052 uint8_t v;
5053 uint8_t d;
5054 uint8_t ored;
5056 DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5058 * Get ethernet address from .conf file
5060 (void) sprintf(propname, "mac-addr");
5061 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dp->dip,
5062 DDI_PROP_DONTPASS, propname, &valstr)) != DDI_PROP_SUCCESS) {
5063 return (B_FALSE);
5066 if (strlen(valstr) != ETHERADDRL*3-1) {
5067 goto syntax_err;
5070 cp = valstr;
5071 j = 0;
5072 ored = 0;
5073 for (;;) {
5074 v = 0;
5075 for (i = 0; i < 2; i++) {
5076 c = *cp++;
5078 if (c >= 'a' && c <= 'f') {
5079 d = c - 'a' + 10;
5080 } else if (c >= 'A' && c <= 'F') {
5081 d = c - 'A' + 10;
5082 } else if (c >= '0' && c <= '9') {
5083 d = c - '0';
5084 } else {
5085 goto syntax_err;
5087 v = (v << 4) | d;
5090 mac[j++] = v;
5091 ored |= v;
5092 if (j == ETHERADDRL) {
5093 /* done */
5094 break;
5097 c = *cp++;
5098 if (c != ':') {
5099 goto syntax_err;
5103 if (ored == 0) {
5104 usbgem_generate_macaddr(dp, mac);
5106 for (i = 0; i < ETHERADDRL; i++) {
5107 dp->dev_addr.ether_addr_octet[i] = mac[i];
5109 ddi_prop_free(valstr);
5110 return (B_TRUE);
5112 syntax_err:
5113 cmn_err(CE_CONT,
5114 "!%s: read mac addr: trying .conf: syntax err %s",
5115 dp->name, valstr);
5116 ddi_prop_free(valstr);
5118 return (B_FALSE);
5121 static void
5122 usbgem_read_conf(struct usbgem_dev *dp)
5124 int val;
5126 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5129 * Get media mode infomation from .conf file
5131 dp->anadv_autoneg = usbgem_prop_get_int(dp, "adv_autoneg_cap", 1) != 0;
5132 dp->anadv_1000fdx = usbgem_prop_get_int(dp, "adv_1000fdx_cap", 1) != 0;
5133 dp->anadv_1000hdx = usbgem_prop_get_int(dp, "adv_1000hdx_cap", 1) != 0;
5134 dp->anadv_100t4 = usbgem_prop_get_int(dp, "adv_100T4_cap", 1) != 0;
5135 dp->anadv_100fdx = usbgem_prop_get_int(dp, "adv_100fdx_cap", 1) != 0;
5136 dp->anadv_100hdx = usbgem_prop_get_int(dp, "adv_100hdx_cap", 1) != 0;
5137 dp->anadv_10fdx = usbgem_prop_get_int(dp, "adv_10fdx_cap", 1) != 0;
5138 dp->anadv_10hdx = usbgem_prop_get_int(dp, "adv_10hdx_cap", 1) != 0;
5139 dp->anadv_1000t_ms = usbgem_prop_get_int(dp, "adv_1000t_ms", 0);
5141 if ((ddi_prop_exists(DDI_DEV_T_ANY, dp->dip,
5142 DDI_PROP_DONTPASS, "full-duplex"))) {
5143 dp->full_duplex =
5144 usbgem_prop_get_int(dp, "full-duplex", 1) != 0;
5145 dp->anadv_autoneg = B_FALSE;
5146 if (dp->full_duplex) {
5147 dp->anadv_1000hdx = B_FALSE;
5148 dp->anadv_100hdx = B_FALSE;
5149 dp->anadv_10hdx = B_FALSE;
5150 } else {
5151 dp->anadv_1000fdx = B_FALSE;
5152 dp->anadv_100fdx = B_FALSE;
5153 dp->anadv_10fdx = B_FALSE;
5157 if ((val = usbgem_prop_get_int(dp, "speed", 0)) > 0) {
5158 dp->anadv_autoneg = B_FALSE;
5159 switch (val) {
5160 case 1000:
5161 dp->speed = USBGEM_SPD_1000;
5162 dp->anadv_100t4 = B_FALSE;
5163 dp->anadv_100fdx = B_FALSE;
5164 dp->anadv_100hdx = B_FALSE;
5165 dp->anadv_10fdx = B_FALSE;
5166 dp->anadv_10hdx = B_FALSE;
5167 break;
5168 case 100:
5169 dp->speed = USBGEM_SPD_100;
5170 dp->anadv_1000fdx = B_FALSE;
5171 dp->anadv_1000hdx = B_FALSE;
5172 dp->anadv_10fdx = B_FALSE;
5173 dp->anadv_10hdx = B_FALSE;
5174 break;
5175 case 10:
5176 dp->speed = USBGEM_SPD_10;
5177 dp->anadv_1000fdx = B_FALSE;
5178 dp->anadv_1000hdx = B_FALSE;
5179 dp->anadv_100t4 = B_FALSE;
5180 dp->anadv_100fdx = B_FALSE;
5181 dp->anadv_100hdx = B_FALSE;
5182 break;
5183 default:
5184 cmn_err(CE_WARN,
5185 "!%s: property %s: illegal value:%d",
5186 dp->name, "speed", val);
5187 dp->anadv_autoneg = B_TRUE;
5188 break;
5191 val = usbgem_prop_get_int(dp,
5192 "adv_pause", dp->ugc.usbgc_flow_control & 1);
5193 val |= usbgem_prop_get_int(dp,
5194 "adv_asmpause", BOOLEAN(dp->ugc.usbgc_flow_control & 2)) << 1;
5195 if (val > FLOW_CONTROL_RX_PAUSE || val < FLOW_CONTROL_NONE) {
5196 cmn_err(CE_WARN,
5197 "!%s: property %s: illegal value:%d",
5198 dp->name, "flow-control", val);
5199 } else {
5200 val = min(val, dp->ugc.usbgc_flow_control);
5202 dp->anadv_pause = BOOLEAN(val & 1);
5203 dp->anadv_asmpause = BOOLEAN(val & 2);
5205 dp->mtu = usbgem_prop_get_int(dp, "mtu", dp->mtu);
5206 dp->txthr = usbgem_prop_get_int(dp, "txthr", dp->txthr);
5207 dp->rxthr = usbgem_prop_get_int(dp, "rxthr", dp->rxthr);
5208 dp->txmaxdma = usbgem_prop_get_int(dp, "txmaxdma", dp->txmaxdma);
5209 dp->rxmaxdma = usbgem_prop_get_int(dp, "rxmaxdma", dp->rxmaxdma);
5210 #ifdef GEM_CONFIG_POLLING
5211 dp->poll_pkt_delay =
5212 usbgem_prop_get_int(dp, "pkt_delay", dp->poll_pkt_delay);
5214 dp->max_poll_interval[GEM_SPD_10] =
5215 usbgem_prop_get_int(dp, "max_poll_interval_10",
5216 dp->max_poll_interval[GEM_SPD_10]);
5217 dp->max_poll_interval[GEM_SPD_100] =
5218 usbgem_prop_get_int(dp, "max_poll_interval_100",
5219 dp->max_poll_interval[GEM_SPD_100]);
5220 dp->max_poll_interval[GEM_SPD_1000] =
5221 usbgem_prop_get_int(dp, "max_poll_interval_1000",
5222 dp->max_poll_interval[GEM_SPD_1000]);
5224 dp->min_poll_interval[GEM_SPD_10] =
5225 usbgem_prop_get_int(dp, "min_poll_interval_10",
5226 dp->min_poll_interval[GEM_SPD_10]);
5227 dp->min_poll_interval[GEM_SPD_100] =
5228 usbgem_prop_get_int(dp, "min_poll_interval_100",
5229 dp->min_poll_interval[GEM_SPD_100]);
5230 dp->min_poll_interval[GEM_SPD_1000] =
5231 usbgem_prop_get_int(dp, "min_poll_interval_1000",
5232 dp->min_poll_interval[GEM_SPD_1000]);
5233 #endif
5237 * usbem kstat support
5239 #ifndef GEM_CONFIG_GLDv3
5240 /* kstat items based from dmfe driver */
5242 struct usbgem_kstat_named {
5243 struct kstat_named ks_xcvr_addr;
5244 struct kstat_named ks_xcvr_id;
5245 struct kstat_named ks_xcvr_inuse;
5246 struct kstat_named ks_link_up;
5247 struct kstat_named ks_link_duplex; /* 0:unknwon, 1:half, 2:full */
5248 struct kstat_named ks_cap_1000fdx;
5249 struct kstat_named ks_cap_1000hdx;
5250 struct kstat_named ks_cap_100fdx;
5251 struct kstat_named ks_cap_100hdx;
5252 struct kstat_named ks_cap_10fdx;
5253 struct kstat_named ks_cap_10hdx;
5254 #ifdef NEVER
5255 struct kstat_named ks_cap_remfault;
5256 #endif
5257 struct kstat_named ks_cap_autoneg;
5259 struct kstat_named ks_adv_cap_1000fdx;
5260 struct kstat_named ks_adv_cap_1000hdx;
5261 struct kstat_named ks_adv_cap_100fdx;
5262 struct kstat_named ks_adv_cap_100hdx;
5263 struct kstat_named ks_adv_cap_10fdx;
5264 struct kstat_named ks_adv_cap_10hdx;
5265 #ifdef NEVER
5266 struct kstat_named ks_adv_cap_remfault;
5267 #endif
5268 struct kstat_named ks_adv_cap_autoneg;
5269 struct kstat_named ks_lp_cap_1000fdx;
5270 struct kstat_named ks_lp_cap_1000hdx;
5271 struct kstat_named ks_lp_cap_100fdx;
5272 struct kstat_named ks_lp_cap_100hdx;
5273 struct kstat_named ks_lp_cap_10fdx;
5274 struct kstat_named ks_lp_cap_10hdx;
5275 struct kstat_named ks_lp_cap_remfault;
5276 struct kstat_named ks_lp_cap_autoneg;
5279 static int
5280 usbgem_kstat_update(kstat_t *ksp, int rw)
5282 struct usbgem_kstat_named *knp;
5283 struct usbgem_dev *dp = (struct usbgem_dev *)ksp->ks_private;
5285 if (rw != KSTAT_READ) {
5286 return (0);
5289 knp = (struct usbgem_kstat_named *)ksp->ks_data;
5291 knp->ks_xcvr_addr.value.ul = dp->mii_phy_addr;
5292 knp->ks_xcvr_id.value.ul = dp->mii_phy_id;
5293 knp->ks_xcvr_inuse.value.ul = usbgem_mac_xcvr_inuse(dp);
5294 knp->ks_link_up.value.ul = dp->mii_state == MII_STATE_LINKUP;
5295 knp->ks_link_duplex.value.ul =
5296 (dp->mii_state == MII_STATE_LINKUP) ?
5297 (dp->full_duplex ? 2 : 1) : 0;
5299 knp->ks_cap_1000fdx.value.ul =
5300 (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
5301 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
5302 knp->ks_cap_1000hdx.value.ul =
5303 (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
5304 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
5305 knp->ks_cap_100fdx.value.ul =
5306 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
5307 knp->ks_cap_100hdx.value.ul =
5308 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
5309 knp->ks_cap_10fdx.value.ul =
5310 BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
5311 knp->ks_cap_10hdx.value.ul =
5312 BOOLEAN(dp->mii_status & MII_STATUS_10);
5313 #ifdef NEVER
5314 knp->ks_cap_remfault.value.ul = B_TRUE;
5315 #endif
5316 knp->ks_cap_autoneg.value.ul =
5317 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
5319 knp->ks_adv_cap_1000fdx.value.ul = dp->anadv_1000fdx;
5320 knp->ks_adv_cap_1000hdx.value.ul = dp->anadv_1000hdx;
5321 knp->ks_adv_cap_100fdx.value.ul = dp->anadv_100fdx;
5322 knp->ks_adv_cap_100hdx.value.ul = dp->anadv_100hdx;
5323 knp->ks_adv_cap_10fdx.value.ul = dp->anadv_10fdx;
5324 knp->ks_adv_cap_10hdx.value.ul = dp->anadv_10hdx;
5325 #ifdef NEVER
5326 knp->ks_adv_cap_remfault.value.ul = 0;
5327 #endif
5328 knp->ks_adv_cap_autoneg.value.ul = dp->anadv_autoneg;
5330 knp->ks_lp_cap_1000fdx.value.ul =
5331 BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
5332 knp->ks_lp_cap_1000hdx.value.ul =
5333 BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
5334 knp->ks_lp_cap_100fdx.value.ul =
5335 BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
5336 knp->ks_lp_cap_100hdx.value.ul =
5337 BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
5338 knp->ks_lp_cap_10fdx.value.ul =
5339 BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
5340 knp->ks_lp_cap_10hdx.value.ul =
5341 BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
5342 knp->ks_lp_cap_remfault.value.ul =
5343 BOOLEAN(dp->mii_exp & MII_AN_EXP_PARFAULT);
5344 knp->ks_lp_cap_autoneg.value.ul =
5345 BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
5347 return (0);
5351 static int
5352 usbgem_kstat_init(struct usbgem_dev *dp)
5354 int i;
5355 kstat_t *ksp;
5356 struct usbgem_kstat_named *knp;
5358 ksp = kstat_create(
5359 (char *)ddi_driver_name(dp->dip), ddi_get_instance(dp->dip),
5360 "mii", "net", KSTAT_TYPE_NAMED,
5361 sizeof (*knp) / sizeof (knp->ks_xcvr_addr), 0);
5363 if (ksp == NULL) {
5364 cmn_err(CE_WARN, "%s: %s() for mii failed",
5365 dp->name, __func__);
5366 return (USB_FAILURE);
5369 knp = (struct usbgem_kstat_named *)ksp->ks_data;
5371 kstat_named_init(&knp->ks_xcvr_addr, "xcvr_addr",
5372 KSTAT_DATA_INT32);
5373 kstat_named_init(&knp->ks_xcvr_id, "xcvr_id",
5374 KSTAT_DATA_UINT32);
5375 kstat_named_init(&knp->ks_xcvr_inuse, "xcvr_inuse",
5376 KSTAT_DATA_UINT32);
5377 kstat_named_init(&knp->ks_link_up, "link_up",
5378 KSTAT_DATA_UINT32);
5379 kstat_named_init(&knp->ks_link_duplex, "link_duplex",
5380 KSTAT_DATA_UINT32);
5381 kstat_named_init(&knp->ks_cap_1000fdx, "cap_1000fdx",
5382 KSTAT_DATA_UINT32);
5383 kstat_named_init(&knp->ks_cap_1000hdx, "cap_1000hdx",
5384 KSTAT_DATA_UINT32);
5385 kstat_named_init(&knp->ks_cap_100fdx, "cap_100fdx",
5386 KSTAT_DATA_UINT32);
5387 kstat_named_init(&knp->ks_cap_100hdx, "cap_100hdx",
5388 KSTAT_DATA_UINT32);
5389 kstat_named_init(&knp->ks_cap_10fdx, "cap_10fdx",
5390 KSTAT_DATA_UINT32);
5391 kstat_named_init(&knp->ks_cap_10hdx, "cap_10hdx",
5392 KSTAT_DATA_UINT32);
5393 #ifdef NEVER
5394 kstat_named_init(&knp->ks_cap_remfault, "cap_rem_fault",
5395 KSTAT_DATA_UINT32);
5396 #endif
5397 kstat_named_init(&knp->ks_cap_autoneg, "cap_autoneg",
5398 KSTAT_DATA_UINT32);
5399 kstat_named_init(&knp->ks_adv_cap_1000fdx, "adv_cap_1000fdx",
5400 KSTAT_DATA_UINT32);
5401 kstat_named_init(&knp->ks_adv_cap_1000hdx, "adv_cap_1000hdx",
5402 KSTAT_DATA_UINT32);
5403 kstat_named_init(&knp->ks_adv_cap_100fdx, "adv_cap_100fdx",
5404 KSTAT_DATA_UINT32);
5405 kstat_named_init(&knp->ks_adv_cap_100hdx, "adv_cap_100hdx",
5406 KSTAT_DATA_UINT32);
5407 kstat_named_init(&knp->ks_adv_cap_10fdx, "adv_cap_10fdx",
5408 KSTAT_DATA_UINT32);
5409 kstat_named_init(&knp->ks_adv_cap_10hdx, "adv_cap_10hdx",
5410 KSTAT_DATA_UINT32);
5411 #ifdef NEVER
5412 kstat_named_init(&knp->ks_adv_cap_remfault, "adv_rem_fault",
5413 KSTAT_DATA_UINT32);
5414 #endif
5415 kstat_named_init(&knp->ks_adv_cap_autoneg, "adv_cap_autoneg",
5416 KSTAT_DATA_UINT32);
5418 kstat_named_init(&knp->ks_lp_cap_1000fdx, "lp_cap_1000fdx",
5419 KSTAT_DATA_UINT32);
5420 kstat_named_init(&knp->ks_lp_cap_1000hdx, "lp_cap_1000hdx",
5421 KSTAT_DATA_UINT32);
5422 kstat_named_init(&knp->ks_lp_cap_100fdx, "lp_cap_100fdx",
5423 KSTAT_DATA_UINT32);
5424 kstat_named_init(&knp->ks_lp_cap_100hdx, "lp_cap_100hdx",
5425 KSTAT_DATA_UINT32);
5426 kstat_named_init(&knp->ks_lp_cap_10fdx, "lp_cap_10fdx",
5427 KSTAT_DATA_UINT32);
5428 kstat_named_init(&knp->ks_lp_cap_10hdx, "lp_cap_10hdx",
5429 KSTAT_DATA_UINT32);
5430 kstat_named_init(&knp->ks_lp_cap_remfault, "lp_cap_rem_fault",
5431 KSTAT_DATA_UINT32);
5432 kstat_named_init(&knp->ks_lp_cap_autoneg, "lp_cap_autoneg",
5433 KSTAT_DATA_UINT32);
5435 ksp->ks_private = (void *) dp;
5436 ksp->ks_update = usbgem_kstat_update;
5437 dp->ksp = ksp;
5439 kstat_install(ksp);
5441 return (USB_SUCCESS);
5443 #endif /* GEM_CONFIG_GLDv3 */
5444 /* ======================================================================== */
5446 * attach/detatch/usb support
5448 /* ======================================================================== */
5450 usbgem_ctrl_out(struct usbgem_dev *dp,
5451 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5452 void *bp, int size)
5454 mblk_t *data;
5455 usb_ctrl_setup_t setup;
5456 usb_cr_t completion_reason;
5457 usb_cb_flags_t cb_flags;
5458 usb_flags_t flags;
5459 int i;
5460 int ret;
5462 DPRINTF(4, (CE_CONT, "!%s: %s "
5463 "reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x "
5464 "bp:0x%p nic_state:%d",
5465 dp->name, __func__, reqt, req, val, ix, len, bp, dp->nic_state));
5467 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5468 return (USB_PIPE_ERROR);
5471 data = NULL;
5472 if (size > 0) {
5473 if ((data = allocb(size, 0)) == NULL) {
5474 return (USB_FAILURE);
5477 bcopy(bp, data->b_rptr, size);
5478 data->b_wptr = data->b_rptr + size;
5481 setup.bmRequestType = reqt;
5482 setup.bRequest = req;
5483 setup.wValue = val;
5484 setup.wIndex = ix;
5485 setup.wLength = len;
5486 setup.attrs = 0; /* attributes */
5488 for (i = usbgem_ctrl_retry; i > 0; i--) {
5489 completion_reason = 0;
5490 cb_flags = 0;
5492 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp),
5493 &setup, &data, &completion_reason, &cb_flags, 0);
5495 if (ret == USB_SUCCESS) {
5496 break;
5498 if (i == 1) {
5499 cmn_err(CE_WARN,
5500 "!%s: %s failed: "
5501 "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5502 "ret:%d cr:%s(%d), cb_flags:0x%x %s",
5503 dp->name, __func__, reqt, req, val, ix, len,
5504 ret, usb_str_cr(completion_reason),
5505 completion_reason,
5506 cb_flags,
5507 (i > 1) ? "retrying..." : "fatal");
5511 if (data != NULL) {
5512 freemsg(data);
5515 return (ret);
5519 usbgem_ctrl_in(struct usbgem_dev *dp,
5520 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5521 void *bp, int size)
5523 mblk_t *data;
5524 usb_ctrl_setup_t setup;
5525 usb_cr_t completion_reason;
5526 usb_cb_flags_t cb_flags;
5527 int i;
5528 int ret;
5529 int reclen;
5531 DPRINTF(4, (CE_CONT,
5532 "!%s: %s:"
5533 " reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x"
5534 " bp:x%p mac_state:%d",
5535 dp->name, __func__, reqt, req, val, ix, len, bp, dp->mac_state));
5537 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5538 return (USB_PIPE_ERROR);
5541 data = NULL;
5543 setup.bmRequestType = reqt;
5544 setup.bRequest = req;
5545 setup.wValue = val;
5546 setup.wIndex = ix;
5547 setup.wLength = len;
5548 setup.attrs = USB_ATTRS_AUTOCLEARING; /* XXX */
5550 for (i = usbgem_ctrl_retry; i > 0; i--) {
5551 completion_reason = 0;
5552 cb_flags = 0;
5553 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp), &setup, &data,
5554 &completion_reason, &cb_flags, 0);
5556 if (ret == USB_SUCCESS) {
5557 reclen = msgdsize(data);
5558 bcopy(data->b_rptr, bp, min(reclen, size));
5559 break;
5561 if (i == 1) {
5562 cmn_err(CE_WARN,
5563 "!%s: %s failed: "
5564 "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5565 "ret:%d cr:%s(%d) cb_flags:0x%x %s",
5566 dp->name, __func__,
5567 reqt, req, val, ix, len,
5568 ret, usb_str_cr(completion_reason),
5569 completion_reason,
5570 cb_flags,
5571 (i > 1) ? "retrying..." : "fatal");
5575 if (data) {
5576 freemsg(data);
5579 return (ret);
5583 usbgem_ctrl_out_val(struct usbgem_dev *dp,
5584 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5585 uint32_t v)
5587 uint8_t buf[4];
5589 /* convert to little endian from native byte order */
5590 switch (len) {
5591 case 4:
5592 buf[3] = v >> 24;
5593 buf[2] = v >> 16;
5594 /* FALLTHROUGH */
5595 case 2:
5596 buf[1] = v >> 8;
5597 /* FALLTHROUGH */
5598 case 1:
5599 buf[0] = v;
5602 return (usbgem_ctrl_out(dp, reqt, req, val, ix, len, buf, len));
5606 usbgem_ctrl_in_val(struct usbgem_dev *dp,
5607 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5608 void *valp)
5610 uint8_t buf[4];
5611 uint_t v;
5612 int err;
5614 #ifdef SANITY
5615 bzero(buf, sizeof (buf));
5616 #endif
5617 err = usbgem_ctrl_in(dp, reqt, req, val, ix, len, buf, len);
5618 if (err == USB_SUCCESS) {
5619 v = 0;
5620 switch (len) {
5621 case 4:
5622 v |= buf[3] << 24;
5623 v |= buf[2] << 16;
5624 /* FALLTHROUGH */
5625 case 2:
5626 v |= buf[1] << 8;
5627 /* FALLTHROUGH */
5628 case 1:
5629 v |= buf[0];
5632 switch (len) {
5633 case 4:
5634 *(uint32_t *)valp = v;
5635 break;
5636 case 2:
5637 *(uint16_t *)valp = v;
5638 break;
5639 case 1:
5640 *(uint8_t *)valp = v;
5641 break;
5644 return (err);
5648 * Attach / detach / disconnect / reconnect management
5650 static int
5651 usbgem_open_pipes(struct usbgem_dev *dp)
5653 int i;
5654 int ret;
5655 int ifnum;
5656 int alt;
5657 usb_client_dev_data_t *reg_data;
5658 usb_ep_data_t *ep_tree_node;
5660 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5662 ifnum = dp->ugc.usbgc_ifnum;
5663 alt = dp->ugc.usbgc_alt;
5665 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5666 0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
5667 if (ep_tree_node == NULL) {
5668 cmn_err(CE_WARN, "!%s: %s: ep_bulkin is NULL",
5669 dp->name, __func__);
5670 goto err;
5672 dp->ep_bulkin = &ep_tree_node->ep_descr;
5674 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5675 0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
5676 if (ep_tree_node == NULL) {
5677 cmn_err(CE_WARN, "!%s: %s: ep_bulkout is NULL",
5678 dp->name, __func__);
5679 goto err;
5681 dp->ep_bulkout = &ep_tree_node->ep_descr;
5683 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5684 0, USB_EP_ATTR_INTR, USB_EP_DIR_IN);
5685 if (ep_tree_node) {
5686 dp->ep_intr = &ep_tree_node->ep_descr;
5687 } else {
5688 /* don't care */
5689 DPRINTF(1, (CE_CONT, "!%s: %s: ep_intr is NULL",
5690 dp->name, __func__));
5691 dp->ep_intr = NULL;
5694 /* XXX -- no need to open default pipe */
5696 /* open bulk out pipe */
5697 bzero(&dp->policy_bulkout, sizeof (usb_pipe_policy_t));
5698 dp->policy_bulkout.pp_max_async_reqs = 1;
5700 if ((ret = usb_pipe_open(dp->dip,
5701 dp->ep_bulkout, &dp->policy_bulkout, USB_FLAGS_SLEEP,
5702 &dp->bulkout_pipe)) != USB_SUCCESS) {
5703 cmn_err(CE_WARN,
5704 "!%s: %s: err:%x: failed to open bulk-out pipe",
5705 dp->name, __func__, ret);
5706 dp->bulkout_pipe = NULL;
5707 goto err;
5709 DPRINTF(1, (CE_CONT, "!%s: %s: bulkout_pipe opened successfully",
5710 dp->name, __func__));
5712 /* open bulk in pipe */
5713 bzero(&dp->policy_bulkin, sizeof (usb_pipe_policy_t));
5714 dp->policy_bulkin.pp_max_async_reqs = 1;
5715 if ((ret = usb_pipe_open(dp->dip,
5716 dp->ep_bulkin, &dp->policy_bulkin, USB_FLAGS_SLEEP,
5717 &dp->bulkin_pipe)) != USB_SUCCESS) {
5718 cmn_err(CE_WARN,
5719 "!%s: %s: ret:%x failed to open bulk-in pipe",
5720 dp->name, __func__, ret);
5721 dp->bulkin_pipe = NULL;
5722 goto err;
5724 DPRINTF(1, (CE_CONT, "!%s: %s: bulkin_pipe opened successfully",
5725 dp->name, __func__));
5727 if (dp->ep_intr) {
5728 /* open interrupt pipe */
5729 bzero(&dp->policy_interrupt, sizeof (usb_pipe_policy_t));
5730 dp->policy_interrupt.pp_max_async_reqs = 1;
5731 if ((ret = usb_pipe_open(dp->dip, dp->ep_intr,
5732 &dp->policy_interrupt, USB_FLAGS_SLEEP,
5733 &dp->intr_pipe)) != USB_SUCCESS) {
5734 cmn_err(CE_WARN,
5735 "!%s: %s: ret:%x failed to open interrupt pipe",
5736 dp->name, __func__, ret);
5737 dp->intr_pipe = NULL;
5738 goto err;
5741 DPRINTF(1, (CE_CONT, "!%s: %s: intr_pipe opened successfully",
5742 dp->name, __func__));
5744 return (USB_SUCCESS);
5746 err:
5747 if (dp->bulkin_pipe) {
5748 usb_pipe_close(dp->dip,
5749 dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5750 dp->bulkin_pipe = NULL;
5752 if (dp->bulkout_pipe) {
5753 usb_pipe_close(dp->dip,
5754 dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5755 dp->bulkout_pipe = NULL;
5757 if (dp->intr_pipe) {
5758 usb_pipe_close(dp->dip,
5759 dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5760 dp->intr_pipe = NULL;
5763 return (USB_FAILURE);
5766 static int
5767 usbgem_close_pipes(struct usbgem_dev *dp)
5769 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5771 if (dp->intr_pipe) {
5772 usb_pipe_close(dp->dip,
5773 dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5774 dp->intr_pipe = NULL;
5776 DPRINTF(1, (CE_CONT, "!%s: %s: 1", dp->name, __func__));
5778 ASSERT(dp->bulkin_pipe);
5779 usb_pipe_close(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5780 dp->bulkin_pipe = NULL;
5781 DPRINTF(1, (CE_CONT, "!%s: %s: 2", dp->name, __func__));
5783 ASSERT(dp->bulkout_pipe);
5784 usb_pipe_close(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5785 dp->bulkout_pipe = NULL;
5786 DPRINTF(1, (CE_CONT, "!%s: %s: 3", dp->name, __func__));
5788 return (USB_SUCCESS);
5791 #define FREEZE_GRACEFUL (B_TRUE)
5792 #define FREEZE_NO_GRACEFUL (B_FALSE)
5793 static int
5794 usbgem_freeze_device(struct usbgem_dev *dp, boolean_t graceful)
5796 DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5798 /* stop nic activity */
5799 (void) usbgem_mac_stop(dp, MAC_STATE_DISCONNECTED, graceful);
5802 * Here we free all memory resource allocated, because it will
5803 * cause to panic the system that we free usb_bulk_req objects
5804 * during the usb device is disconnected.
5806 (void) usbgem_free_memory(dp);
5808 return (USB_SUCCESS);
5811 static int
5812 usbgem_disconnect_cb(dev_info_t *dip)
5814 int ret;
5815 struct usbgem_dev *dp;
5817 dp = USBGEM_GET_DEV(dip);
5819 cmn_err(CE_NOTE, "!%s: the usb device was disconnected (dp=%p)",
5820 dp->name, (void *)dp);
5822 /* start serialize */
5823 rw_enter(&dp->dev_state_lock, RW_WRITER);
5825 ret = usbgem_freeze_device(dp, 0);
5827 /* end of serialize */
5828 rw_exit(&dp->dev_state_lock);
5830 return (ret);
5833 static int
5834 usbgem_recover_device(struct usbgem_dev *dp)
5836 int err;
5838 DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5840 err = USB_SUCCESS;
5842 /* reinitialize the usb connection */
5843 usbgem_close_pipes(dp);
5844 if ((err = usbgem_open_pipes(dp)) != USB_SUCCESS) {
5845 goto x;
5848 /* initialize nic state */
5849 dp->mac_state = MAC_STATE_STOPPED;
5850 dp->mii_state = MII_STATE_UNKNOWN;
5852 /* allocate memory resources again */
5853 if ((err = usbgem_alloc_memory(dp)) != USB_SUCCESS) {
5854 goto x;
5857 /* restart nic and recover state */
5858 (void) usbgem_restart_nic(dp);
5860 usbgem_mii_init(dp);
5862 /* kick potentially stopped house keeping thread */
5863 cv_signal(&dp->link_watcher_wait_cv);
5865 return (err);
5868 static int
5869 usbgem_reconnect_cb(dev_info_t *dip)
5871 int err = USB_SUCCESS;
5872 struct usbgem_dev *dp;
5874 dp = USBGEM_GET_DEV(dip);
5875 DPRINTF(0, (CE_CONT, "!%s: dp=%p", ddi_get_name(dip), dp));
5876 #ifdef notdef
5877 /* check device changes after disconnect */
5878 if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5879 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5880 cmn_err(CE_CONT,
5881 "!%s: no or different device installed", dp->name);
5882 return (DDI_SUCCESS);
5884 #endif
5885 cmn_err(CE_NOTE, "%s: the usb device was reconnected", dp->name);
5887 /* start serialize */
5888 rw_enter(&dp->dev_state_lock, RW_WRITER);
5890 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5891 err = usbgem_recover_device(dp);
5894 /* end of serialize */
5895 rw_exit(&dp->dev_state_lock);
5897 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5901 usbgem_suspend(dev_info_t *dip)
5903 int err = USB_SUCCESS;
5904 struct usbgem_dev *dp;
5906 dp = USBGEM_GET_DEV(dip);
5908 DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5910 /* start serialize */
5911 rw_enter(&dp->dev_state_lock, RW_WRITER);
5913 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5914 err = usbgem_freeze_device(dp, STOP_GRACEFUL);
5917 /* end of serialize */
5918 rw_exit(&dp->dev_state_lock);
5920 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5924 usbgem_resume(dev_info_t *dip)
5926 int err = USB_SUCCESS;
5927 struct usbgem_dev *dp;
5929 dp = USBGEM_GET_DEV(dip);
5931 DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5932 #ifdef notdef
5933 /* check device changes after disconnect */
5934 if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5935 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5936 cmn_err(CE_CONT,
5937 "!%s: no or different device installed", dp->name);
5938 return (DDI_SUCCESS);
5940 #endif
5941 /* start serialize */
5942 rw_enter(&dp->dev_state_lock, RW_WRITER);
5944 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5945 err = usbgem_recover_device(dp);
5948 /* end of serialize */
5949 rw_exit(&dp->dev_state_lock);
5951 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5954 #define USBGEM_LOCAL_DATA_SIZE(gc) \
5955 (sizeof (struct usbgem_dev) + USBGEM_MCALLOC)
5957 struct usbgem_dev *
5958 usbgem_do_attach(dev_info_t *dip,
5959 struct usbgem_conf *gc, void *lp, int lmsize)
5961 struct usbgem_dev *dp;
5962 int i;
5963 #ifdef USBGEM_CONFIG_GLDv3
5964 mac_register_t *macp = NULL;
5965 #else
5966 gld_mac_info_t *macinfo;
5967 void *tmp;
5968 #endif
5969 int ret;
5970 int unit;
5971 int err;
5973 unit = ddi_get_instance(dip);
5975 DPRINTF(2, (CE_CONT, "!usbgem%d: %s: called", unit, __func__));
5978 * Allocate soft data structure
5980 dp = kmem_zalloc(USBGEM_LOCAL_DATA_SIZE(gc), KM_SLEEP);
5981 if (dp == NULL) {
5982 #ifndef USBGEM_CONFIG_GLDv3
5983 gld_mac_free(macinfo);
5984 #endif
5985 return (NULL);
5987 #ifdef USBGEM_CONFIG_GLDv3
5988 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5989 cmn_err(CE_WARN, "!gem%d: %s: mac_alloc failed",
5990 unit, __func__);
5991 return (NULL);
5993 #else
5994 macinfo = gld_mac_alloc(dip);
5995 dp->macinfo = macinfo;
5996 #endif
5998 /* link to private area */
5999 dp->private = lp;
6000 dp->priv_size = lmsize;
6001 dp->mc_list = (struct mcast_addr *)&dp[1];
6003 dp->dip = dip;
6004 bcopy(gc->usbgc_name, dp->name, USBGEM_NAME_LEN);
6007 * register with usb service
6009 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6010 cmn_err(CE_WARN,
6011 "%s: %s: usb_client_attach failed",
6012 dp->name, __func__);
6013 goto err_free_private;
6016 if (usb_get_dev_data(dip, &dp->reg_data,
6017 USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
6018 dp->reg_data = NULL;
6019 goto err_unregister_client;
6021 #ifdef USBGEM_DEBUG_LEVEL
6022 usb_print_descr_tree(dp->dip, dp->reg_data);
6023 #endif
6025 if (usbgem_open_pipes(dp) != USB_SUCCESS) {
6026 /* failed to open pipes */
6027 cmn_err(CE_WARN, "!%s: %s: failed to open pipes",
6028 dp->name, __func__);
6029 goto err_unregister_client;
6033 * Initialize mutexs and condition variables
6035 mutex_init(&dp->rxlock, NULL, MUTEX_DRIVER, NULL);
6036 mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
6037 cv_init(&dp->rx_drain_cv, NULL, CV_DRIVER, NULL);
6038 cv_init(&dp->tx_drain_cv, NULL, CV_DRIVER, NULL);
6039 rw_init(&dp->dev_state_lock, NULL, RW_DRIVER, NULL);
6040 mutex_init(&dp->link_watcher_lock, NULL, MUTEX_DRIVER, NULL);
6041 cv_init(&dp->link_watcher_wait_cv, NULL, CV_DRIVER, NULL);
6042 sema_init(&dp->hal_op_lock, 1, NULL, SEMA_DRIVER, NULL);
6043 sema_init(&dp->rxfilter_lock, 1, NULL, SEMA_DRIVER, NULL);
6046 * Initialize configuration
6048 dp->ugc = *gc;
6050 dp->mtu = ETHERMTU;
6051 dp->rxmode = 0;
6052 dp->speed = USBGEM_SPD_10; /* default is 10Mbps */
6053 dp->full_duplex = B_FALSE; /* default is half */
6054 dp->flow_control = FLOW_CONTROL_NONE;
6056 dp->nic_state = NIC_STATE_STOPPED;
6057 dp->mac_state = MAC_STATE_STOPPED;
6058 dp->mii_state = MII_STATE_UNKNOWN;
6060 /* performance tuning parameters */
6061 dp->txthr = ETHERMAX; /* tx fifo threshoold */
6062 dp->txmaxdma = 16*4; /* tx max dma burst size */
6063 dp->rxthr = 128; /* rx fifo threshoold */
6064 dp->rxmaxdma = 16*4; /* rx max dma burst size */
6067 * Get media mode infomation from .conf file
6069 usbgem_read_conf(dp);
6071 /* rx_buf_len depend on MTU */
6072 dp->rx_buf_len = MAXPKTBUF(dp) + dp->ugc.usbgc_rx_header_len;
6075 * Reset the chip
6077 if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
6078 cmn_err(CE_WARN,
6079 "!%s: %s: failed to reset the usb device",
6080 dp->name, __func__);
6081 goto err_destroy_locks;
6085 * HW dependant paremeter initialization
6087 if (usbgem_hal_attach_chip(dp) != USB_SUCCESS) {
6088 cmn_err(CE_WARN,
6089 "!%s: %s: failed to attach the usb device",
6090 dp->name, __func__);
6091 goto err_destroy_locks;
6094 /* allocate resources */
6095 if (usbgem_alloc_memory(dp) != USB_SUCCESS) {
6096 goto err_destroy_locks;
6099 DPRINTF(0, (CE_CONT,
6100 "!%s: %02x:%02x:%02x:%02x:%02x:%02x",
6101 dp->name,
6102 dp->dev_addr.ether_addr_octet[0],
6103 dp->dev_addr.ether_addr_octet[1],
6104 dp->dev_addr.ether_addr_octet[2],
6105 dp->dev_addr.ether_addr_octet[3],
6106 dp->dev_addr.ether_addr_octet[4],
6107 dp->dev_addr.ether_addr_octet[5]));
6109 /* copy mac address */
6110 dp->cur_addr = dp->dev_addr;
6112 /* pre-calculated tx timeout in second for performance */
6113 dp->bulkout_timeout =
6114 dp->ugc.usbgc_tx_timeout / drv_usectohz(1000*1000);
6116 #ifdef USBGEM_CONFIG_GLDv3
6117 usbgem_gld3_init(dp, macp);
6118 #else
6119 usbgem_gld_init(dp, macinfo, ident);
6120 #endif
6122 /* Probe MII phy (scan phy) */
6123 dp->mii_lpable = 0;
6124 dp->mii_advert = 0;
6125 dp->mii_exp = 0;
6126 dp->mii_ctl1000 = 0;
6127 dp->mii_stat1000 = 0;
6129 dp->mii_status_ro = 0;
6130 dp->mii_xstatus_ro = 0;
6132 if (usbgem_mii_probe(dp) != USB_SUCCESS) {
6133 cmn_err(CE_WARN, "!%s: %s: mii_probe failed",
6134 dp->name, __func__);
6135 goto err_free_memory;
6138 /* mask unsupported abilities */
6139 dp->anadv_autoneg &= BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
6140 dp->anadv_1000fdx &=
6141 BOOLEAN(dp->mii_xstatus &
6142 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD));
6143 dp->anadv_1000hdx &=
6144 BOOLEAN(dp->mii_xstatus &
6145 (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET));
6146 dp->anadv_100t4 &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
6147 dp->anadv_100fdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
6148 dp->anadv_100hdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
6149 dp->anadv_10fdx &= BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
6150 dp->anadv_10hdx &= BOOLEAN(dp->mii_status & MII_STATUS_10);
6152 if (usbgem_mii_init(dp) != USB_SUCCESS) {
6153 cmn_err(CE_WARN, "!%s: %s: mii_init failed",
6154 dp->name, __func__);
6155 goto err_free_memory;
6159 * initialize kstats including mii statistics
6161 #ifdef USBGEM_CONFIG_GLDv3
6162 #ifdef USBGEM_CONFIG_ND
6163 usbgem_nd_setup(dp);
6164 #endif
6165 #else
6166 if (usbgem_kstat_init(dp) != USB_SUCCESS) {
6167 goto err_free_memory;
6169 #endif
6172 * Add interrupt to system.
6174 #ifdef USBGEM_CONFIG_GLDv3
6175 if (ret = mac_register(macp, &dp->mh)) {
6176 cmn_err(CE_WARN, "!%s: mac_register failed, error:%d",
6177 dp->name, ret);
6178 goto err_release_stats;
6180 mac_free(macp);
6181 macp = NULL;
6182 #else
6183 /* gld_register will corrupts driver_private */
6184 tmp = ddi_get_driver_private(dip);
6185 if (gld_register(dip,
6186 (char *)ddi_driver_name(dip), macinfo) != DDI_SUCCESS) {
6187 cmn_err(CE_WARN, "!%s: %s: gld_register failed",
6188 dp->name, __func__);
6189 ddi_set_driver_private(dip, tmp);
6190 goto err_release_stats;
6192 /* restore driver private */
6193 ddi_set_driver_private(dip, tmp);
6194 #endif /* USBGEM_CONFIG_GLDv3 */
6195 if (usb_register_hotplug_cbs(dip,
6196 usbgem_suspend, usbgem_resume) != USB_SUCCESS) {
6197 cmn_err(CE_WARN,
6198 "!%s: %s: failed to register hotplug cbs",
6199 dp->name, __func__);
6200 goto err_unregister_gld;
6203 /* reset mii and start mii link watcher */
6204 if (usbgem_mii_start(dp) != USB_SUCCESS) {
6205 goto err_unregister_hotplug;
6208 /* start tx watchdow watcher */
6209 if (usbgem_tx_watcher_start(dp)) {
6210 goto err_usbgem_mii_stop;
6213 ddi_set_driver_private(dip, (caddr_t)dp);
6215 DPRINTF(2, (CE_CONT, "!%s: %s: return: success", dp->name, __func__));
6217 return (dp);
6219 err_usbgem_mii_stop:
6220 usbgem_mii_stop(dp);
6222 err_unregister_hotplug:
6223 usb_unregister_hotplug_cbs(dip);
6225 err_unregister_gld:
6226 #ifdef USBGEM_CONFIG_GLDv3
6227 mac_unregister(dp->mh);
6228 #else
6229 gld_unregister(macinfo);
6230 #endif
6232 err_release_stats:
6233 #ifdef USBGEM_CONFIG_GLDv3
6234 #ifdef USBGEM_CONFIG_ND
6235 /* release NDD resources */
6236 usbgem_nd_cleanup(dp);
6237 #endif
6238 #else
6239 kstat_delete(dp->ksp);
6240 #endif
6242 err_free_memory:
6243 usbgem_free_memory(dp);
6245 err_destroy_locks:
6246 cv_destroy(&dp->tx_drain_cv);
6247 cv_destroy(&dp->rx_drain_cv);
6248 mutex_destroy(&dp->txlock);
6249 mutex_destroy(&dp->rxlock);
6250 rw_destroy(&dp->dev_state_lock);
6251 mutex_destroy(&dp->link_watcher_lock);
6252 cv_destroy(&dp->link_watcher_wait_cv);
6253 sema_destroy(&dp->hal_op_lock);
6254 sema_destroy(&dp->rxfilter_lock);
6256 err_close_pipes:
6257 (void) usbgem_close_pipes(dp);
6259 err_unregister_client:
6260 usb_client_detach(dp->dip, dp->reg_data);
6262 err_free_private:
6263 #ifdef USBGEM_CONFIG_GLDv3
6264 if (macp) {
6265 mac_free(macp);
6267 #else
6268 gld_mac_free(macinfo);
6269 #endif
6270 kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(gc));
6272 return (NULL);
6276 usbgem_do_detach(dev_info_t *dip)
6278 struct usbgem_dev *dp;
6280 dp = USBGEM_GET_DEV(dip);
6282 #ifdef USBGEM_CONFIG_GLDv3
6283 /* unregister with gld v3 */
6284 if (mac_unregister(dp->mh) != DDI_SUCCESS) {
6285 return (DDI_FAILURE);
6287 #else
6288 /* unregister with gld v2 */
6289 if (gld_unregister(dp->macinfo) != DDI_SUCCESS) {
6290 return (DDI_FAILURE);
6292 #endif
6293 /* unregister with hotplug service */
6294 usb_unregister_hotplug_cbs(dip);
6296 /* stop tx watchdog watcher */
6297 usbgem_tx_watcher_stop(dp);
6299 /* stop the link manager */
6300 usbgem_mii_stop(dp);
6302 /* unregister with usb service */
6303 (void) usbgem_free_memory(dp);
6304 (void) usbgem_close_pipes(dp);
6305 usb_client_detach(dp->dip, dp->reg_data);
6306 dp->reg_data = NULL;
6308 /* unregister with kernel statistics */
6309 #ifdef USBGEM_CONFIG_GLDv3
6310 #ifdef USBGEM_CONFIG_ND
6311 /* release ndd resources */
6312 usbgem_nd_cleanup(dp);
6313 #endif
6314 #else
6315 /* destroy kstat objects */
6316 kstat_delete(dp->ksp);
6317 #endif
6319 /* release locks and condition variables */
6320 mutex_destroy(&dp->txlock);
6321 mutex_destroy(&dp->rxlock);
6322 cv_destroy(&dp->tx_drain_cv);
6323 cv_destroy(&dp->rx_drain_cv);
6324 rw_destroy(&dp->dev_state_lock);
6325 mutex_destroy(&dp->link_watcher_lock);
6326 cv_destroy(&dp->link_watcher_wait_cv);
6327 sema_destroy(&dp->hal_op_lock);
6328 sema_destroy(&dp->rxfilter_lock);
6330 /* release basic memory resources */
6331 #ifndef USBGEM_CONFIG_GLDv3
6332 gld_mac_free(dp->macinfo);
6333 #endif
6334 kmem_free((caddr_t)(dp->private), dp->priv_size);
6335 kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(&dp->ugc));
6337 DPRINTF(2, (CE_CONT, "!%s: %s: return: success",
6338 ddi_driver_name(dip), __func__));
6340 return (DDI_SUCCESS);
6344 usbgem_mod_init(struct dev_ops *dop, char *name)
6346 #ifdef USBGEM_CONFIG_GLDv3
6347 major_t major;
6348 major = ddi_name_to_major(name);
6349 if (major == DDI_MAJOR_T_NONE) {
6350 return (DDI_FAILURE);
6352 mac_init_ops(dop, name);
6353 #endif
6354 return (DDI_SUCCESS);
6357 void
6358 usbgem_mod_fini(struct dev_ops *dop)
6360 #ifdef USBGEM_CONFIG_GLDv3
6361 mac_fini_ops(dop);
6362 #endif
6366 usbgem_quiesce(dev_info_t *dip)
6368 struct usbgem_dev *dp;
6370 dp = USBGEM_GET_DEV(dip);
6372 ASSERT(dp != NULL);
6374 if (dp->mac_state != MAC_STATE_DISCONNECTED &&
6375 dp->mac_state != MAC_STATE_STOPPED) {
6376 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
6377 (void) usbgem_hal_reset_chip(dp);
6381 /* devo_quiesce() must return DDI_SUCCESS always */
6382 return (DDI_SUCCESS);