1 /*
2 * usbgem.c: General USB to Fast Ethernet mac driver framework
3 *
4 * Copyright (c) 2002-2012 Masayuki Murayama. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the author nor the names of its contributors may be
17 * used to endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE.
32 */
33
34 /*
35 * Copyright 2019 Joyent, Inc.
36 * Copyright 2022 Garrett D'Amore
37 */
38
39 /*
40 * Change log
41 */
42
43 /*
44 * TODO:
45 * implement DELAYED_START
46 */
47
48 /*
49 * System Header files.
50 */
51 #include <sys/types.h>
52 #include <sys/conf.h>
53 #include <sys/debug.h>
54 #include <sys/kmem.h>
55 #include <sys/vtrace.h>
56 #include <sys/ethernet.h>
57 #include <sys/modctl.h>
58 #include <sys/errno.h>
59 #include <sys/ddi.h>
60 #include <sys/sunddi.h>
61 #include <sys/stream.h> /* required for MBLK* */
62 #include <sys/strsun.h> /* required for mionack() */
63 #include <sys/byteorder.h>
64
65 #include <sys/usb/usba.h>
66 #include <inet/common.h>
67 #include <inet/led.h>
68 #include <inet/mi.h>
69 #include <inet/nd.h>
70
71 /* supplement definitions */
72 extern const char *usb_str_cr(usb_cr_t);
73
74 #include <sys/note.h>
75
76 #include "usbgem_mii.h"
77 #include "usbgem.h"
78
79 char ident[] = "usb general ethernet mac driver v" VERSION;
80
81 /* Debugging support */
82 #ifdef USBGEM_DEBUG_LEVEL
83 static int usbgem_debug = USBGEM_DEBUG_LEVEL;
84 #define DPRINTF(n, args) if (usbgem_debug > (n)) cmn_err args
85 #else
86 #define DPRINTF(n, args)
87 #endif
88
89 /*
90 * Useful macros and typedefs
91 */
92 #define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
93 #define DEFAULT_PIPE(dp) ((dp)->reg_data->dev_default_ph)
94 #define VTAG_SIZE 4
95 #define BOOLEAN(x) ((x) != 0)
96 /*
97 * configuration parameters
98 */
99 #define USBDRV_MAJOR_VER 2
100 #define USBDRV_MINOR_VER 0
101
102 #define ETHERHEADERL (sizeof (struct ether_header))
103 #define MAXPKTLEN(dp) ((dp)->mtu + ETHERHEADERL)
104 #define MAXPKTBUF(dp) ((dp)->mtu + ETHERHEADERL + ETHERFCSL)
105
106 #define WATCH_INTERVAL_FAST drv_usectohz(100*1000)
107
108 #define STOP_GRACEFUL B_TRUE
109
110 /*
111 * Private functions
112 */
113 static int usbgem_open_pipes(struct usbgem_dev *dp);
114 static int usbgem_close_pipes(struct usbgem_dev *dp);
115 static void usbgem_intr_cb(usb_pipe_handle_t, usb_intr_req_t *);
116 static void usbgem_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
117 static void usbgem_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
118
119 static int usbgem_mii_start(struct usbgem_dev *);
120 static void usbgem_mii_stop(struct usbgem_dev *);
121
122 /* local buffer management */
123 static int usbgem_init_rx_buf(struct usbgem_dev *);
124
125 /* internal mac interfaces */
126 static void usbgem_tx_timeout(struct usbgem_dev *);
127 static void usbgem_mii_link_watcher(struct usbgem_dev *);
128 static int usbgem_mac_init(struct usbgem_dev *);
129 static int usbgem_mac_start(struct usbgem_dev *);
130 static int usbgem_mac_stop(struct usbgem_dev *, int, boolean_t);
131 static void usbgem_mac_ioctl(struct usbgem_dev *, queue_t *, mblk_t *);
132
133 int usbgem_speed_value[] = {10, 100, 1000};
134
135 static int usbgem_ctrl_retry = 5;
136
137 /* usb event support */
138 static int usbgem_disconnect_cb(dev_info_t *dip);
139 static int usbgem_reconnect_cb(dev_info_t *dip);
140 int usbgem_suspend(dev_info_t *dip);
141 int usbgem_resume(dev_info_t *dip);
142
143 static uint8_t usbgem_bcastaddr[] = {
144 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
145 };
146
147 extern struct mod_ops mod_miscops;
148
149 static struct modlmisc modlmisc = {
150 &mod_miscops,
151 "usbgem v" VERSION,
152 };
153
154 static struct modlinkage modlinkage = {
155 MODREV_1, &modlmisc, NULL
156 };
157
158 /*
159 * _init : done
160 */
161 int
_init(void)162 _init(void)
163 {
164 int status;
165
166 DPRINTF(2, (CE_CONT, "!usbgem: _init: called"));
167 status = mod_install(&modlinkage);
168
169 return (status);
170 }
171
172 /*
173 * _fini : done
174 */
175 int
_fini(void)176 _fini(void)
177 {
178 int status;
179
180 DPRINTF(2, (CE_CONT, "!usbgem: _fini: called"));
181 status = mod_remove(&modlinkage);
182 return (status);
183 }
184
185 int
_info(struct modinfo * modinfop)186 _info(struct modinfo *modinfop)
187 {
188 return (mod_info(&modlinkage, modinfop));
189 }
190
191 /* ============================================================== */
192 /*
193 * Ether CRC calculation utilities
194 */
195 /* ============================================================== */
196 /*
197 * Ether CRC calculation according to 21143 data sheet
198 */
199 #define CRC32_POLY_LE 0xedb88320
200 uint32_t
usbgem_ether_crc_le(const uint8_t * addr)201 usbgem_ether_crc_le(const uint8_t *addr)
202 {
203 int idx;
204 int bit;
205 uint_t data;
206 uint32_t crc = 0xffffffff;
207
208 crc = 0xffffffff;
209 for (idx = 0; idx < ETHERADDRL; idx++) {
210 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
211 crc = (crc >> 1) ^
212 (((crc ^ data) & 1) ? CRC32_POLY_LE : 0);
213 }
214 }
215 return (crc);
216 }
217
218 #define CRC32_POLY_BE 0x04c11db7
219 uint32_t
usbgem_ether_crc_be(const uint8_t * addr)220 usbgem_ether_crc_be(const uint8_t *addr)
221 {
222 int idx;
223 int bit;
224 uint_t data;
225 uint32_t crc;
226
227 crc = 0xffffffff;
228 for (idx = 0; idx < ETHERADDRL; idx++) {
229 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
230 crc = (crc << 1) ^
231 ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
232 }
233 }
234 return (crc);
235 }
236
237 int
usbgem_prop_get_int(struct usbgem_dev * dp,char * prop_template,int def_val)238 usbgem_prop_get_int(struct usbgem_dev *dp, char *prop_template, int def_val)
239 {
240 char propname[32];
241
242 (void) sprintf(propname, prop_template, dp->name);
243
244 return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
245 DDI_PROP_DONTPASS, propname, def_val));
246 }
247
248 static int
usbgem_population(uint32_t x)249 usbgem_population(uint32_t x)
250 {
251 int i;
252 int cnt;
253
254 cnt = 0;
255 for (i = 0; i < 32; i++) {
256 if (x & (1 << i)) {
257 cnt++;
258 }
259 }
260 return (cnt);
261 }
262
263 static clock_t
usbgem_timestamp_nz()264 usbgem_timestamp_nz()
265 {
266 clock_t now;
267 now = ddi_get_lbolt();
268 return (now ? now : (clock_t)1);
269 }
270
271 /* ============================================================== */
272 /*
273 * hardware operations
274 */
275 /* ============================================================== */
276 static int
usbgem_hal_reset_chip(struct usbgem_dev * dp)277 usbgem_hal_reset_chip(struct usbgem_dev *dp)
278 {
279 int err;
280
281 sema_p(&dp->hal_op_lock);
282 err = (*dp->ugc.usbgc_reset_chip)(dp);
283 sema_v(&dp->hal_op_lock);
284 return (err);
285 }
286
287 static int
usbgem_hal_init_chip(struct usbgem_dev * dp)288 usbgem_hal_init_chip(struct usbgem_dev *dp)
289 {
290 int err;
291
292 sema_p(&dp->hal_op_lock);
293 err = (*dp->ugc.usbgc_init_chip)(dp);
294 sema_v(&dp->hal_op_lock);
295 return (err);
296 }
297
298 static int
usbgem_hal_attach_chip(struct usbgem_dev * dp)299 usbgem_hal_attach_chip(struct usbgem_dev *dp)
300 {
301 int err;
302
303 sema_p(&dp->hal_op_lock);
304 err = (*dp->ugc.usbgc_attach_chip)(dp);
305 sema_v(&dp->hal_op_lock);
306 return (err);
307 }
308
309 static int
usbgem_hal_set_rx_filter(struct usbgem_dev * dp)310 usbgem_hal_set_rx_filter(struct usbgem_dev *dp)
311 {
312 int err;
313
314 sema_p(&dp->hal_op_lock);
315 err = (*dp->ugc.usbgc_set_rx_filter)(dp);
316 sema_v(&dp->hal_op_lock);
317 return (err);
318 }
319
320 static int
usbgem_hal_set_media(struct usbgem_dev * dp)321 usbgem_hal_set_media(struct usbgem_dev *dp)
322 {
323 int err;
324
325 sema_p(&dp->hal_op_lock);
326 err = (*dp->ugc.usbgc_set_media)(dp);
327 sema_v(&dp->hal_op_lock);
328 return (err);
329 }
330
331 static int
usbgem_hal_start_chip(struct usbgem_dev * dp)332 usbgem_hal_start_chip(struct usbgem_dev *dp)
333 {
334 int err;
335
336 sema_p(&dp->hal_op_lock);
337 err = (*dp->ugc.usbgc_start_chip)(dp);
338 sema_v(&dp->hal_op_lock);
339 return (err);
340 }
341
342 static int
usbgem_hal_stop_chip(struct usbgem_dev * dp)343 usbgem_hal_stop_chip(struct usbgem_dev *dp)
344 {
345 int err;
346
347 sema_p(&dp->hal_op_lock);
348 err = (*dp->ugc.usbgc_stop_chip)(dp);
349 sema_v(&dp->hal_op_lock);
350 return (err);
351 }
352
353 static int
usbgem_hal_get_stats(struct usbgem_dev * dp)354 usbgem_hal_get_stats(struct usbgem_dev *dp)
355 {
356 int err;
357
358 sema_p(&dp->hal_op_lock);
359 err = (*dp->ugc.usbgc_get_stats)(dp);
360 sema_v(&dp->hal_op_lock);
361 return (err);
362 }
363
364
365 /* ============================================================== */
366 /*
367 * USB pipe management
368 */
369 /* ============================================================== */
370 static boolean_t
usbgem_rx_start_unit(struct usbgem_dev * dp,usb_bulk_req_t * req)371 usbgem_rx_start_unit(struct usbgem_dev *dp, usb_bulk_req_t *req)
372 {
373 mblk_t *mp;
374 int err;
375 usb_flags_t flags;
376
377 ASSERT(req);
378
379 mp = allocb(dp->rx_buf_len, BPRI_MED);
380 if (mp == NULL) {
381 cmn_err(CE_WARN, "!%s: %s: failed to allocate mblk",
382 dp->name, __func__);
383 goto err;
384 }
385
386 req->bulk_len = dp->rx_buf_len;
387 req->bulk_data = mp;
388 req->bulk_client_private = (usb_opaque_t)dp;
389 req->bulk_timeout = 0;
390 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
391 req->bulk_cb = usbgem_bulkin_cb;
392 req->bulk_exc_cb = usbgem_bulkin_cb;
393 req->bulk_completion_reason = 0;
394 req->bulk_cb_flags = 0;
395
396 flags = 0;
397 err = usb_pipe_bulk_xfer(dp->bulkin_pipe, req, flags);
398
399 if (err != USB_SUCCESS) {
400 cmn_err(CE_WARN, "%s: failed to bulk_xfer for rx, err:%d",
401 dp->name, err);
402
403 /* free req and mp */
404 usb_free_bulk_req(req);
405 goto err;
406 }
407 return (B_TRUE);
408 err:
409 return (B_FALSE);
410 }
411
412 /* ============================================================== */
413 /*
414 * Rx/Tx buffer management
415 */
416 /* ============================================================== */
417 static int
usbgem_init_rx_buf(struct usbgem_dev * dp)418 usbgem_init_rx_buf(struct usbgem_dev *dp)
419 {
420 int i;
421 usb_bulk_req_t *req;
422
423 ASSERT(dp->mac_state == MAC_STATE_ONLINE);
424
425 for (i = 0; i < dp->ugc.usbgc_rx_list_max; i++) {
426 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
427 if (req == NULL) {
428 cmn_err(CE_WARN,
429 "!%s: %s: failed to allocate bulkreq for rx",
430 dp->name, __func__);
431 return (USB_FAILURE);
432 }
433 if (!usbgem_rx_start_unit(dp, req)) {
434 return (USB_FAILURE);
435 }
436 mutex_enter(&dp->rxlock);
437 dp->rx_busy_cnt++;
438 mutex_exit(&dp->rxlock);
439 }
440 return (USB_SUCCESS);
441 }
442
443 /* ============================================================== */
444 /*
445 * memory resource management
446 */
447 /* ============================================================== */
448 static int
usbgem_free_memory(struct usbgem_dev * dp)449 usbgem_free_memory(struct usbgem_dev *dp)
450 {
451 usb_bulk_req_t *req;
452
453 /* free all tx requst structure */
454 while ((req = dp->tx_free_list) != NULL) {
455 dp->tx_free_list =
456 (usb_bulk_req_t *)req->bulk_client_private;
457 req->bulk_data = NULL;
458 usb_free_bulk_req(req);
459 }
460 return (USB_SUCCESS);
461 }
462
463 static int
usbgem_alloc_memory(struct usbgem_dev * dp)464 usbgem_alloc_memory(struct usbgem_dev *dp)
465 {
466 int i;
467 usb_bulk_req_t *req;
468
469 /* allocate tx requests */
470 dp->tx_free_list = NULL;
471 for (i = 0; i < dp->ugc.usbgc_tx_list_max; i++) {
472 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
473 if (req == NULL) {
474 cmn_err(CE_WARN,
475 "%s:%s failed to allocate tx requests",
476 dp->name, __func__);
477
478 /* free partially allocated tx requests */
479 (void) usbgem_free_memory(dp);
480 return (USB_FAILURE);
481 }
482
483 /* add the new one allocated into tx free list */
484 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
485 dp->tx_free_list = req;
486 }
487
488 return (USB_SUCCESS);
489 }
490
491 /* ========================================================== */
492 /*
493 * Start transmission.
494 * Return zero on success,
495 */
496 /* ========================================================== */
497
498 #ifdef TXTIMEOUT_TEST
499 static int usbgem_send_cnt = 0;
500 #endif
501
502 /*
503 * usbgem_send is used only to send data packet into ethernet line.
504 */
505 static mblk_t *
usbgem_send_common(struct usbgem_dev * dp,mblk_t * mp,uint32_t flags)506 usbgem_send_common(struct usbgem_dev *dp, mblk_t *mp, uint32_t flags)
507 {
508 int err;
509 mblk_t *new;
510 usb_bulk_req_t *req;
511 int mcast;
512 int bcast;
513 int len;
514 boolean_t intr;
515 usb_flags_t usb_flags = 0;
516 #ifdef USBGEM_DEBUG_LEVEL
517 usb_pipe_state_t p_state;
518 #endif
519 DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
520
521 intr = (flags & 1) != 0;
522 len = msgdsize(mp);
523 bcast = 0;
524 mcast = 0;
525 if (mp->b_rptr[0] & 1) {
526 if (bcmp(mp->b_rptr, &usbgem_bcastaddr, ETHERADDRL) == 0) {
527 bcast = 1;
528 } else {
529 mcast = 1;
530 }
531 }
532 new = (*dp->ugc.usbgc_tx_make_packet)(dp, mp);
533 if (new == NULL) {
534 /*
535 * no memory resource. we don't stop downstream,
536 * we just discard the packet.
537 */
538 DPRINTF(0, (CE_CONT, "!%s: %s: no memory",
539 dp->name, __func__));
540 freemsg(mp);
541
542 mutex_enter(&dp->txlock);
543 dp->stats.noxmtbuf++;
544 dp->stats.errxmt++;
545 mutex_exit(&dp->txlock);
546
547 return (NULL);
548 }
549
550 ASSERT(new->b_cont == NULL);
551
552 mutex_enter(&dp->txlock);
553 if (dp->tx_free_list == NULL) {
554 /*
555 * no tx free slot
556 */
557 ASSERT(dp->tx_busy_cnt == dp->ugc.usbgc_tx_list_max);
558 mutex_exit(&dp->txlock);
559
560 DPRINTF(4, (CE_CONT, "!%s: %s: no free slot",
561 dp->name, __func__));
562 if (new && new != mp) {
563 /* free reallocated message */
564 freemsg(new);
565 }
566 return (mp);
567 }
568 req = dp->tx_free_list;
569 dp->tx_free_list = (usb_bulk_req_t *)req->bulk_client_private;
570 dp->tx_busy_cnt++;
571
572 if (dp->tx_free_list == NULL) {
573 intr = B_TRUE;
574 }
575 if (intr) {
576 dp->tx_intr_pended++;
577 }
578 DB_TCI(new) = intr;
579 #ifdef USBGEM_DEBUG_LEVEL
580 new->b_datap->db_cksum32 = dp->tx_seq_num;
581 dp->tx_seq_num++;
582 #endif
583 dp->stats.obytes += len;
584 dp->stats.opackets++;
585 if (bcast | mcast) {
586 dp->stats.obcast += bcast;
587 dp->stats.omcast += mcast;
588 }
589 mutex_exit(&dp->txlock);
590
591 DPRINTF(2, (CE_CONT, "!%s: %s: sending", dp->name, __func__));
592
593 req->bulk_len = (long)new->b_wptr - (long)new->b_rptr;
594 req->bulk_data = new;
595 req->bulk_client_private = (usb_opaque_t)dp;
596 req->bulk_timeout = dp->bulkout_timeout; /* in second */
597 req->bulk_attributes = 0;
598 req->bulk_cb = usbgem_bulkout_cb;
599 req->bulk_exc_cb = usbgem_bulkout_cb;
600 req->bulk_completion_reason = 0;
601 req->bulk_cb_flags = 0;
602
603 if (intr) {
604 usb_flags = USB_FLAGS_SLEEP;
605 }
606 if ((err = usb_pipe_bulk_xfer(dp->bulkout_pipe, req, usb_flags))
607 != USB_SUCCESS) {
608
609 /* failed to transfer the packet, discard it. */
610 freemsg(new);
611 req->bulk_data = NULL;
612
613 /* recycle the request block */
614 mutex_enter(&dp->txlock);
615 dp->tx_busy_cnt--;
616 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
617 dp->tx_free_list = req;
618 mutex_exit(&dp->txlock);
619
620 cmn_err(CE_NOTE,
621 "%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
622 dp->name, __func__, err);
623
624 /* we use another flag to indicate error state. */
625 if (dp->fatal_error == (clock_t)0) {
626 dp->fatal_error = usbgem_timestamp_nz();
627 }
628 } else {
629 /* record the start time */
630 dp->tx_start_time = ddi_get_lbolt();
631 }
632
633 if (err == USB_SUCCESS && (usb_flags & USB_FLAGS_SLEEP)) {
634 usbgem_bulkout_cb(dp->bulkout_pipe, req);
635 }
636
637 if (new != mp) {
638 freemsg(mp);
639 }
640 return (NULL);
641 }
642
643 int
usbgem_restart_nic(struct usbgem_dev * dp)644 usbgem_restart_nic(struct usbgem_dev *dp)
645 {
646 int ret;
647 int flags = 0;
648
649 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
650
651 ASSERT(dp->mac_state != MAC_STATE_DISCONNECTED);
652
653 /*
654 * ensure to stop the nic
655 */
656 if (dp->mac_state == MAC_STATE_ONLINE) {
657 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
658 }
659
660 /* now the nic become quiescent, reset the chip */
661 if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
662 cmn_err(CE_WARN, "%s: %s: failed to reset chip",
663 dp->name, __func__);
664 goto err;
665 }
666
667 /*
668 * restore the nic state step by step
669 */
670 if (dp->nic_state < NIC_STATE_INITIALIZED) {
671 goto done;
672 }
673
674 if (usbgem_mac_init(dp) != USB_SUCCESS) {
675 cmn_err(CE_WARN, "%s: %s: failed to initialize chip",
676 dp->name, __func__);
677 goto err;
678 }
679
680 /* setup mac address and enable rx filter */
681 sema_p(&dp->rxfilter_lock);
682 dp->rxmode |= RXMODE_ENABLE;
683 ret = usbgem_hal_set_rx_filter(dp);
684 sema_v(&dp->rxfilter_lock);
685 if (ret != USB_SUCCESS) {
686 goto err;
687 }
688
689 /*
690 * update the link state asynchronously
691 */
692 cv_signal(&dp->link_watcher_wait_cv);
693
694 /*
695 * XXX - a panic happened because of linkdown.
696 * We must check mii_state here, because the link can be down just
697 * before the restart event happen. If the link is down now,
698 * gem_mac_start() will be called from gem_mii_link_check() when
699 * the link become up later.
700 */
701 if (dp->mii_state == MII_STATE_LINKUP) {
702 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
703 goto err;
704 }
705 if (dp->nic_state < NIC_STATE_ONLINE) {
706 goto done;
707 }
708
709 (void) usbgem_mac_start(dp);
710
711 }
712 done:
713 return (USB_SUCCESS);
714 err:
715 return (USB_FAILURE);
716 }
717
718 static void
usbgem_tx_timeout(struct usbgem_dev * dp)719 usbgem_tx_timeout(struct usbgem_dev *dp)
720 {
721 uint_t rwlock;
722 clock_t now;
723
724 for (; ; ) {
725 mutex_enter(&dp->tx_watcher_lock);
726 (void) cv_timedwait(&dp->tx_watcher_cv, &dp->tx_watcher_lock,
727 dp->tx_watcher_interval + ddi_get_lbolt());
728 mutex_exit(&dp->tx_watcher_lock);
729
730 if (dp->tx_watcher_stop) {
731 break;
732 }
733
734 now = ddi_get_lbolt();
735
736 rwlock = RW_READER;
737 again:
738 rw_enter(&dp->dev_state_lock, rwlock);
739
740 if ((dp->mac_state != MAC_STATE_DISCONNECTED &&
741 dp->fatal_error &&
742 now - dp->fatal_error >= dp->ugc.usbgc_tx_timeout) ||
743 (dp->mac_state == MAC_STATE_ONLINE &&
744 dp->mii_state == MII_STATE_LINKUP &&
745 dp->tx_busy_cnt != 0 &&
746 now - dp->tx_start_time >= dp->ugc.usbgc_tx_timeout)) {
747 if (rwlock == RW_READER) {
748 /*
749 * Upgrade dev_state_lock from shared mode
750 * to exclusive mode to restart nic
751 */
752 rwlock = RW_WRITER;
753 rw_exit(&dp->dev_state_lock);
754 goto again;
755 }
756 cmn_err(CE_WARN, "%s: %s: restarting the nic:"
757 " fatal_error:%ld nic_state:%d"
758 " mac_state:%d starttime:%ld",
759 dp->name, __func__,
760 dp->fatal_error ? now - dp->fatal_error: 0,
761 dp->nic_state, dp->mac_state,
762 dp->tx_busy_cnt ? now - dp->tx_start_time : 0);
763
764 (void) usbgem_restart_nic(dp);
765 }
766
767 rw_exit(&dp->dev_state_lock);
768 }
769 }
770
771 static int
usbgem_tx_watcher_start(struct usbgem_dev * dp)772 usbgem_tx_watcher_start(struct usbgem_dev *dp)
773 {
774 int err;
775 kthread_t *wdth;
776
777 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
778
779 /* make a first call of uwgem_lw_link_check() */
780 dp->tx_watcher_stop = 0;
781 dp->tx_watcher_interval = drv_usectohz(1000*1000);
782
783 wdth = thread_create(NULL, 0, usbgem_tx_timeout, dp, 0, &p0,
784 TS_RUN, minclsyspri);
785 if (wdth == NULL) {
786 cmn_err(CE_WARN,
787 "!%s: %s: failed to create a tx_watcher thread",
788 dp->name, __func__);
789 return (USB_FAILURE);
790 }
791 dp->tx_watcher_did = wdth->t_did;
792
793 return (USB_SUCCESS);
794 }
795
796 static void
usbgem_tx_watcher_stop(struct usbgem_dev * dp)797 usbgem_tx_watcher_stop(struct usbgem_dev *dp)
798 {
799 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
800 if (dp->tx_watcher_did) {
801 /* Ensure timer routine stopped */
802 dp->tx_watcher_stop = 1;
803 cv_signal(&dp->tx_watcher_cv);
804 thread_join(dp->tx_watcher_did);
805 dp->tx_watcher_did = 0;
806 }
807 }
808
809 /* ================================================================== */
810 /*
811 * Callback handlers
812 */
813 /* ================================================================== */
814 static void
usbgem_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)815 usbgem_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
816 {
817 mblk_t *newmp;
818 mblk_t *mp;
819 mblk_t *tp;
820 uint64_t len = 0;
821 int pkts = 0;
822 int bcast = 0;
823 int mcast = 0;
824 boolean_t busy;
825 struct usbgem_dev *dp;
826
827 dp = (struct usbgem_dev *)req->bulk_client_private;
828 mp = req->bulk_data;
829 req->bulk_data = NULL;
830
831 DPRINTF(2, (CE_CONT, "!%s: %s: mp:%p, cr:%s(%d)",
832 dp->name, __func__, mp,
833 usb_str_cr(req->bulk_completion_reason),
834 req->bulk_completion_reason));
835
836 /*
837 * we cannot acquire dev_state_lock because the routine
838 * must be executed during usbgem_mac_stop() to avoid
839 * dead lock.
840 * we use a simle membar operation to get the state correctly.
841 */
842 membar_consumer();
843
844 if (req->bulk_completion_reason == USB_CR_OK &&
845 dp->nic_state == NIC_STATE_ONLINE) {
846 newmp = (*dp->ugc.usbgc_rx_make_packet)(dp, mp);
847
848 if (newmp != mp) {
849 /* the message has been reallocated, free old one */
850 freemsg(mp);
851 }
852
853 /* the message may includes one or more ethernet packets */
854 for (tp = newmp; tp; tp = tp->b_next) {
855 len += (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
856 pkts++;
857 if (tp->b_rptr[0] & 1) {
858 if (bcmp(tp->b_rptr, &usbgem_bcastaddr,
859 ETHERADDRL) == 0) {
860 bcast++;
861 } else {
862 mcast++;
863 }
864 }
865 }
866
867 /* send up if it is a valid packet */
868 mac_rx(dp->mh, NULL, newmp);
869 } else {
870 freemsg(mp);
871 len = 0;
872 }
873
874 mutex_enter(&dp->rxlock);
875 /* update rx_active */
876 if (dp->rx_active) {
877 dp->rx_active = dp->mac_state == MAC_STATE_ONLINE;
878 }
879
880 dp->stats.rbytes += len;
881 dp->stats.rpackets += pkts;
882 if (bcast | mcast) {
883 dp->stats.rbcast += bcast;
884 dp->stats.rmcast += mcast;
885 }
886 mutex_exit(&dp->rxlock);
887
888 if (dp->rx_active) {
889 /* prepare to receive the next packets */
890 if (usbgem_rx_start_unit(dp, req)) {
891 /* we successed */
892 goto done;
893 }
894 cmn_err(CE_WARN,
895 "!%s: %s: failed to fill next rx packet",
896 dp->name, __func__);
897 /*
898 * we use another flag to indicate error state.
899 * if we acquire dev_state_lock for RW_WRITER here,
900 * usbgem_mac_stop() may hang.
901 */
902 if (dp->fatal_error == (clock_t)0) {
903 dp->fatal_error = usbgem_timestamp_nz();
904 }
905 } else {
906 /* no need to prepare the next packets */
907 usb_free_bulk_req(req);
908 }
909
910 mutex_enter(&dp->rxlock);
911 dp->rx_active = B_FALSE;
912 dp->rx_busy_cnt--;
913 if (dp->rx_busy_cnt == 0) {
914 /* wake up someone waits for me */
915 cv_broadcast(&dp->rx_drain_cv);
916 }
917 mutex_exit(&dp->rxlock);
918 done:
919 ;
920 }
921
922 static void
usbgem_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)923 usbgem_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
924 {
925 boolean_t intr;
926 boolean_t tx_sched;
927 struct usbgem_dev *dp;
928
929 dp = (struct usbgem_dev *)req->bulk_client_private;
930 tx_sched = B_FALSE;
931
932 DPRINTF(2, (CE_CONT,
933 "!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
934 dp->name, __func__,
935 usb_str_cr(req->bulk_completion_reason),
936 req->bulk_completion_reason,
937 req->bulk_cb_flags,
938 dp->tx_busy_cnt));
939
940 /* we have finished to transfer the packet into tx fifo */
941 intr = DB_TCI(req->bulk_data);
942 freemsg(req->bulk_data);
943
944 if (req->bulk_completion_reason != USB_CR_OK &&
945 dp->fatal_error == (clock_t)0) {
946 dp->fatal_error = usbgem_timestamp_nz();
947 }
948
949 mutex_enter(&dp->txlock);
950
951 if (intr) {
952 ASSERT(dp->tx_intr_pended > 0);
953 /* find the last interrupt we have scheduled */
954 if (--(dp->tx_intr_pended) == 0) {
955 tx_sched = B_TRUE;
956 }
957 }
958
959 ASSERT(dp->tx_busy_cnt > 0);
960 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
961 dp->tx_free_list = req;
962 dp->tx_busy_cnt--;
963
964 #ifdef CONFIG_TX_LIMITER
965 if (tx_sched) {
966 dp->tx_max_packets =
967 min(dp->tx_max_packets + 1, dp->ugc.usbgc_tx_list_max);
968 }
969 #endif
970 if (dp->mac_state != MAC_STATE_ONLINE && dp->tx_busy_cnt == 0) {
971 cv_broadcast(&dp->tx_drain_cv);
972 }
973
974 mutex_exit(&dp->txlock);
975
976 if (tx_sched) {
977 mac_tx_update(dp->mh);
978 }
979 }
980
981 static void
usbgem_intr_cb(usb_pipe_handle_t ph,usb_intr_req_t * req)982 usbgem_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
983 {
984 struct usbgem_dev *dp;
985
986 dp = (struct usbgem_dev *)req->intr_client_private;
987 dp->stats.intr++;
988
989 if (req->intr_completion_reason == USB_CR_OK) {
990 (*dp->ugc.usbgc_interrupt)(dp, req->intr_data);
991 }
992
993 /* free the request and data */
994 usb_free_intr_req(req);
995 }
996
997 /* ======================================================================== */
998 /*
999 * MII support routines
1000 */
1001 /* ======================================================================== */
1002 static void
usbgem_choose_forcedmode(struct usbgem_dev * dp)1003 usbgem_choose_forcedmode(struct usbgem_dev *dp)
1004 {
1005 /* choose media mode */
1006 if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
1007 dp->speed = USBGEM_SPD_1000;
1008 dp->full_duplex = dp->anadv_1000fdx;
1009 } else if (dp->anadv_100fdx || dp->anadv_100t4) {
1010 dp->speed = USBGEM_SPD_100;
1011 dp->full_duplex = B_TRUE;
1012 } else if (dp->anadv_100hdx) {
1013 dp->speed = USBGEM_SPD_100;
1014 dp->full_duplex = B_FALSE;
1015 } else {
1016 dp->speed = USBGEM_SPD_10;
1017 dp->full_duplex = dp->anadv_10fdx;
1018 }
1019 }
1020
1021 static uint16_t
usbgem_mii_read(struct usbgem_dev * dp,uint_t reg,int * errp)1022 usbgem_mii_read(struct usbgem_dev *dp, uint_t reg, int *errp)
1023 {
1024 uint16_t val;
1025
1026 sema_p(&dp->hal_op_lock);
1027 val = (*dp->ugc.usbgc_mii_read)(dp, reg, errp);
1028 sema_v(&dp->hal_op_lock);
1029
1030 return (val);
1031 }
1032
1033 static void
usbgem_mii_write(struct usbgem_dev * dp,uint_t reg,uint16_t val,int * errp)1034 usbgem_mii_write(struct usbgem_dev *dp, uint_t reg, uint16_t val, int *errp)
1035 {
1036 sema_p(&dp->hal_op_lock);
1037 (*dp->ugc.usbgc_mii_write)(dp, reg, val, errp);
1038 sema_v(&dp->hal_op_lock);
1039 }
1040
1041 static int
usbgem_mii_probe(struct usbgem_dev * dp)1042 usbgem_mii_probe(struct usbgem_dev *dp)
1043 {
1044 int err;
1045
1046 err = (*dp->ugc.usbgc_mii_probe)(dp);
1047 return (err);
1048 }
1049
1050 static int
usbgem_mii_init(struct usbgem_dev * dp)1051 usbgem_mii_init(struct usbgem_dev *dp)
1052 {
1053 int err;
1054
1055 err = (*dp->ugc.usbgc_mii_init)(dp);
1056 return (err);
1057 }
1058
1059 #define fc_cap_decode(x) \
1060 ((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) | \
1061 (((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
1062
1063 int
usbgem_mii_config_default(struct usbgem_dev * dp,int * errp)1064 usbgem_mii_config_default(struct usbgem_dev *dp, int *errp)
1065 {
1066 uint16_t mii_stat;
1067 uint16_t val;
1068
1069 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1070
1071 /*
1072 * Configure bits in advertisement register
1073 */
1074 mii_stat = dp->mii_status;
1075
1076 DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
1077 dp->name, __func__, mii_stat, MII_STATUS_BITS));
1078
1079 if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
1080 /* it's funny */
1081 cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
1082 dp->name, mii_stat, MII_STATUS_BITS);
1083 return (USB_FAILURE);
1084 }
1085
1086 /* Do not change the rest of ability bits in advert reg */
1087 val = usbgem_mii_read(dp, MII_AN_ADVERT, errp) & ~MII_ABILITY_ALL;
1088 if (*errp != USB_SUCCESS) {
1089 goto usberr;
1090 }
1091
1092 DPRINTF(0, (CE_CONT,
1093 "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
1094 dp->name, __func__,
1095 dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
1096 dp->anadv_10fdx, dp->anadv_10hdx));
1097
1098 /* set technology bits */
1099 if (dp->anadv_100t4) {
1100 val |= MII_ABILITY_100BASE_T4;
1101 }
1102 if (dp->anadv_100fdx) {
1103 val |= MII_ABILITY_100BASE_TX_FD;
1104 }
1105 if (dp->anadv_100hdx) {
1106 val |= MII_ABILITY_100BASE_TX;
1107 }
1108 if (dp->anadv_10fdx) {
1109 val |= MII_ABILITY_10BASE_T_FD;
1110 }
1111 if (dp->anadv_10hdx) {
1112 val |= MII_ABILITY_10BASE_T;
1113 }
1114
1115 /* set flow control capabilities */
1116 if (dp->anadv_pause) {
1117 val |= MII_ABILITY_PAUSE;
1118 }
1119 if (dp->anadv_asmpause) {
1120 val |= MII_ABILITY_ASM_DIR;
1121 }
1122
1123 DPRINTF(0, (CE_CONT,
1124 "!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
1125 dp->name, __func__, val, MII_ABILITY_BITS,
1126 dp->anadv_pause, dp->anadv_asmpause));
1127
1128 usbgem_mii_write(dp, MII_AN_ADVERT, val, errp);
1129 if (*errp != USB_SUCCESS) {
1130 goto usberr;
1131 }
1132
1133 if (dp->mii_status & MII_STATUS_XSTATUS) {
1134 /*
1135 * 1000Base-T GMII support
1136 */
1137 if (!dp->anadv_autoneg) {
1138 /* enable manual configuration */
1139 val = MII_1000TC_CFG_EN;
1140 if (dp->anadv_1000t_ms == 2) {
1141 val |= MII_1000TC_CFG_VAL;
1142 }
1143 } else {
1144 val = 0;
1145 if (dp->anadv_1000fdx) {
1146 val |= MII_1000TC_ADV_FULL;
1147 }
1148 if (dp->anadv_1000hdx) {
1149 val |= MII_1000TC_ADV_HALF;
1150 }
1151 switch (dp->anadv_1000t_ms) {
1152 case 1:
1153 /* slave */
1154 val |= MII_1000TC_CFG_EN;
1155 break;
1156
1157 case 2:
1158 /* master */
1159 val |= MII_1000TC_CFG_EN | MII_1000TC_CFG_VAL;
1160 break;
1161
1162 default:
1163 /* auto: do nothing */
1164 break;
1165 }
1166 }
1167 DPRINTF(0, (CE_CONT,
1168 "!%s: %s: setting MII_1000TC reg:%b",
1169 dp->name, __func__, val, MII_1000TC_BITS));
1170
1171 usbgem_mii_write(dp, MII_1000TC, val, errp);
1172 if (*errp != USB_SUCCESS) {
1173 goto usberr;
1174 }
1175 }
1176 return (USB_SUCCESS);
1177
1178 usberr:
1179 return (*errp);
1180 }
1181
1182 static char *usbgem_fc_type[] = {
1183 "without",
1184 "with symmetric",
1185 "with tx",
1186 "with rx",
1187 };
1188
1189 #define USBGEM_LINKUP(dp) mac_link_update((dp)->mh, LINK_STATE_UP)
1190 #define USBGEM_LINKDOWN(dp) mac_link_update((dp)->mh, LINK_STATE_DOWN)
1191
1192 static uint8_t usbgem_fc_result[4 /* my cap */][4 /* lp cap */] = {
1193 /* none symm tx rx/symm */
1194 /* none */
1195 {FLOW_CONTROL_NONE,
1196 FLOW_CONTROL_NONE,
1197 FLOW_CONTROL_NONE,
1198 FLOW_CONTROL_NONE},
1199 /* sym */
1200 {FLOW_CONTROL_NONE,
1201 FLOW_CONTROL_SYMMETRIC,
1202 FLOW_CONTROL_NONE,
1203 FLOW_CONTROL_SYMMETRIC},
1204 /* tx */
1205 {FLOW_CONTROL_NONE,
1206 FLOW_CONTROL_NONE,
1207 FLOW_CONTROL_NONE,
1208 FLOW_CONTROL_TX_PAUSE},
1209 /* rx/symm */
1210 {FLOW_CONTROL_NONE,
1211 FLOW_CONTROL_SYMMETRIC,
1212 FLOW_CONTROL_RX_PAUSE,
1213 FLOW_CONTROL_SYMMETRIC},
1214 };
1215
1216 static boolean_t
usbgem_mii_link_check(struct usbgem_dev * dp,int * oldstatep,int * newstatep)1217 usbgem_mii_link_check(struct usbgem_dev *dp, int *oldstatep, int *newstatep)
1218 {
1219 boolean_t tx_sched = B_FALSE;
1220 uint16_t status;
1221 uint16_t advert;
1222 uint16_t lpable;
1223 uint16_t exp;
1224 uint16_t ctl1000;
1225 uint16_t stat1000;
1226 uint16_t val;
1227 clock_t now;
1228 clock_t diff;
1229 int linkdown_action;
1230 boolean_t fix_phy = B_FALSE;
1231 int err;
1232 uint_t rwlock;
1233
1234 DPRINTF(4, (CE_CONT, "!%s: %s: time:%d state:%d",
1235 dp->name, __func__, ddi_get_lbolt(), dp->mii_state));
1236
1237 if (dp->mii_state != MII_STATE_LINKUP) {
1238 rwlock = RW_WRITER;
1239 } else {
1240 rwlock = RW_READER;
1241 }
1242 again:
1243 rw_enter(&dp->dev_state_lock, rwlock);
1244
1245 /* save old mii state */
1246 *oldstatep = dp->mii_state;
1247
1248 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
1249 /* stop periodic execution of the link watcher */
1250 dp->mii_interval = 0;
1251 tx_sched = B_FALSE;
1252 goto next;
1253 }
1254
1255 now = ddi_get_lbolt();
1256 diff = now - dp->mii_last_check;
1257 dp->mii_last_check = now;
1258
1259 /*
1260 * For NWAM, don't show linkdown state right
1261 * when the device is attached.
1262 */
1263 if (dp->linkup_delay > 0) {
1264 if (dp->linkup_delay > diff) {
1265 dp->linkup_delay -= diff;
1266 } else {
1267 /* link up timeout */
1268 dp->linkup_delay = -1;
1269 }
1270 }
1271
1272 next_nowait:
1273 switch (dp->mii_state) {
1274 case MII_STATE_UNKNOWN:
1275 goto reset_phy;
1276
1277 case MII_STATE_RESETTING:
1278 dp->mii_timer -= diff;
1279 if (dp->mii_timer > 0) {
1280 /* don't read phy registers in resetting */
1281 dp->mii_interval = WATCH_INTERVAL_FAST;
1282 goto next;
1283 }
1284
1285 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1286 if (err != USB_SUCCESS) {
1287 goto usberr;
1288 }
1289 if (val & MII_CONTROL_RESET) {
1290 cmn_err(CE_NOTE,
1291 "!%s: time:%ld resetting phy not complete."
1292 " mii_control:0x%b",
1293 dp->name, ddi_get_lbolt(),
1294 val, MII_CONTROL_BITS);
1295 }
1296
1297 /* ensure neither isolated nor pwrdown nor auto-nego mode */
1298 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1299 if (err != USB_SUCCESS) {
1300 goto usberr;
1301 }
1302 #if USBGEM_DEBUG_LEVEL > 10
1303 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1304 cmn_err(CE_CONT, "!%s: readback control %b",
1305 dp->name, val, MII_CONTROL_BITS);
1306 #endif
1307 /* As resetting PHY has completed, configure PHY registers */
1308 if ((*dp->ugc.usbgc_mii_config)(dp, &err) != USB_SUCCESS) {
1309 /* we failed to configure PHY */
1310 goto usberr;
1311 }
1312
1313 /* prepare for forced mode */
1314 usbgem_choose_forcedmode(dp);
1315
1316 dp->mii_lpable = 0;
1317 dp->mii_advert = 0;
1318 dp->mii_exp = 0;
1319 dp->mii_ctl1000 = 0;
1320 dp->mii_stat1000 = 0;
1321
1322 dp->flow_control = FLOW_CONTROL_NONE;
1323
1324 if (!dp->anadv_autoneg) {
1325 /* skip auto-negotiation phase */
1326 dp->mii_state = MII_STATE_MEDIA_SETUP;
1327 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1328 goto next_nowait;
1329 }
1330
1331 /* issue an auto-negotiation command */
1332 goto autonego;
1333
1334 case MII_STATE_AUTONEGOTIATING:
1335 /*
1336 * Autonegotiation in progress
1337 */
1338 dp->mii_timer -= diff;
1339 if (dp->mii_timer -
1340 (dp->ugc.usbgc_mii_an_timeout - dp->ugc.usbgc_mii_an_wait)
1341 > 0) {
1342 /* wait for minimum time (2.3 - 2.5 sec) */
1343 dp->mii_interval = WATCH_INTERVAL_FAST;
1344 goto next;
1345 }
1346
1347 /* read PHY status */
1348 status = usbgem_mii_read(dp, MII_STATUS, &err);
1349 if (err != USB_SUCCESS) {
1350 goto usberr;
1351 }
1352 DPRINTF(4, (CE_CONT,
1353 "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
1354 dp->name, __func__, dp->mii_state,
1355 status, MII_STATUS_BITS));
1356
1357 if (status & MII_STATUS_REMFAULT) {
1358 /*
1359 * The link parnert told me something wrong happend.
1360 * What do we do ?
1361 */
1362 cmn_err(CE_CONT,
1363 "!%s: auto-negotiation failed: remote fault",
1364 dp->name);
1365 goto autonego;
1366 }
1367
1368 if ((status & MII_STATUS_ANDONE) == 0) {
1369 if (dp->mii_timer <= 0) {
1370 /*
1371 * Auto-negotiation has been timed out,
1372 * Reset PHY and try again.
1373 */
1374 if (!dp->mii_supress_msg) {
1375 cmn_err(CE_WARN,
1376 "!%s: auto-negotiation failed:"
1377 " timeout",
1378 dp->name);
1379 dp->mii_supress_msg = B_TRUE;
1380 }
1381 goto autonego;
1382 }
1383 /*
1384 * Auto-negotiation is in progress. Wait for a while.
1385 */
1386 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1387 goto next;
1388 }
1389
1390 /*
1391 * Auto-negotiation has been completed. Let's go to AN_DONE.
1392 */
1393 dp->mii_state = MII_STATE_AN_DONE;
1394 dp->mii_supress_msg = B_FALSE;
1395 DPRINTF(0, (CE_CONT,
1396 "!%s: auto-negotiation completed, MII_STATUS:%b",
1397 dp->name, status, MII_STATUS_BITS));
1398
1399 if (dp->ugc.usbgc_mii_an_delay > 0) {
1400 dp->mii_timer = dp->ugc.usbgc_mii_an_delay;
1401 dp->mii_interval = drv_usectohz(20*1000);
1402 goto next;
1403 }
1404
1405 dp->mii_timer = 0;
1406 diff = 0;
1407 goto next_nowait;
1408
1409 case MII_STATE_AN_DONE:
1410 /*
1411 * Auto-negotiation has done. Now we can set up media.
1412 */
1413 dp->mii_timer -= diff;
1414 if (dp->mii_timer > 0) {
1415 /* wait for a while */
1416 dp->mii_interval = WATCH_INTERVAL_FAST;
1417 goto next;
1418 }
1419
1420 /*
1421 * Setup speed and duplex mode according with
1422 * the result of auto negotiation.
1423 */
1424
1425 /*
1426 * Read registers required to determin current
1427 * duplex mode and media speed.
1428 */
1429 if (dp->ugc.usbgc_mii_an_delay > 0) {
1430 /* the 'status' variable is not initialized yet */
1431 status = usbgem_mii_read(dp, MII_STATUS, &err);
1432 if (err != USB_SUCCESS) {
1433 goto usberr;
1434 }
1435 }
1436 advert = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
1437 if (err != USB_SUCCESS) {
1438 goto usberr;
1439 }
1440 lpable = usbgem_mii_read(dp, MII_AN_LPABLE, &err);
1441 if (err != USB_SUCCESS) {
1442 goto usberr;
1443 }
1444 exp = usbgem_mii_read(dp, MII_AN_EXPANSION, &err);
1445 if (err != USB_SUCCESS) {
1446 goto usberr;
1447 }
1448 if (exp == 0xffff) {
1449 /* some phys don't have exp register */
1450 exp = 0;
1451 }
1452
1453 ctl1000 = 0;
1454 stat1000 = 0;
1455 if (dp->mii_status & MII_STATUS_XSTATUS) {
1456 ctl1000 = usbgem_mii_read(dp, MII_1000TC, &err);
1457 if (err != USB_SUCCESS) {
1458 goto usberr;
1459 }
1460 stat1000 = usbgem_mii_read(dp, MII_1000TS, &err);
1461 if (err != USB_SUCCESS) {
1462 goto usberr;
1463 }
1464 }
1465 dp->mii_lpable = lpable;
1466 dp->mii_advert = advert;
1467 dp->mii_exp = exp;
1468 dp->mii_ctl1000 = ctl1000;
1469 dp->mii_stat1000 = stat1000;
1470
1471 cmn_err(CE_CONT,
1472 "!%s: auto-negotiation done: "
1473 "status:%b, advert:%b, lpable:%b, exp:%b",
1474 dp->name,
1475 status, MII_STATUS_BITS,
1476 advert, MII_ABILITY_BITS,
1477 lpable, MII_ABILITY_BITS,
1478 exp, MII_AN_EXP_BITS);
1479
1480 DPRINTF(0, (CE_CONT, "!%s: MII_STATUS:%b",
1481 dp->name, status, MII_STATUS_BITS));
1482
1483 if (dp->mii_status & MII_STATUS_XSTATUS) {
1484 cmn_err(CE_CONT,
1485 "! MII_1000TC reg:%b, MII_1000TS reg:%b",
1486 ctl1000, MII_1000TC_BITS,
1487 stat1000, MII_1000TS_BITS);
1488 }
1489
1490 if (usbgem_population(lpable) <= 1 &&
1491 (exp & MII_AN_EXP_LPCANAN) == 0) {
1492 if ((advert & MII_ABILITY_TECH) != lpable) {
1493 cmn_err(CE_WARN,
1494 "!%s: but the link partner doesn't seem"
1495 " to have auto-negotiation capability."
1496 " please check the link configuration.",
1497 dp->name);
1498 }
1499 /*
1500 * it should be a result of pararell detection,
1501 * which cannot detect duplex mode.
1502 */
1503 if ((advert & lpable) == 0 &&
1504 lpable & MII_ABILITY_10BASE_T) {
1505 /* no common technology, try 10M half mode */
1506 lpable |= advert & MII_ABILITY_10BASE_T;
1507 fix_phy = B_TRUE;
1508 }
1509 } else if (lpable == 0) {
1510 cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
1511 goto reset_phy;
1512 }
1513 /*
1514 * configure current link mode according to AN priority.
1515 */
1516 val = advert & lpable;
1517 if ((ctl1000 & MII_1000TC_ADV_FULL) &&
1518 (stat1000 & MII_1000TS_LP_FULL)) {
1519 /* 1000BaseT & full duplex */
1520 dp->speed = USBGEM_SPD_1000;
1521 dp->full_duplex = B_TRUE;
1522 } else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
1523 (stat1000 & MII_1000TS_LP_HALF)) {
1524 /* 1000BaseT & half duplex */
1525 dp->speed = USBGEM_SPD_1000;
1526 dp->full_duplex = B_FALSE;
1527 } else if ((val & MII_ABILITY_100BASE_TX_FD)) {
1528 /* 100BaseTx & fullduplex */
1529 dp->speed = USBGEM_SPD_100;
1530 dp->full_duplex = B_TRUE;
1531 } else if ((val & MII_ABILITY_100BASE_T4)) {
1532 /* 100BaseTx & fullduplex */
1533 dp->speed = USBGEM_SPD_100;
1534 dp->full_duplex = B_TRUE;
1535 } else if ((val & MII_ABILITY_100BASE_TX)) {
1536 /* 100BaseTx & half duplex */
1537 dp->speed = USBGEM_SPD_100;
1538 dp->full_duplex = B_FALSE;
1539 } else if ((val & MII_ABILITY_10BASE_T_FD)) {
1540 /* 10BaseT & full duplex */
1541 dp->speed = USBGEM_SPD_10;
1542 dp->full_duplex = B_TRUE;
1543 } else if ((val & MII_ABILITY_10BASE_T)) {
1544 /* 10BaseT & half duplex */
1545 dp->speed = USBGEM_SPD_10;
1546 dp->full_duplex = B_FALSE;
1547 } else {
1548 /*
1549 * the link partner doesn't seem to have
1550 * auto-negotiation capability and our PHY
1551 * could not report current mode correctly.
1552 * We guess current mode by mii_control register.
1553 */
1554 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1555 if (err != USB_SUCCESS) {
1556 goto usberr;
1557 }
1558
1559 /* select 100m half or 10m half */
1560 dp->speed = (val & MII_CONTROL_100MB) ?
1561 USBGEM_SPD_100 : USBGEM_SPD_10;
1562 dp->full_duplex = B_FALSE;
1563 fix_phy = B_TRUE;
1564
1565 cmn_err(CE_NOTE,
1566 "!%s: auto-negotiation done but "
1567 "common ability not found.\n"
1568 "PHY state: control:%b advert:%b lpable:%b\n"
1569 "guessing %d Mbps %s duplex mode",
1570 dp->name,
1571 val, MII_CONTROL_BITS,
1572 advert, MII_ABILITY_BITS,
1573 lpable, MII_ABILITY_BITS,
1574 usbgem_speed_value[dp->speed],
1575 dp->full_duplex ? "full" : "half");
1576 }
1577
1578 if (dp->full_duplex) {
1579 dp->flow_control =
1580 usbgem_fc_result[fc_cap_decode(advert)]
1581 [fc_cap_decode(lpable)];
1582 } else {
1583 dp->flow_control = FLOW_CONTROL_NONE;
1584 }
1585 dp->mii_state = MII_STATE_MEDIA_SETUP;
1586 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1587 goto next_nowait;
1588
1589 case MII_STATE_MEDIA_SETUP:
1590 DPRINTF(2, (CE_CONT, "!%s: setup midia mode", dp->name));
1591
1592 /* assume the link state is down */
1593 dp->mii_state = MII_STATE_LINKDOWN;
1594 dp->mii_supress_msg = B_FALSE;
1595
1596 /* use short interval */
1597 dp->mii_interval = WATCH_INTERVAL_FAST;
1598
1599 if ((!dp->anadv_autoneg) ||
1600 dp->ugc.usbgc_mii_an_oneshot || fix_phy) {
1601
1602 /*
1603 * write the result of auto negotiation back.
1604 */
1605 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1606 if (err != USB_SUCCESS) {
1607 goto usberr;
1608 }
1609 val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
1610 MII_CONTROL_ANE | MII_CONTROL_RSAN);
1611
1612 if (dp->full_duplex) {
1613 val |= MII_CONTROL_FDUPLEX;
1614 }
1615
1616 switch (dp->speed) {
1617 case USBGEM_SPD_1000:
1618 val |= MII_CONTROL_1000MB;
1619 break;
1620
1621 case USBGEM_SPD_100:
1622 val |= MII_CONTROL_100MB;
1623 break;
1624
1625 default:
1626 cmn_err(CE_WARN, "%s: unknown speed:%d",
1627 dp->name, dp->speed);
1628 /* FALLTHROUGH */
1629
1630 case USBGEM_SPD_10:
1631 /* for USBGEM_SPD_10, do nothing */
1632 break;
1633 }
1634
1635 if (dp->mii_status & MII_STATUS_XSTATUS) {
1636 usbgem_mii_write(dp,
1637 MII_1000TC, MII_1000TC_CFG_EN, &err);
1638 if (err != USB_SUCCESS) {
1639 goto usberr;
1640 }
1641 }
1642 usbgem_mii_write(dp, MII_CONTROL, val, &err);
1643 if (err != USB_SUCCESS) {
1644 goto usberr;
1645 }
1646 }
1647 /*
1648 * XXX -- nic state should be one of
1649 * NIC_STATE_DISCONNECTED
1650 * NIC_STATE_STOPPED
1651 * NIC_STATE_INITIALIZED
1652 * NIC_STATE_ONLINE
1653 */
1654 if (dp->nic_state >= NIC_STATE_INITIALIZED) {
1655 /* notify the result of autonegotiation to mac */
1656 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
1657 goto usberr;
1658 }
1659 }
1660 goto next_nowait;
1661
1662 case MII_STATE_LINKDOWN:
1663 status = usbgem_mii_read(dp, MII_STATUS, &err);
1664 if (err != USB_SUCCESS) {
1665 goto usberr;
1666 }
1667 if (status & MII_STATUS_LINKUP) {
1668 /*
1669 * Link is going up
1670 */
1671 dp->mii_state = MII_STATE_LINKUP;
1672 dp->mii_supress_msg = B_FALSE;
1673
1674 DPRINTF(0, (CE_CONT,
1675 "!%s: link up detected: status:%b",
1676 dp->name, status, MII_STATUS_BITS));
1677
1678 /*
1679 * MII_CONTROL_100MB and MII_CONTROL_FDUPLEX are
1680 * ignored when MII_CONTROL_ANE is set.
1681 */
1682 cmn_err(CE_CONT,
1683 "!%s: Link up: %d Mbps %s duplex %s flow control",
1684 dp->name,
1685 usbgem_speed_value[dp->speed],
1686 dp->full_duplex ? "full" : "half",
1687 usbgem_fc_type[dp->flow_control]);
1688
1689 dp->mii_interval =
1690 dp->ugc.usbgc_mii_link_watch_interval;
1691
1692 if (dp->ugc.usbgc_mii_hw_link_detection &&
1693 dp->nic_state == NIC_STATE_ONLINE) {
1694 dp->mii_interval = 0;
1695 }
1696
1697 if (dp->nic_state == NIC_STATE_ONLINE) {
1698 if (dp->mac_state == MAC_STATE_INITIALIZED) {
1699 (void) usbgem_mac_start(dp);
1700 }
1701 tx_sched = B_TRUE;
1702 }
1703
1704 goto next;
1705 }
1706
1707 dp->mii_supress_msg = B_TRUE;
1708 if (dp->anadv_autoneg) {
1709 dp->mii_timer -= diff;
1710 if (dp->mii_timer <= 0) {
1711 /*
1712 * the link down timer expired.
1713 * need to restart auto-negotiation.
1714 */
1715 linkdown_action =
1716 dp->ugc.usbgc_mii_linkdown_timeout_action;
1717 goto restart_autonego;
1718 }
1719 }
1720 /* don't change mii_state */
1721 goto next;
1722
1723 case MII_STATE_LINKUP:
1724 if (rwlock == RW_READER) {
1725 /* first pass, read mii status */
1726 status = usbgem_mii_read(dp, MII_STATUS, &err);
1727 if (err != USB_SUCCESS) {
1728 goto usberr;
1729 }
1730 }
1731 if ((status & MII_STATUS_LINKUP) == 0) {
1732 /*
1733 * Link is going down
1734 */
1735 cmn_err(CE_NOTE,
1736 "!%s: link down detected: status:%b",
1737 dp->name, status, MII_STATUS_BITS);
1738 /*
1739 * Acquire exclusive lock to change mii_state
1740 */
1741 if (rwlock == RW_READER) {
1742 rwlock = RW_WRITER;
1743 rw_exit(&dp->dev_state_lock);
1744 goto again;
1745 }
1746
1747 dp->mii_state = MII_STATE_LINKDOWN;
1748 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1749
1750 /*
1751 * As we may change the state of the device,
1752 * let us acquire exclusive lock for the state.
1753 */
1754 if (dp->nic_state == NIC_STATE_ONLINE &&
1755 dp->mac_state == MAC_STATE_ONLINE &&
1756 dp->ugc.usbgc_mii_stop_mac_on_linkdown) {
1757 (void) usbgem_restart_nic(dp);
1758 /* drain tx */
1759 tx_sched = B_TRUE;
1760 }
1761
1762 if (dp->anadv_autoneg) {
1763 /* need to restart auto-negotiation */
1764 linkdown_action =
1765 dp->ugc.usbgc_mii_linkdown_action;
1766 goto restart_autonego;
1767 }
1768 /*
1769 * don't use hw link down detection until the link
1770 * status become stable for a while.
1771 */
1772 dp->mii_interval =
1773 dp->ugc.usbgc_mii_link_watch_interval;
1774
1775 goto next;
1776 }
1777
1778 /*
1779 * still link up, no need to change mii_state
1780 */
1781 if (dp->ugc.usbgc_mii_hw_link_detection &&
1782 dp->nic_state == NIC_STATE_ONLINE) {
1783 /*
1784 * no need to check link status periodicly
1785 * if nic can generate interrupts when link go down.
1786 */
1787 dp->mii_interval = 0;
1788 }
1789 goto next;
1790 }
1791 /* NOTREACHED */
1792 cmn_err(CE_PANIC, "!%s: %s: not reached", dp->name, __func__);
1793
1794 /*
1795 * Actions for new state.
1796 */
1797 restart_autonego:
1798 switch (linkdown_action) {
1799 case MII_ACTION_RESET:
1800 if (!dp->mii_supress_msg) {
1801 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
1802 }
1803 dp->mii_supress_msg = B_TRUE;
1804 goto reset_phy;
1805
1806 case MII_ACTION_NONE:
1807 dp->mii_supress_msg = B_TRUE;
1808 if (dp->ugc.usbgc_mii_an_oneshot) {
1809 goto autonego;
1810 }
1811 /* PHY will restart autonego automatically */
1812 dp->mii_state = MII_STATE_AUTONEGOTIATING;
1813 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
1814 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1815 goto next;
1816
1817 case MII_ACTION_RSA:
1818 if (!dp->mii_supress_msg) {
1819 cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
1820 dp->name);
1821 }
1822 dp->mii_supress_msg = B_TRUE;
1823 goto autonego;
1824
1825 default:
1826 cmn_err(CE_PANIC, "!%s: unknowm linkdown action: %d",
1827 dp->name, dp->ugc.usbgc_mii_linkdown_action);
1828 }
1829 /* NOTREACHED */
1830
1831 reset_phy:
1832 if (!dp->mii_supress_msg) {
1833 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
1834 }
1835 dp->mii_state = MII_STATE_RESETTING;
1836 dp->mii_timer = dp->ugc.usbgc_mii_reset_timeout;
1837 if (!dp->ugc.usbgc_mii_dont_reset) {
1838 usbgem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET, &err);
1839 if (err != USB_SUCCESS) {
1840 goto usberr;
1841 }
1842 }
1843 dp->mii_interval = WATCH_INTERVAL_FAST;
1844 goto next;
1845
1846 autonego:
1847 if (!dp->mii_supress_msg) {
1848 cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
1849 }
1850 dp->mii_state = MII_STATE_AUTONEGOTIATING;
1851 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
1852
1853 /* start/restart autoneg */
1854 val = usbgem_mii_read(dp, MII_CONTROL, &err) &
1855 ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
1856 if (err != USB_SUCCESS) {
1857 goto usberr;
1858 }
1859 if (val & MII_CONTROL_ANE) {
1860 val |= MII_CONTROL_RSAN;
1861 }
1862 usbgem_mii_write(dp, MII_CONTROL,
1863 val | dp->ugc.usbgc_mii_an_cmd | MII_CONTROL_ANE, &err);
1864 if (err != USB_SUCCESS) {
1865 goto usberr;
1866 }
1867
1868 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1869 goto next;
1870
1871 usberr:
1872 dp->mii_state = MII_STATE_UNKNOWN;
1873 dp->mii_interval = dp->ugc.usbgc_mii_link_watch_interval;
1874 tx_sched = B_TRUE;
1875
1876 next:
1877 *newstatep = dp->mii_state;
1878 rw_exit(&dp->dev_state_lock);
1879 return (tx_sched);
1880 }
1881
1882 static void
usbgem_mii_link_watcher(struct usbgem_dev * dp)1883 usbgem_mii_link_watcher(struct usbgem_dev *dp)
1884 {
1885 int old_mii_state;
1886 int new_mii_state;
1887 boolean_t tx_sched;
1888
1889 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1890
1891 for (; ; ) {
1892
1893 mutex_enter(&dp->link_watcher_lock);
1894 if (dp->mii_interval) {
1895 (void) cv_timedwait(&dp->link_watcher_wait_cv,
1896 &dp->link_watcher_lock,
1897 dp->mii_interval + ddi_get_lbolt());
1898 } else {
1899 cv_wait(&dp->link_watcher_wait_cv,
1900 &dp->link_watcher_lock);
1901 }
1902 mutex_exit(&dp->link_watcher_lock);
1903
1904 if (dp->link_watcher_stop) {
1905 break;
1906 }
1907
1908 /* we block callbacks from disconnect/suspend and restart */
1909 tx_sched = usbgem_mii_link_check(dp,
1910 &old_mii_state, &new_mii_state);
1911
1912 /*
1913 * gld v2 notifier functions are not able to
1914 * be called with any locks in this layer.
1915 */
1916 if (tx_sched) {
1917 /* kick potentially stopped downstream */
1918 mac_tx_update(dp->mh);
1919 }
1920
1921 if (old_mii_state != new_mii_state) {
1922 /* notify new mii link state */
1923 if (new_mii_state == MII_STATE_LINKUP) {
1924 dp->linkup_delay = 0;
1925 USBGEM_LINKUP(dp);
1926 } else if (dp->linkup_delay <= 0) {
1927 USBGEM_LINKDOWN(dp);
1928 }
1929 } else if (dp->linkup_delay < 0) {
1930 /* first linkup timeout */
1931 dp->linkup_delay = 0;
1932 USBGEM_LINKDOWN(dp);
1933 }
1934 }
1935
1936 thread_exit();
1937 }
1938
1939 void
usbgem_mii_update_link(struct usbgem_dev * dp)1940 usbgem_mii_update_link(struct usbgem_dev *dp)
1941 {
1942 cv_signal(&dp->link_watcher_wait_cv);
1943 }
1944
1945 int
usbgem_mii_probe_default(struct usbgem_dev * dp)1946 usbgem_mii_probe_default(struct usbgem_dev *dp)
1947 {
1948 int phy;
1949 uint16_t status;
1950 uint16_t xstatus;
1951 int err;
1952 uint16_t adv;
1953 uint16_t adv_org;
1954
1955 DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1956
1957 /*
1958 * Scan PHY
1959 */
1960 dp->mii_status = 0;
1961
1962 /* Try default phy first */
1963 if (dp->mii_phy_addr) {
1964 status = usbgem_mii_read(dp, MII_STATUS, &err);
1965 if (err != USB_SUCCESS) {
1966 goto usberr;
1967 }
1968 if (status != 0xffff && status != 0x0000) {
1969 goto PHY_found;
1970 }
1971
1972 if (dp->mii_phy_addr < 0) {
1973 cmn_err(CE_NOTE,
1974 "!%s: failed to probe default internal and/or non-MII PHY",
1975 dp->name);
1976 return (USB_FAILURE);
1977 }
1978
1979 cmn_err(CE_NOTE,
1980 "!%s: failed to probe default MII PHY at %d",
1981 dp->name, dp->mii_phy_addr);
1982 }
1983
1984 /* Try all possible address */
1985 for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
1986 dp->mii_phy_addr = phy;
1987 status = usbgem_mii_read(dp, MII_STATUS, &err);
1988 if (err != USB_SUCCESS) {
1989 DPRINTF(0, (CE_CONT,
1990 "!%s: %s: mii_read(status) failed",
1991 dp->name, __func__));
1992 goto usberr;
1993 }
1994
1995 if (status != 0xffff && status != 0x0000) {
1996 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1997 if (err != USB_SUCCESS) {
1998 DPRINTF(0, (CE_CONT,
1999 "!%s: %s: mii_write(control) failed",
2000 dp->name, __func__));
2001 goto usberr;
2002 }
2003 goto PHY_found;
2004 }
2005 }
2006 for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2007 dp->mii_phy_addr = phy;
2008 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2009 if (err != USB_SUCCESS) {
2010 DPRINTF(0, (CE_CONT,
2011 "!%s: %s: mii_write(control) failed",
2012 dp->name, __func__));
2013 goto usberr;
2014 }
2015 status = usbgem_mii_read(dp, MII_STATUS, &err);
2016 if (err != USB_SUCCESS) {
2017 DPRINTF(0, (CE_CONT,
2018 "!%s: %s: mii_read(status) failed",
2019 dp->name, __func__));
2020 goto usberr;
2021 }
2022
2023 if (status != 0xffff && status != 0) {
2024 goto PHY_found;
2025 }
2026 }
2027
2028 cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
2029 return (USB_FAILURE);
2030
2031 PHY_found:
2032 dp->mii_status = status;
2033 dp->mii_status_ro = ~status;
2034 dp->mii_phy_id = usbgem_mii_read(dp, MII_PHYIDH, &err) << 16;
2035 if (err != USB_SUCCESS) {
2036 DPRINTF(0, (CE_CONT,
2037 "!%s: %s: mii_read(PHYIDH) failed",
2038 dp->name, __func__));
2039 goto usberr;
2040 }
2041 dp->mii_phy_id |= usbgem_mii_read(dp, MII_PHYIDL, &err);
2042 if (err != USB_SUCCESS) {
2043 DPRINTF(0, (CE_CONT,
2044 "!%s: %s: mii_read(PHYIDL) failed",
2045 dp->name, __func__));
2046 goto usberr;
2047 }
2048
2049 if (dp->mii_phy_addr < 0) {
2050 cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
2051 dp->name, dp->mii_phy_id);
2052 } else {
2053 cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
2054 dp->name, dp->mii_phy_id, dp->mii_phy_addr);
2055 }
2056
2057 cmn_err(CE_CONT,
2058 "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
2059 dp->name,
2060 usbgem_mii_read(dp, MII_CONTROL, &err), MII_CONTROL_BITS,
2061 status, MII_STATUS_BITS,
2062 usbgem_mii_read(dp, MII_AN_ADVERT, &err), MII_ABILITY_BITS,
2063 usbgem_mii_read(dp, MII_AN_LPABLE, &err), MII_ABILITY_BITS,
2064 usbgem_mii_read(dp, MII_AN_EXPANSION, &err), MII_AN_EXP_BITS);
2065
2066 dp->mii_xstatus = 0;
2067 if (status & MII_STATUS_XSTATUS) {
2068 dp->mii_xstatus = usbgem_mii_read(dp, MII_XSTATUS, &err);
2069
2070 cmn_err(CE_CONT, "!%s: xstatus:%b",
2071 dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
2072 }
2073 dp->mii_xstatus_ro = ~dp->mii_xstatus;
2074
2075 /* check if the phy can advertize pause abilities */
2076 adv_org = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2077 if (err != USB_SUCCESS) {
2078 goto usberr;
2079 }
2080
2081 usbgem_mii_write(dp, MII_AN_ADVERT,
2082 MII_ABILITY_PAUSE | MII_ABILITY_ASM_DIR, &err);
2083 if (err != USB_SUCCESS) {
2084 goto usberr;
2085 }
2086
2087 adv = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2088 if (err != USB_SUCCESS) {
2089 goto usberr;
2090 }
2091
2092 if ((adv & MII_ABILITY_PAUSE) == 0) {
2093 dp->ugc.usbgc_flow_control &= ~1;
2094 }
2095
2096 if ((adv & MII_ABILITY_ASM_DIR) == 0) {
2097 dp->ugc.usbgc_flow_control &= ~2;
2098 }
2099
2100 usbgem_mii_write(dp, MII_AN_ADVERT, adv_org, &err);
2101 if (err != USB_SUCCESS) {
2102 goto usberr;
2103 }
2104 return (USB_SUCCESS);
2105
2106 usberr:
2107 return (USB_FAILURE);
2108 }
2109
2110 int
usbgem_mii_init_default(struct usbgem_dev * dp)2111 usbgem_mii_init_default(struct usbgem_dev *dp)
2112 {
2113 /* ENPTY */
2114 return (USB_SUCCESS);
2115 }
2116
2117 static int
usbgem_mii_start(struct usbgem_dev * dp)2118 usbgem_mii_start(struct usbgem_dev *dp)
2119 {
2120 int err;
2121 kthread_t *lwth;
2122
2123 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2124
2125 /* make a first call of usbgem_mii_link_check() */
2126 dp->link_watcher_stop = 0;
2127 dp->mii_state = MII_STATE_UNKNOWN;
2128 dp->mii_interval = drv_usectohz(1000*1000); /* 1sec */
2129 dp->mii_last_check = ddi_get_lbolt();
2130 dp->linkup_delay = 600 * drv_usectohz(1000*1000); /* 10 minutes */
2131
2132 lwth = thread_create(NULL, 0, usbgem_mii_link_watcher, dp, 0, &p0,
2133 TS_RUN, minclsyspri);
2134 if (lwth == NULL) {
2135 cmn_err(CE_WARN,
2136 "!%s: %s: failed to create a link watcher thread",
2137 dp->name, __func__);
2138 return (USB_FAILURE);
2139 }
2140 dp->link_watcher_did = lwth->t_did;
2141
2142 return (USB_SUCCESS);
2143 }
2144
2145 static void
usbgem_mii_stop(struct usbgem_dev * dp)2146 usbgem_mii_stop(struct usbgem_dev *dp)
2147 {
2148 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2149
2150 /* Ensure timer routine stopped */
2151 dp->link_watcher_stop = 1;
2152 cv_signal(&dp->link_watcher_wait_cv);
2153 thread_join(dp->link_watcher_did);
2154 }
2155
2156 /* ============================================================== */
2157 /*
2158 * internal mac register operation interface
2159 */
2160 /* ============================================================== */
2161 /*
2162 * usbgem_mac_init: cold start
2163 */
2164 static int
usbgem_mac_init(struct usbgem_dev * dp)2165 usbgem_mac_init(struct usbgem_dev *dp)
2166 {
2167 int err;
2168
2169 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2170
2171 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2172 /* pretend we succeeded */
2173 return (USB_SUCCESS);
2174 }
2175
2176 ASSERT(dp->mac_state == MAC_STATE_STOPPED);
2177
2178 /* reset fatal error timestamp */
2179 dp->fatal_error = (clock_t)0;
2180
2181 /* reset tx side state */
2182 mutex_enter(&dp->txlock);
2183 dp->tx_busy_cnt = 0;
2184 dp->tx_max_packets = dp->ugc.usbgc_tx_list_max;
2185 mutex_exit(&dp->txlock);
2186
2187 /* reset rx side state */
2188 mutex_enter(&dp->rxlock);
2189 dp->rx_busy_cnt = 0;
2190 mutex_exit(&dp->rxlock);
2191
2192 err = usbgem_hal_init_chip(dp);
2193 if (err == USB_SUCCESS) {
2194 dp->mac_state = MAC_STATE_INITIALIZED;
2195 }
2196
2197 return (err);
2198 }
2199
2200 /*
2201 * usbgem_mac_start: warm start
2202 */
2203 static int
usbgem_mac_start(struct usbgem_dev * dp)2204 usbgem_mac_start(struct usbgem_dev *dp)
2205 {
2206 int err;
2207 int i;
2208 usb_flags_t flags = 0;
2209 usb_intr_req_t *req;
2210 #ifdef USBGEM_DEBUG_LEVEL
2211 usb_pipe_state_t p_state;
2212 #endif
2213 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2214
2215 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2216 /* do nothing but don't return failure */
2217 return (USB_SUCCESS);
2218 }
2219
2220 if (dp->mac_state != MAC_STATE_INITIALIZED) {
2221 /* don't return failer */
2222 DPRINTF(0, (CE_CONT,
2223 "!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
2224 dp->name, __func__, dp->mac_state));
2225 goto x;
2226 }
2227
2228 dp->mac_state = MAC_STATE_ONLINE;
2229
2230 if (usbgem_hal_start_chip(dp) != USB_SUCCESS) {
2231 cmn_err(CE_NOTE,
2232 "!%s: %s: usb error was detected during start_chip",
2233 dp->name, __func__);
2234 goto x;
2235 }
2236
2237 #ifdef USBGEM_DEBUG_LEVEL
2238 usb_pipe_get_state(dp->intr_pipe, &p_state, 0);
2239 ASSERT(p_state == USB_PIPE_STATE_IDLE);
2240 #endif /* USBGEM_DEBUG_LEVEL */
2241
2242 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2243
2244 /* make a request for interrupt */
2245
2246 req = usb_alloc_intr_req(dp->dip, 0, USB_FLAGS_SLEEP);
2247 if (req == NULL) {
2248 cmn_err(CE_WARN, "!%s: %s: failed to allocate intreq",
2249 dp->name, __func__);
2250 goto x;
2251 }
2252 req->intr_data = NULL;
2253 req->intr_client_private = (usb_opaque_t)dp;
2254 req->intr_timeout = 0;
2255 req->intr_attributes =
2256 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
2257 req->intr_len = dp->ep_intr->wMaxPacketSize;
2258 req->intr_cb = usbgem_intr_cb;
2259 req->intr_exc_cb = usbgem_intr_cb;
2260 req->intr_completion_reason = 0;
2261 req->intr_cb_flags = 0;
2262
2263 err = usb_pipe_intr_xfer(dp->intr_pipe, req, flags);
2264 if (err != USB_SUCCESS) {
2265 cmn_err(CE_WARN,
2266 "%s: err:%d failed to start polling of intr pipe",
2267 dp->name, err);
2268 goto x;
2269 }
2270 }
2271
2272 /* kick to receive the first packet */
2273 if (usbgem_init_rx_buf(dp) != USB_SUCCESS) {
2274 goto err_stop_intr;
2275 }
2276 dp->rx_active = B_TRUE;
2277
2278 return (USB_SUCCESS);
2279
2280 err_stop_intr:
2281 /* stop the interrupt pipe */
2282 DPRINTF(0, (CE_CONT, "!%s: %s: FAULURE", dp->name, __func__));
2283 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2284 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2285 }
2286 x:
2287 ASSERT(dp->mac_state == MAC_STATE_ONLINE);
2288 /* we use another flag to indicate error state. */
2289 if (dp->fatal_error == (clock_t)0) {
2290 dp->fatal_error = usbgem_timestamp_nz();
2291 }
2292 return (USB_FAILURE);
2293 }
2294
2295 static int
usbgem_mac_stop(struct usbgem_dev * dp,int new_state,boolean_t graceful)2296 usbgem_mac_stop(struct usbgem_dev *dp, int new_state, boolean_t graceful)
2297 {
2298 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2299
2300 /*
2301 * we must have writer lock for dev_state_lock
2302 */
2303 ASSERT(new_state == MAC_STATE_STOPPED ||
2304 new_state == MAC_STATE_DISCONNECTED);
2305
2306 /* stop polling interrupt pipe */
2307 if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2308 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2309 }
2310
2311 if (new_state == MAC_STATE_STOPPED || graceful) {
2312 /* stop the nic hardware completely */
2313 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
2314 (void) usbgem_hal_reset_chip(dp);
2315 }
2316 }
2317
2318 /* stop preparing new rx packets and sending new packets */
2319 dp->mac_state = new_state;
2320
2321 /* other processors must get mac_state correctly after here */
2322 membar_producer();
2323
2324 /* cancel all requests we have sent */
2325 usb_pipe_reset(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
2326 usb_pipe_reset(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
2327
2328 DPRINTF(0, (CE_CONT,
2329 "!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
2330 dp->name, __func__, dp->rx_busy_cnt, dp->tx_busy_cnt));
2331
2332 /*
2333 * Here all rx packets has been cancelled and their call back
2334 * function has been exeuted, because we called usb_pipe_reset
2335 * synchronously.
2336 * So actually we just ensure rx_busy_cnt == 0.
2337 */
2338 mutex_enter(&dp->rxlock);
2339 while (dp->rx_busy_cnt > 0) {
2340 cv_wait(&dp->rx_drain_cv, &dp->rxlock);
2341 }
2342 mutex_exit(&dp->rxlock);
2343
2344 DPRINTF(0, (CE_CONT, "!%s: %s: rx_busy_cnt is %d now",
2345 dp->name, __func__, dp->rx_busy_cnt));
2346
2347 mutex_enter(&dp->txlock);
2348 while (dp->tx_busy_cnt > 0) {
2349 cv_wait(&dp->tx_drain_cv, &dp->txlock);
2350 }
2351 mutex_exit(&dp->txlock);
2352
2353 DPRINTF(0, (CE_CONT, "!%s: %s: tx_busy_cnt is %d now",
2354 dp->name, __func__, dp->tx_busy_cnt));
2355
2356 return (USB_SUCCESS);
2357 }
2358
2359 static int
usbgem_add_multicast(struct usbgem_dev * dp,const uint8_t * ep)2360 usbgem_add_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2361 {
2362 int cnt;
2363 int err;
2364
2365 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2366
2367 sema_p(&dp->rxfilter_lock);
2368 if (dp->mc_count_req++ < USBGEM_MAXMC) {
2369 /* append the new address at the end of the mclist */
2370 cnt = dp->mc_count;
2371 bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
2372 ETHERADDRL);
2373 if (dp->ugc.usbgc_multicast_hash) {
2374 dp->mc_list[cnt].hash =
2375 (*dp->ugc.usbgc_multicast_hash)(dp, ep);
2376 }
2377 dp->mc_count = cnt + 1;
2378 }
2379
2380 if (dp->mc_count_req != dp->mc_count) {
2381 /* multicast address list overflow */
2382 dp->rxmode |= RXMODE_MULTI_OVF;
2383 } else {
2384 dp->rxmode &= ~RXMODE_MULTI_OVF;
2385 }
2386
2387 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2388 /* tell new multicast list to the hardware */
2389 err = usbgem_hal_set_rx_filter(dp);
2390 }
2391 sema_v(&dp->rxfilter_lock);
2392
2393 return (err);
2394 }
2395
2396 static int
usbgem_remove_multicast(struct usbgem_dev * dp,const uint8_t * ep)2397 usbgem_remove_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2398 {
2399 size_t len;
2400 int i;
2401 int cnt;
2402 int err;
2403
2404 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2405
2406 sema_p(&dp->rxfilter_lock);
2407 dp->mc_count_req--;
2408 cnt = dp->mc_count;
2409 for (i = 0; i < cnt; i++) {
2410 if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
2411 continue;
2412 }
2413 /* shrink the mclist by copying forward */
2414 len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
2415 if (len > 0) {
2416 bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
2417 }
2418 dp->mc_count--;
2419 break;
2420 }
2421
2422 if (dp->mc_count_req != dp->mc_count) {
2423 /* multicast address list overflow */
2424 dp->rxmode |= RXMODE_MULTI_OVF;
2425 } else {
2426 dp->rxmode &= ~RXMODE_MULTI_OVF;
2427 }
2428
2429 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2430 err = usbgem_hal_set_rx_filter(dp);
2431 }
2432 sema_v(&dp->rxfilter_lock);
2433
2434 return (err);
2435 }
2436
2437
2438 /* ============================================================== */
2439 /*
2440 * ioctl
2441 */
2442 /* ============================================================== */
2443 enum ioc_reply {
2444 IOC_INVAL = -1, /* bad, NAK with EINVAL */
2445 IOC_DONE, /* OK, reply sent */
2446 IOC_ACK, /* OK, just send ACK */
2447 IOC_REPLY, /* OK, just send reply */
2448 IOC_RESTART_ACK, /* OK, restart & ACK */
2449 IOC_RESTART_REPLY /* OK, restart & reply */
2450 };
2451
2452
2453 static int
usbgem_get_def_val(struct usbgem_dev * dp,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)2454 usbgem_get_def_val(struct usbgem_dev *dp, mac_prop_id_t pr_num,
2455 uint_t pr_valsize, void *pr_val)
2456 {
2457 link_flowctrl_t fl;
2458 int err = 0;
2459
2460 ASSERT(pr_valsize > 0);
2461 switch (pr_num) {
2462 case MAC_PROP_AUTONEG:
2463 *(uint8_t *)pr_val =
2464 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
2465 break;
2466
2467 case MAC_PROP_FLOWCTRL:
2468 if (pr_valsize < sizeof (link_flowctrl_t)) {
2469 return (EINVAL);
2470 }
2471 switch (dp->ugc.usbgc_flow_control) {
2472 case FLOW_CONTROL_NONE:
2473 fl = LINK_FLOWCTRL_NONE;
2474 break;
2475 case FLOW_CONTROL_SYMMETRIC:
2476 fl = LINK_FLOWCTRL_BI;
2477 break;
2478 case FLOW_CONTROL_TX_PAUSE:
2479 fl = LINK_FLOWCTRL_TX;
2480 break;
2481 case FLOW_CONTROL_RX_PAUSE:
2482 fl = LINK_FLOWCTRL_RX;
2483 break;
2484 }
2485 bcopy(&fl, pr_val, sizeof (fl));
2486 break;
2487
2488 case MAC_PROP_ADV_1000FDX_CAP:
2489 case MAC_PROP_EN_1000FDX_CAP:
2490 *(uint8_t *)pr_val =
2491 (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
2492 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
2493 break;
2494
2495 case MAC_PROP_ADV_1000HDX_CAP:
2496 case MAC_PROP_EN_1000HDX_CAP:
2497 *(uint8_t *)pr_val =
2498 (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
2499 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
2500 break;
2501
2502 case MAC_PROP_ADV_100T4_CAP:
2503 case MAC_PROP_EN_100T4_CAP:
2504 *(uint8_t *)pr_val =
2505 BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
2506 break;
2507
2508 case MAC_PROP_ADV_100FDX_CAP:
2509 case MAC_PROP_EN_100FDX_CAP:
2510 *(uint8_t *)pr_val =
2511 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
2512 break;
2513
2514 case MAC_PROP_ADV_100HDX_CAP:
2515 case MAC_PROP_EN_100HDX_CAP:
2516 *(uint8_t *)pr_val =
2517 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
2518 break;
2519
2520 case MAC_PROP_ADV_10FDX_CAP:
2521 case MAC_PROP_EN_10FDX_CAP:
2522 *(uint8_t *)pr_val =
2523 BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
2524 break;
2525
2526 case MAC_PROP_ADV_10HDX_CAP:
2527 case MAC_PROP_EN_10HDX_CAP:
2528 *(uint8_t *)pr_val =
2529 BOOLEAN(dp->mii_status & MII_STATUS_10);
2530 break;
2531
2532 default:
2533 err = ENOTSUP;
2534 break;
2535 }
2536 return (err);
2537 }
2538
2539 static void
usbgem_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)2540 usbgem_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2541 mac_prop_info_handle_t prh)
2542 {
2543 struct usbgem_dev *dp = arg;
2544 link_flowctrl_t fl;
2545
2546 /*
2547 * By default permissions are read/write unless specified
2548 * otherwise by the driver.
2549 */
2550
2551 switch (pr_num) {
2552 case MAC_PROP_DUPLEX:
2553 case MAC_PROP_SPEED:
2554 case MAC_PROP_STATUS:
2555 case MAC_PROP_ADV_1000FDX_CAP:
2556 case MAC_PROP_ADV_1000HDX_CAP:
2557 case MAC_PROP_ADV_100FDX_CAP:
2558 case MAC_PROP_ADV_100HDX_CAP:
2559 case MAC_PROP_ADV_10FDX_CAP:
2560 case MAC_PROP_ADV_10HDX_CAP:
2561 case MAC_PROP_ADV_100T4_CAP:
2562 case MAC_PROP_EN_100T4_CAP:
2563 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2564 break;
2565
2566 case MAC_PROP_EN_1000FDX_CAP:
2567 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0) {
2568 mac_prop_info_set_default_uint8(prh,
2569 BOOLEAN(
2570 dp->mii_xstatus & MII_XSTATUS_1000BASET_FD));
2571 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)
2572 == 0) {
2573 mac_prop_info_set_default_uint8(prh,
2574 BOOLEAN(
2575 dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD));
2576 } else {
2577 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2578 }
2579 break;
2580
2581 case MAC_PROP_EN_1000HDX_CAP:
2582 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0) {
2583 mac_prop_info_set_default_uint8(prh,
2584 BOOLEAN(
2585 dp->mii_xstatus & MII_XSTATUS_1000BASET));
2586 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2587 mac_prop_info_set_default_uint8(prh,
2588 BOOLEAN(
2589 dp->mii_xstatus & MII_XSTATUS_1000BASEX));
2590 } else {
2591 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2592 }
2593 break;
2594
2595 case MAC_PROP_EN_100FDX_CAP:
2596 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2597 mac_prop_info_set_default_uint8(prh,
2598 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD));
2599 } else {
2600 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2601 }
2602 break;
2603
2604 case MAC_PROP_EN_100HDX_CAP:
2605 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2606 mac_prop_info_set_default_uint8(prh,
2607 BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX));
2608 } else {
2609 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2610 }
2611 break;
2612
2613 case MAC_PROP_EN_10FDX_CAP:
2614 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2615 mac_prop_info_set_default_uint8(prh,
2616 BOOLEAN(dp->mii_status & MII_STATUS_10_FD));
2617 } else {
2618 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2619 }
2620 break;
2621
2622 case MAC_PROP_EN_10HDX_CAP:
2623 if ((dp->mii_status_ro & MII_STATUS_10) == 0) {
2624 mac_prop_info_set_default_uint8(prh,
2625 BOOLEAN(dp->mii_status & MII_STATUS_10));
2626 } else {
2627 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2628 }
2629 break;
2630
2631 case MAC_PROP_AUTONEG:
2632 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2633 mac_prop_info_set_default_uint8(prh,
2634 BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG));
2635 } else {
2636 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2637 }
2638 break;
2639
2640 case MAC_PROP_FLOWCTRL:
2641 switch (dp->ugc.usbgc_flow_control) {
2642 case FLOW_CONTROL_NONE:
2643 fl = LINK_FLOWCTRL_NONE;
2644 break;
2645 case FLOW_CONTROL_SYMMETRIC:
2646 fl = LINK_FLOWCTRL_BI;
2647 break;
2648 case FLOW_CONTROL_TX_PAUSE:
2649 fl = LINK_FLOWCTRL_TX;
2650 break;
2651 case FLOW_CONTROL_RX_PAUSE:
2652 fl = LINK_FLOWCTRL_RX;
2653 break;
2654 }
2655 mac_prop_info_set_default_link_flowctrl(prh, fl);
2656 break;
2657
2658 case MAC_PROP_MTU:
2659 mac_prop_info_set_range_uint32(prh,
2660 dp->ugc.usbgc_min_mtu, dp->ugc.usbgc_max_mtu);
2661 break;
2662
2663 case MAC_PROP_PRIVATE:
2664 break;
2665 }
2666 }
2667
2668 static int
usbgem_m_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)2669 usbgem_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2670 uint_t pr_valsize, const void *pr_val)
2671 {
2672 struct usbgem_dev *dp = arg;
2673 int err = 0;
2674 boolean_t update = B_FALSE;
2675 link_flowctrl_t flowctrl;
2676 uint32_t cur_mtu, new_mtu;
2677
2678 rw_enter(&dp->dev_state_lock, RW_WRITER);
2679 switch (pr_num) {
2680 case MAC_PROP_EN_1000FDX_CAP:
2681 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0 ||
2682 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD) == 0) {
2683 if (dp->anadv_1000fdx != *(uint8_t *)pr_val) {
2684 dp->anadv_1000fdx = *(uint8_t *)pr_val;
2685 update = B_TRUE;
2686 }
2687 } else {
2688 err = ENOTSUP;
2689 }
2690 break;
2691
2692 case MAC_PROP_EN_1000HDX_CAP:
2693 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0 ||
2694 (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2695 if (dp->anadv_1000hdx != *(uint8_t *)pr_val) {
2696 dp->anadv_1000hdx = *(uint8_t *)pr_val;
2697 update = B_TRUE;
2698 }
2699 } else {
2700 err = ENOTSUP;
2701 }
2702 break;
2703
2704 case MAC_PROP_EN_100FDX_CAP:
2705 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2706 if (dp->anadv_100fdx != *(uint8_t *)pr_val) {
2707 dp->anadv_100fdx = *(uint8_t *)pr_val;
2708 update = B_TRUE;
2709 }
2710 } else {
2711 err = ENOTSUP;
2712 }
2713 break;
2714
2715 case MAC_PROP_EN_100HDX_CAP:
2716 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2717 if (dp->anadv_100hdx != *(uint8_t *)pr_val) {
2718 dp->anadv_100hdx = *(uint8_t *)pr_val;
2719 update = B_TRUE;
2720 }
2721 } else {
2722 err = ENOTSUP;
2723 }
2724 break;
2725
2726 case MAC_PROP_EN_10FDX_CAP:
2727 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2728 if (dp->anadv_10fdx != *(uint8_t *)pr_val) {
2729 dp->anadv_10fdx = *(uint8_t *)pr_val;
2730 update = B_TRUE;
2731 }
2732 } else {
2733 err = ENOTSUP;
2734 }
2735 break;
2736
2737 case MAC_PROP_EN_10HDX_CAP:
2738 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2739 if (dp->anadv_10hdx != *(uint8_t *)pr_val) {
2740 dp->anadv_10hdx = *(uint8_t *)pr_val;
2741 update = B_TRUE;
2742 }
2743 } else {
2744 err = ENOTSUP;
2745 }
2746 break;
2747
2748 case MAC_PROP_AUTONEG:
2749 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2750 if (dp->anadv_autoneg != *(uint8_t *)pr_val) {
2751 dp->anadv_autoneg = *(uint8_t *)pr_val;
2752 update = B_TRUE;
2753 }
2754 } else {
2755 err = ENOTSUP;
2756 }
2757 break;
2758
2759 case MAC_PROP_FLOWCTRL:
2760 bcopy(pr_val, &flowctrl, sizeof (flowctrl));
2761
2762 switch (flowctrl) {
2763 default:
2764 err = EINVAL;
2765 break;
2766
2767 case LINK_FLOWCTRL_NONE:
2768 if (dp->flow_control != FLOW_CONTROL_NONE) {
2769 dp->flow_control = FLOW_CONTROL_NONE;
2770 update = B_TRUE;
2771 }
2772 break;
2773
2774 case LINK_FLOWCTRL_RX:
2775 if (dp->flow_control != FLOW_CONTROL_RX_PAUSE) {
2776 dp->flow_control = FLOW_CONTROL_RX_PAUSE;
2777 update = B_TRUE;
2778 }
2779 break;
2780
2781 case LINK_FLOWCTRL_TX:
2782 if (dp->flow_control != FLOW_CONTROL_TX_PAUSE) {
2783 dp->flow_control = FLOW_CONTROL_TX_PAUSE;
2784 update = B_TRUE;
2785 }
2786 break;
2787
2788 case LINK_FLOWCTRL_BI:
2789 if (dp->flow_control != FLOW_CONTROL_SYMMETRIC) {
2790 dp->flow_control = FLOW_CONTROL_SYMMETRIC;
2791 update = B_TRUE;
2792 }
2793 break;
2794 }
2795 break;
2796
2797 case MAC_PROP_ADV_1000FDX_CAP:
2798 case MAC_PROP_ADV_1000HDX_CAP:
2799 case MAC_PROP_ADV_100FDX_CAP:
2800 case MAC_PROP_ADV_100HDX_CAP:
2801 case MAC_PROP_ADV_10FDX_CAP:
2802 case MAC_PROP_ADV_10HDX_CAP:
2803 case MAC_PROP_STATUS:
2804 case MAC_PROP_SPEED:
2805 case MAC_PROP_DUPLEX:
2806 err = ENOTSUP; /* read-only prop. Can't set this. */
2807 break;
2808
2809 case MAC_PROP_MTU:
2810 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
2811 if (new_mtu != dp->mtu) {
2812 err = EINVAL;
2813 }
2814 break;
2815
2816 case MAC_PROP_PRIVATE:
2817 err = ENOTSUP;
2818 break;
2819
2820 default:
2821 err = ENOTSUP;
2822 break;
2823 }
2824
2825 if (update) {
2826 /* sync with PHY */
2827 usbgem_choose_forcedmode(dp);
2828 dp->mii_state = MII_STATE_UNKNOWN;
2829 cv_signal(&dp->link_watcher_wait_cv);
2830 }
2831 rw_exit(&dp->dev_state_lock);
2832 return (err);
2833 }
2834
2835 static int
usbgem_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)2836 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2837 uint_t pr_valsize, void *pr_val)
2838 {
2839 struct usbgem_dev *dp = arg;
2840 int err = 0;
2841 link_flowctrl_t flowctrl;
2842 uint64_t tmp = 0;
2843
2844 if (pr_valsize == 0) {
2845 return (EINVAL);
2846 }
2847
2848 bzero(pr_val, pr_valsize);
2849 rw_enter(&dp->dev_state_lock, RW_READER);
2850 switch (pr_num) {
2851 case MAC_PROP_DUPLEX:
2852 if (pr_valsize >= sizeof (link_duplex_t)) {
2853 if (dp->mii_state != MII_STATE_LINKUP) {
2854 *(link_duplex_t *)pr_val = LINK_DUPLEX_UNKNOWN;
2855 } else if (dp->full_duplex) {
2856 *(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
2857 } else {
2858 *(link_duplex_t *)pr_val = LINK_DUPLEX_HALF;
2859 }
2860 } else {
2861 err = EINVAL;
2862 }
2863 break;
2864 case MAC_PROP_SPEED:
2865 if (pr_valsize >= sizeof (uint64_t)) {
2866 switch (dp->speed) {
2867 case USBGEM_SPD_1000:
2868 tmp = 1000000000;
2869 break;
2870 case USBGEM_SPD_100:
2871 tmp = 100000000;
2872 break;
2873 case USBGEM_SPD_10:
2874 tmp = 10000000;
2875 break;
2876 default:
2877 tmp = 0;
2878 }
2879 bcopy(&tmp, pr_val, sizeof (tmp));
2880 } else {
2881 err = EINVAL;
2882 }
2883 break;
2884
2885 case MAC_PROP_AUTONEG:
2886 *(uint8_t *)pr_val = dp->anadv_autoneg;
2887 break;
2888
2889 case MAC_PROP_FLOWCTRL:
2890 if (pr_valsize >= sizeof (link_flowctrl_t)) {
2891 switch (dp->flow_control) {
2892 case FLOW_CONTROL_NONE:
2893 flowctrl = LINK_FLOWCTRL_NONE;
2894 break;
2895 case FLOW_CONTROL_RX_PAUSE:
2896 flowctrl = LINK_FLOWCTRL_RX;
2897 break;
2898 case FLOW_CONTROL_TX_PAUSE:
2899 flowctrl = LINK_FLOWCTRL_TX;
2900 break;
2901 case FLOW_CONTROL_SYMMETRIC:
2902 flowctrl = LINK_FLOWCTRL_BI;
2903 break;
2904 }
2905 bcopy(&flowctrl, pr_val, sizeof (flowctrl));
2906 } else {
2907 err = EINVAL;
2908 }
2909 break;
2910
2911 case MAC_PROP_ADV_1000FDX_CAP:
2912 case MAC_PROP_ADV_1000HDX_CAP:
2913 case MAC_PROP_ADV_100FDX_CAP:
2914 case MAC_PROP_ADV_100HDX_CAP:
2915 case MAC_PROP_ADV_10FDX_CAP:
2916 case MAC_PROP_ADV_10HDX_CAP:
2917 case MAC_PROP_ADV_100T4_CAP:
2918 usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val);
2919 break;
2920
2921 case MAC_PROP_EN_1000FDX_CAP:
2922 *(uint8_t *)pr_val = dp->anadv_1000fdx;
2923 break;
2924
2925 case MAC_PROP_EN_1000HDX_CAP:
2926 *(uint8_t *)pr_val = dp->anadv_1000hdx;
2927 break;
2928
2929 case MAC_PROP_EN_100FDX_CAP:
2930 *(uint8_t *)pr_val = dp->anadv_100fdx;
2931 break;
2932
2933 case MAC_PROP_EN_100HDX_CAP:
2934 *(uint8_t *)pr_val = dp->anadv_100hdx;
2935 break;
2936
2937 case MAC_PROP_EN_10FDX_CAP:
2938 *(uint8_t *)pr_val = dp->anadv_10fdx;
2939 break;
2940
2941 case MAC_PROP_EN_10HDX_CAP:
2942 *(uint8_t *)pr_val = dp->anadv_10hdx;
2943 break;
2944
2945 case MAC_PROP_EN_100T4_CAP:
2946 *(uint8_t *)pr_val = dp->anadv_100t4;
2947 break;
2948
2949 case MAC_PROP_PRIVATE:
2950 err = ENOTSUP;
2951 break;
2952
2953 default:
2954 err = ENOTSUP;
2955 break;
2956 }
2957
2958 rw_exit(&dp->dev_state_lock);
2959 return (err);
2960 }
2961
2962 static void
usbgem_mac_ioctl(struct usbgem_dev * dp,queue_t * wq,mblk_t * mp)2963 usbgem_mac_ioctl(struct usbgem_dev *dp, queue_t *wq, mblk_t *mp)
2964 {
2965 struct iocblk *iocp;
2966 enum ioc_reply status;
2967
2968 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2969
2970 /*
2971 * Validate the command before bothering with the mutex ...
2972 */
2973 iocp = (void *)mp->b_rptr;
2974 iocp->ioc_error = 0;
2975
2976 DPRINTF(1, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__,
2977 iocp->ioc_cmd));
2978
2979 miocnak(wq, mp, 0, EINVAL);
2980 }
2981
2982 static int
usbgem_mac_xcvr_inuse(struct usbgem_dev * dp)2983 usbgem_mac_xcvr_inuse(struct usbgem_dev *dp)
2984 {
2985 int val = XCVR_UNDEFINED;
2986
2987 if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
2988 if (dp->mii_status & MII_STATUS_100_BASE_T4) {
2989 val = XCVR_100T4;
2990 } else if (dp->mii_status &
2991 (MII_STATUS_100_BASEX_FD |
2992 MII_STATUS_100_BASEX)) {
2993 val = XCVR_100X;
2994 } else if (dp->mii_status &
2995 (MII_STATUS_100_BASE_T2_FD |
2996 MII_STATUS_100_BASE_T2)) {
2997 val = XCVR_100T2;
2998 } else if (dp->mii_status &
2999 (MII_STATUS_10_FD | MII_STATUS_10)) {
3000 val = XCVR_10;
3001 }
3002 } else if (dp->mii_xstatus &
3003 (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
3004 val = XCVR_1000T;
3005 } else if (dp->mii_xstatus &
3006 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
3007 val = XCVR_1000X;
3008 }
3009
3010 return (val);
3011 }
3012
3013 /* ============================================================== */
3014 /*
3015 * GLDv3 interface
3016 */
3017 /* ============================================================== */
3018 static int usbgem_m_getstat(void *, uint_t, uint64_t *);
3019 static int usbgem_m_start(void *);
3020 static void usbgem_m_stop(void *);
3021 static int usbgem_m_setpromisc(void *, boolean_t);
3022 static int usbgem_m_multicst(void *, boolean_t, const uint8_t *);
3023 static int usbgem_m_unicst(void *, const uint8_t *);
3024 static mblk_t *usbgem_m_tx(void *, mblk_t *);
3025 static void usbgem_m_ioctl(void *, queue_t *, mblk_t *);
3026 static int usbgem_m_setprop(void *, const char *, mac_prop_id_t,
3027 uint_t, const void *);
3028 static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
3029 uint_t, void *);
3030
3031 static mac_callbacks_t gem_m_callbacks = {
3032 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
3033 usbgem_m_getstat,
3034 usbgem_m_start,
3035 usbgem_m_stop,
3036 usbgem_m_setpromisc,
3037 usbgem_m_multicst,
3038 usbgem_m_unicst,
3039 usbgem_m_tx,
3040 NULL,
3041 usbgem_m_ioctl,
3042 NULL, /* m_getcapab */
3043 NULL,
3044 NULL,
3045 usbgem_m_setprop,
3046 usbgem_m_getprop,
3047 usbgem_m_propinfo,
3048 };
3049
3050 static int
usbgem_m_start(void * arg)3051 usbgem_m_start(void *arg)
3052 {
3053 int ret;
3054 int err;
3055 struct usbgem_dev *dp = arg;
3056
3057 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3058
3059 err = EIO;
3060
3061 rw_enter(&dp->dev_state_lock, RW_WRITER);
3062 dp->nic_state = NIC_STATE_ONLINE;
3063
3064 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
3065 err = 0;
3066 goto x;
3067 }
3068 if (usbgem_mac_init(dp) != USB_SUCCESS) {
3069 goto x;
3070 }
3071
3072 /* initialize rx filter state */
3073 sema_p(&dp->rxfilter_lock);
3074 dp->mc_count = 0;
3075 dp->mc_count_req = 0;
3076
3077 bcopy(dp->dev_addr.ether_addr_octet,
3078 dp->cur_addr.ether_addr_octet, ETHERADDRL);
3079 dp->rxmode |= RXMODE_ENABLE;
3080
3081 ret = usbgem_hal_set_rx_filter(dp);
3082 sema_v(&dp->rxfilter_lock);
3083
3084 if (ret != USB_SUCCESS) {
3085 goto x;
3086 }
3087
3088 if (dp->mii_state == MII_STATE_LINKUP) {
3089 /* setup media mode if the link have been up */
3090 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
3091 goto x;
3092 }
3093 if (usbgem_mac_start(dp) != USB_SUCCESS) {
3094 goto x;
3095 }
3096 }
3097
3098 err = 0;
3099 x:
3100 rw_exit(&dp->dev_state_lock);
3101 return (err);
3102 }
3103
3104 static void
usbgem_m_stop(void * arg)3105 usbgem_m_stop(void *arg)
3106 {
3107 struct usbgem_dev *dp = arg;
3108
3109 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3110
3111 /* stop rx gracefully */
3112 rw_enter(&dp->dev_state_lock, RW_READER);
3113 sema_p(&dp->rxfilter_lock);
3114 dp->rxmode &= ~RXMODE_ENABLE;
3115
3116 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3117 (void) usbgem_hal_set_rx_filter(dp);
3118 }
3119 sema_v(&dp->rxfilter_lock);
3120 rw_exit(&dp->dev_state_lock);
3121
3122 /* make the nic state inactive */
3123 rw_enter(&dp->dev_state_lock, RW_WRITER);
3124 dp->nic_state = NIC_STATE_STOPPED;
3125
3126 /* stop mac completely */
3127 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3128 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
3129 }
3130 rw_exit(&dp->dev_state_lock);
3131 }
3132
3133 static int
usbgem_m_multicst(void * arg,boolean_t add,const uint8_t * ep)3134 usbgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
3135 {
3136 int err;
3137 int ret;
3138 struct usbgem_dev *dp = arg;
3139
3140 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3141
3142 rw_enter(&dp->dev_state_lock, RW_READER);
3143 if (add) {
3144 ret = usbgem_add_multicast(dp, ep);
3145 } else {
3146 ret = usbgem_remove_multicast(dp, ep);
3147 }
3148 rw_exit(&dp->dev_state_lock);
3149
3150 err = 0;
3151 if (ret != USB_SUCCESS) {
3152 err = EIO;
3153 }
3154
3155 return (err);
3156 }
3157
3158 static int
usbgem_m_setpromisc(void * arg,boolean_t on)3159 usbgem_m_setpromisc(void *arg, boolean_t on)
3160 {
3161 int err;
3162 struct usbgem_dev *dp = arg;
3163
3164 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3165
3166 rw_enter(&dp->dev_state_lock, RW_READER);
3167
3168 sema_p(&dp->rxfilter_lock);
3169 if (on) {
3170 dp->rxmode |= RXMODE_PROMISC;
3171 } else {
3172 dp->rxmode &= ~RXMODE_PROMISC;
3173 }
3174
3175 err = 0;
3176 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3177 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
3178 err = EIO;
3179 }
3180 }
3181 sema_v(&dp->rxfilter_lock);
3182
3183 rw_exit(&dp->dev_state_lock);
3184
3185 return (err);
3186 }
3187
3188 int
usbgem_m_getstat(void * arg,uint_t stat,uint64_t * valp)3189 usbgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
3190 {
3191 uint64_t val;
3192 struct usbgem_dev *dp = arg;
3193 struct usbgem_stats *gstp = &dp->stats;
3194
3195 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3196
3197 rw_enter(&dp->dev_state_lock, RW_READER);
3198 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
3199 rw_exit(&dp->dev_state_lock);
3200 return (0);
3201 }
3202
3203 (void) usbgem_hal_get_stats(dp);
3204 rw_exit(&dp->dev_state_lock);
3205
3206 switch (stat) {
3207 case MAC_STAT_IFSPEED:
3208 val = usbgem_speed_value[dp->speed] *1000000ull;
3209 break;
3210
3211 case MAC_STAT_MULTIRCV:
3212 val = gstp->rmcast;
3213 break;
3214
3215 case MAC_STAT_BRDCSTRCV:
3216 val = gstp->rbcast;
3217 break;
3218
3219 case MAC_STAT_MULTIXMT:
3220 val = gstp->omcast;
3221 break;
3222
3223 case MAC_STAT_BRDCSTXMT:
3224 val = gstp->obcast;
3225 break;
3226
3227 case MAC_STAT_NORCVBUF:
3228 val = gstp->norcvbuf + gstp->missed;
3229 break;
3230
3231 case MAC_STAT_IERRORS:
3232 val = gstp->errrcv;
3233 break;
3234
3235 case MAC_STAT_NOXMTBUF:
3236 val = gstp->noxmtbuf;
3237 break;
3238
3239 case MAC_STAT_OERRORS:
3240 val = gstp->errxmt;
3241 break;
3242
3243 case MAC_STAT_COLLISIONS:
3244 val = gstp->collisions;
3245 break;
3246
3247 case MAC_STAT_RBYTES:
3248 val = gstp->rbytes;
3249 break;
3250
3251 case MAC_STAT_IPACKETS:
3252 val = gstp->rpackets;
3253 break;
3254
3255 case MAC_STAT_OBYTES:
3256 val = gstp->obytes;
3257 break;
3258
3259 case MAC_STAT_OPACKETS:
3260 val = gstp->opackets;
3261 break;
3262
3263 case MAC_STAT_UNDERFLOWS:
3264 val = gstp->underflow;
3265 break;
3266
3267 case MAC_STAT_OVERFLOWS:
3268 val = gstp->overflow;
3269 break;
3270
3271 case ETHER_STAT_ALIGN_ERRORS:
3272 val = gstp->frame;
3273 break;
3274
3275 case ETHER_STAT_FCS_ERRORS:
3276 val = gstp->crc;
3277 break;
3278
3279 case ETHER_STAT_FIRST_COLLISIONS:
3280 val = gstp->first_coll;
3281 break;
3282
3283 case ETHER_STAT_MULTI_COLLISIONS:
3284 val = gstp->multi_coll;
3285 break;
3286
3287 case ETHER_STAT_SQE_ERRORS:
3288 val = gstp->sqe;
3289 break;
3290
3291 case ETHER_STAT_DEFER_XMTS:
3292 val = gstp->defer;
3293 break;
3294
3295 case ETHER_STAT_TX_LATE_COLLISIONS:
3296 val = gstp->xmtlatecoll;
3297 break;
3298
3299 case ETHER_STAT_EX_COLLISIONS:
3300 val = gstp->excoll;
3301 break;
3302
3303 case ETHER_STAT_MACXMT_ERRORS:
3304 val = gstp->xmit_internal_err;
3305 break;
3306
3307 case ETHER_STAT_CARRIER_ERRORS:
3308 val = gstp->nocarrier;
3309 break;
3310
3311 case ETHER_STAT_TOOLONG_ERRORS:
3312 val = gstp->frame_too_long;
3313 break;
3314
3315 case ETHER_STAT_MACRCV_ERRORS:
3316 val = gstp->rcv_internal_err;
3317 break;
3318
3319 case ETHER_STAT_XCVR_ADDR:
3320 val = dp->mii_phy_addr;
3321 break;
3322
3323 case ETHER_STAT_XCVR_ID:
3324 val = dp->mii_phy_id;
3325 break;
3326
3327 case ETHER_STAT_XCVR_INUSE:
3328 val = usbgem_mac_xcvr_inuse(dp);
3329 break;
3330
3331 case ETHER_STAT_CAP_1000FDX:
3332 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
3333 (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
3334 break;
3335
3336 case ETHER_STAT_CAP_1000HDX:
3337 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
3338 (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
3339 break;
3340
3341 case ETHER_STAT_CAP_100FDX:
3342 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
3343 break;
3344
3345 case ETHER_STAT_CAP_100HDX:
3346 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
3347 break;
3348
3349 case ETHER_STAT_CAP_10FDX:
3350 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
3351 break;
3352
3353 case ETHER_STAT_CAP_10HDX:
3354 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
3355 break;
3356
3357 case ETHER_STAT_CAP_ASMPAUSE:
3358 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
3359 break;
3360
3361 case ETHER_STAT_CAP_PAUSE:
3362 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
3363 break;
3364
3365 case ETHER_STAT_CAP_AUTONEG:
3366 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
3367 break;
3368
3369 case ETHER_STAT_ADV_CAP_1000FDX:
3370 val = dp->anadv_1000fdx;
3371 break;
3372
3373 case ETHER_STAT_ADV_CAP_1000HDX:
3374 val = dp->anadv_1000hdx;
3375 break;
3376
3377 case ETHER_STAT_ADV_CAP_100FDX:
3378 val = dp->anadv_100fdx;
3379 break;
3380
3381 case ETHER_STAT_ADV_CAP_100HDX:
3382 val = dp->anadv_100hdx;
3383 break;
3384
3385 case ETHER_STAT_ADV_CAP_10FDX:
3386 val = dp->anadv_10fdx;
3387 break;
3388
3389 case ETHER_STAT_ADV_CAP_10HDX:
3390 val = dp->anadv_10hdx;
3391 break;
3392
3393 case ETHER_STAT_ADV_CAP_ASMPAUSE:
3394 val = dp->anadv_asmpause;
3395 break;
3396
3397 case ETHER_STAT_ADV_CAP_PAUSE:
3398 val = dp->anadv_pause;
3399 break;
3400
3401 case ETHER_STAT_ADV_CAP_AUTONEG:
3402 val = dp->anadv_autoneg;
3403 break;
3404
3405 case ETHER_STAT_LP_CAP_1000FDX:
3406 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
3407 break;
3408
3409 case ETHER_STAT_LP_CAP_1000HDX:
3410 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
3411 break;
3412
3413 case ETHER_STAT_LP_CAP_100FDX:
3414 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
3415 break;
3416
3417 case ETHER_STAT_LP_CAP_100HDX:
3418 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
3419 break;
3420
3421 case ETHER_STAT_LP_CAP_10FDX:
3422 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
3423 break;
3424
3425 case ETHER_STAT_LP_CAP_10HDX:
3426 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
3427 break;
3428
3429 case ETHER_STAT_LP_CAP_ASMPAUSE:
3430 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
3431 break;
3432
3433 case ETHER_STAT_LP_CAP_PAUSE:
3434 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
3435 break;
3436
3437 case ETHER_STAT_LP_CAP_AUTONEG:
3438 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3439 break;
3440
3441 case ETHER_STAT_LINK_ASMPAUSE:
3442 val = BOOLEAN(dp->flow_control & 2);
3443 break;
3444
3445 case ETHER_STAT_LINK_PAUSE:
3446 val = BOOLEAN(dp->flow_control & 1);
3447 break;
3448
3449 case ETHER_STAT_LINK_AUTONEG:
3450 val = dp->anadv_autoneg &&
3451 BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3452 break;
3453
3454 case ETHER_STAT_LINK_DUPLEX:
3455 val = (dp->mii_state == MII_STATE_LINKUP) ?
3456 (dp->full_duplex ? 2 : 1) : 0;
3457 break;
3458
3459 case ETHER_STAT_TOOSHORT_ERRORS:
3460 val = gstp->runt;
3461 break;
3462 #ifdef NEVER /* it doesn't make sense */
3463 case ETHER_STAT_CAP_REMFAULT:
3464 val = B_TRUE;
3465 break;
3466
3467 case ETHER_STAT_ADV_REMFAULT:
3468 val = dp->anadv_remfault;
3469 break;
3470 #endif
3471 case ETHER_STAT_LP_REMFAULT:
3472 val = BOOLEAN(dp->mii_lpable & MII_AN_ADVERT_REMFAULT);
3473 break;
3474
3475 case ETHER_STAT_JABBER_ERRORS:
3476 val = gstp->jabber;
3477 break;
3478
3479 case ETHER_STAT_CAP_100T4:
3480 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
3481 break;
3482
3483 case ETHER_STAT_ADV_CAP_100T4:
3484 val = dp->anadv_100t4;
3485 break;
3486
3487 case ETHER_STAT_LP_CAP_100T4:
3488 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
3489 break;
3490
3491 default:
3492 #if GEM_DEBUG_LEVEL > 2
3493 cmn_err(CE_WARN,
3494 "%s: unrecognized parameter value = %d",
3495 __func__, stat);
3496 #endif
3497 *valp = 0;
3498 return (ENOTSUP);
3499 }
3500
3501 *valp = val;
3502
3503 return (0);
3504 }
3505
3506 static int
usbgem_m_unicst(void * arg,const uint8_t * mac)3507 usbgem_m_unicst(void *arg, const uint8_t *mac)
3508 {
3509 int err;
3510 struct usbgem_dev *dp = arg;
3511
3512 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3513
3514 rw_enter(&dp->dev_state_lock, RW_READER);
3515
3516 sema_p(&dp->rxfilter_lock);
3517 bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
3518 dp->rxmode |= RXMODE_ENABLE;
3519
3520 err = 0;
3521 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3522 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
3523 err = EIO;
3524 }
3525 }
3526 sema_v(&dp->rxfilter_lock);
3527 rw_exit(&dp->dev_state_lock);
3528
3529 return (err);
3530 }
3531
3532 /*
3533 * usbgem_m_tx is used only for sending data packets into ethernet wire.
3534 */
3535 static mblk_t *
usbgem_m_tx(void * arg,mblk_t * mp_head)3536 usbgem_m_tx(void *arg, mblk_t *mp_head)
3537 {
3538 int limit;
3539 mblk_t *mp;
3540 mblk_t *nmp;
3541 struct usbgem_dev *dp = arg;
3542
3543 DPRINTF(4, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3544
3545 mp = mp_head;
3546
3547 rw_enter(&dp->dev_state_lock, RW_READER);
3548
3549 if (dp->mii_state != MII_STATE_LINKUP ||
3550 dp->mac_state != MAC_STATE_ONLINE) {
3551 /* some nics hate to send packets during the link is down */
3552 for (; mp; mp = nmp) {
3553 nmp = mp->b_next;
3554 mp->b_next = NULL;
3555 freemsg(mp);
3556 }
3557 goto x;
3558 }
3559
3560 ASSERT(dp->nic_state == NIC_STATE_ONLINE);
3561
3562 limit = dp->tx_max_packets;
3563 for (; limit-- && mp; mp = nmp) {
3564 nmp = mp->b_next;
3565 mp->b_next = NULL;
3566 if (usbgem_send_common(dp, mp,
3567 (limit == 0 && nmp) ? 1 : 0)) {
3568 mp->b_next = nmp;
3569 break;
3570 }
3571 }
3572 #ifdef CONFIG_TX_LIMITER
3573 if (mp == mp_head) {
3574 /* no packets were sent, descrease allocation limit */
3575 mutex_enter(&dp->txlock);
3576 dp->tx_max_packets = max(dp->tx_max_packets - 1, 1);
3577 mutex_exit(&dp->txlock);
3578 }
3579 #endif
3580 x:
3581 rw_exit(&dp->dev_state_lock);
3582
3583 return (mp);
3584 }
3585
3586 static void
usbgem_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)3587 usbgem_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
3588 {
3589 struct usbgem_dev *dp = arg;
3590
3591 DPRINTF(1, (CE_CONT, "!%s: %s: called",
3592 ((struct usbgem_dev *)arg)->name, __func__));
3593
3594 rw_enter(&dp->dev_state_lock, RW_READER);
3595 usbgem_mac_ioctl((struct usbgem_dev *)arg, wq, mp);
3596 rw_exit(&dp->dev_state_lock);
3597 }
3598
3599 static void
usbgem_gld3_init(struct usbgem_dev * dp,mac_register_t * macp)3600 usbgem_gld3_init(struct usbgem_dev *dp, mac_register_t *macp)
3601 {
3602 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
3603 macp->m_driver = dp;
3604 macp->m_dip = dp->dip;
3605 macp->m_src_addr = dp->dev_addr.ether_addr_octet;
3606 macp->m_callbacks = &gem_m_callbacks;
3607 macp->m_min_sdu = 0;
3608 macp->m_max_sdu = dp->mtu;
3609
3610 if (dp->misc_flag & USBGEM_VLAN) {
3611 macp->m_margin = VTAG_SIZE;
3612 }
3613 }
3614
3615 /* ======================================================================== */
3616 /*
3617 * .conf interface
3618 */
3619 /* ======================================================================== */
3620 void
usbgem_generate_macaddr(struct usbgem_dev * dp,uint8_t * mac)3621 usbgem_generate_macaddr(struct usbgem_dev *dp, uint8_t *mac)
3622 {
3623 extern char hw_serial[];
3624 char *hw_serial_p;
3625 int i;
3626 uint64_t val;
3627 uint64_t key;
3628
3629 cmn_err(CE_NOTE,
3630 "!%s: using temp ether address,"
3631 " do not use this for long time",
3632 dp->name);
3633
3634 /* prefer a fixed address for DHCP */
3635 hw_serial_p = &hw_serial[0];
3636 val = stoi(&hw_serial_p);
3637
3638 key = 0;
3639 for (i = 0; i < USBGEM_NAME_LEN; i++) {
3640 if (dp->name[i] == 0) {
3641 break;
3642 }
3643 key ^= dp->name[i];
3644 }
3645 key ^= ddi_get_instance(dp->dip);
3646 val ^= key << 32;
3647
3648 /* generate a local address */
3649 mac[0] = 0x02;
3650 mac[1] = (uint8_t)(val >> 32);
3651 mac[2] = (uint8_t)(val >> 24);
3652 mac[3] = (uint8_t)(val >> 16);
3653 mac[4] = (uint8_t)(val >> 8);
3654 mac[5] = (uint8_t)val;
3655 }
3656
3657 boolean_t
usbgem_get_mac_addr_conf(struct usbgem_dev * dp)3658 usbgem_get_mac_addr_conf(struct usbgem_dev *dp)
3659 {
3660 char propname[32];
3661 char *valstr;
3662 uint8_t mac[ETHERADDRL];
3663 char *cp;
3664 int c;
3665 int i;
3666 int j;
3667 uint8_t v;
3668 uint8_t d;
3669 uint8_t ored;
3670
3671 DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3672 /*
3673 * Get ethernet address from .conf file
3674 */
3675 (void) sprintf(propname, "mac-addr");
3676 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dp->dip,
3677 DDI_PROP_DONTPASS, propname, &valstr)) != DDI_PROP_SUCCESS) {
3678 return (B_FALSE);
3679 }
3680
3681 if (strlen(valstr) != ETHERADDRL*3-1) {
3682 goto syntax_err;
3683 }
3684
3685 cp = valstr;
3686 j = 0;
3687 ored = 0;
3688 for (;;) {
3689 v = 0;
3690 for (i = 0; i < 2; i++) {
3691 c = *cp++;
3692
3693 if (c >= 'a' && c <= 'f') {
3694 d = c - 'a' + 10;
3695 } else if (c >= 'A' && c <= 'F') {
3696 d = c - 'A' + 10;
3697 } else if (c >= '0' && c <= '9') {
3698 d = c - '0';
3699 } else {
3700 goto syntax_err;
3701 }
3702 v = (v << 4) | d;
3703 }
3704
3705 mac[j++] = v;
3706 ored |= v;
3707 if (j == ETHERADDRL) {
3708 /* done */
3709 break;
3710 }
3711
3712 c = *cp++;
3713 if (c != ':') {
3714 goto syntax_err;
3715 }
3716 }
3717
3718 if (ored == 0) {
3719 usbgem_generate_macaddr(dp, mac);
3720 }
3721 for (i = 0; i < ETHERADDRL; i++) {
3722 dp->dev_addr.ether_addr_octet[i] = mac[i];
3723 }
3724 ddi_prop_free(valstr);
3725 return (B_TRUE);
3726
3727 syntax_err:
3728 cmn_err(CE_CONT,
3729 "!%s: read mac addr: trying .conf: syntax err %s",
3730 dp->name, valstr);
3731 ddi_prop_free(valstr);
3732
3733 return (B_FALSE);
3734 }
3735
3736 static void
usbgem_read_conf(struct usbgem_dev * dp)3737 usbgem_read_conf(struct usbgem_dev *dp)
3738 {
3739 int val;
3740
3741 DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3742
3743 /*
3744 * Get media mode infomation from .conf file
3745 */
3746 dp->anadv_autoneg = usbgem_prop_get_int(dp, "adv_autoneg_cap", 1) != 0;
3747 dp->anadv_1000fdx = usbgem_prop_get_int(dp, "adv_1000fdx_cap", 1) != 0;
3748 dp->anadv_1000hdx = usbgem_prop_get_int(dp, "adv_1000hdx_cap", 1) != 0;
3749 dp->anadv_100t4 = usbgem_prop_get_int(dp, "adv_100T4_cap", 1) != 0;
3750 dp->anadv_100fdx = usbgem_prop_get_int(dp, "adv_100fdx_cap", 1) != 0;
3751 dp->anadv_100hdx = usbgem_prop_get_int(dp, "adv_100hdx_cap", 1) != 0;
3752 dp->anadv_10fdx = usbgem_prop_get_int(dp, "adv_10fdx_cap", 1) != 0;
3753 dp->anadv_10hdx = usbgem_prop_get_int(dp, "adv_10hdx_cap", 1) != 0;
3754 dp->anadv_1000t_ms = usbgem_prop_get_int(dp, "adv_1000t_ms", 0);
3755
3756 if ((ddi_prop_exists(DDI_DEV_T_ANY, dp->dip,
3757 DDI_PROP_DONTPASS, "full-duplex"))) {
3758 dp->full_duplex =
3759 usbgem_prop_get_int(dp, "full-duplex", 1) != 0;
3760 dp->anadv_autoneg = B_FALSE;
3761 if (dp->full_duplex) {
3762 dp->anadv_1000hdx = B_FALSE;
3763 dp->anadv_100hdx = B_FALSE;
3764 dp->anadv_10hdx = B_FALSE;
3765 } else {
3766 dp->anadv_1000fdx = B_FALSE;
3767 dp->anadv_100fdx = B_FALSE;
3768 dp->anadv_10fdx = B_FALSE;
3769 }
3770 }
3771
3772 if ((val = usbgem_prop_get_int(dp, "speed", 0)) > 0) {
3773 dp->anadv_autoneg = B_FALSE;
3774 switch (val) {
3775 case 1000:
3776 dp->speed = USBGEM_SPD_1000;
3777 dp->anadv_100t4 = B_FALSE;
3778 dp->anadv_100fdx = B_FALSE;
3779 dp->anadv_100hdx = B_FALSE;
3780 dp->anadv_10fdx = B_FALSE;
3781 dp->anadv_10hdx = B_FALSE;
3782 break;
3783 case 100:
3784 dp->speed = USBGEM_SPD_100;
3785 dp->anadv_1000fdx = B_FALSE;
3786 dp->anadv_1000hdx = B_FALSE;
3787 dp->anadv_10fdx = B_FALSE;
3788 dp->anadv_10hdx = B_FALSE;
3789 break;
3790 case 10:
3791 dp->speed = USBGEM_SPD_10;
3792 dp->anadv_1000fdx = B_FALSE;
3793 dp->anadv_1000hdx = B_FALSE;
3794 dp->anadv_100t4 = B_FALSE;
3795 dp->anadv_100fdx = B_FALSE;
3796 dp->anadv_100hdx = B_FALSE;
3797 break;
3798 default:
3799 cmn_err(CE_WARN,
3800 "!%s: property %s: illegal value:%d",
3801 dp->name, "speed", val);
3802 dp->anadv_autoneg = B_TRUE;
3803 break;
3804 }
3805 }
3806 val = usbgem_prop_get_int(dp,
3807 "adv_pause", dp->ugc.usbgc_flow_control & 1);
3808 val |= usbgem_prop_get_int(dp,
3809 "adv_asmpause", BOOLEAN(dp->ugc.usbgc_flow_control & 2)) << 1;
3810 if (val > FLOW_CONTROL_RX_PAUSE || val < FLOW_CONTROL_NONE) {
3811 cmn_err(CE_WARN,
3812 "!%s: property %s: illegal value:%d",
3813 dp->name, "flow-control", val);
3814 } else {
3815 val = min(val, dp->ugc.usbgc_flow_control);
3816 }
3817 dp->anadv_pause = BOOLEAN(val & 1);
3818 dp->anadv_asmpause = BOOLEAN(val & 2);
3819
3820 dp->mtu = usbgem_prop_get_int(dp, "mtu", dp->mtu);
3821 dp->txthr = usbgem_prop_get_int(dp, "txthr", dp->txthr);
3822 dp->rxthr = usbgem_prop_get_int(dp, "rxthr", dp->rxthr);
3823 dp->txmaxdma = usbgem_prop_get_int(dp, "txmaxdma", dp->txmaxdma);
3824 dp->rxmaxdma = usbgem_prop_get_int(dp, "rxmaxdma", dp->rxmaxdma);
3825 #ifdef GEM_CONFIG_POLLING
3826 dp->poll_pkt_delay =
3827 usbgem_prop_get_int(dp, "pkt_delay", dp->poll_pkt_delay);
3828
3829 dp->max_poll_interval[GEM_SPD_10] =
3830 usbgem_prop_get_int(dp, "max_poll_interval_10",
3831 dp->max_poll_interval[GEM_SPD_10]);
3832 dp->max_poll_interval[GEM_SPD_100] =
3833 usbgem_prop_get_int(dp, "max_poll_interval_100",
3834 dp->max_poll_interval[GEM_SPD_100]);
3835 dp->max_poll_interval[GEM_SPD_1000] =
3836 usbgem_prop_get_int(dp, "max_poll_interval_1000",
3837 dp->max_poll_interval[GEM_SPD_1000]);
3838
3839 dp->min_poll_interval[GEM_SPD_10] =
3840 usbgem_prop_get_int(dp, "min_poll_interval_10",
3841 dp->min_poll_interval[GEM_SPD_10]);
3842 dp->min_poll_interval[GEM_SPD_100] =
3843 usbgem_prop_get_int(dp, "min_poll_interval_100",
3844 dp->min_poll_interval[GEM_SPD_100]);
3845 dp->min_poll_interval[GEM_SPD_1000] =
3846 usbgem_prop_get_int(dp, "min_poll_interval_1000",
3847 dp->min_poll_interval[GEM_SPD_1000]);
3848 #endif
3849 }
3850
3851 /*
3852 * attach/detatch/usb support
3853 */
3854 /* ======================================================================== */
3855 int
usbgem_ctrl_out(struct usbgem_dev * dp,uint8_t reqt,uint8_t req,uint16_t val,uint16_t ix,uint16_t len,void * bp,int size)3856 usbgem_ctrl_out(struct usbgem_dev *dp,
3857 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
3858 void *bp, int size)
3859 {
3860 mblk_t *data;
3861 usb_ctrl_setup_t setup;
3862 usb_cr_t completion_reason;
3863 usb_cb_flags_t cb_flags;
3864 usb_flags_t flags;
3865 int i;
3866 int ret;
3867
3868 DPRINTF(4, (CE_CONT, "!%s: %s "
3869 "reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x "
3870 "bp:0x%p nic_state:%d",
3871 dp->name, __func__, reqt, req, val, ix, len, bp, dp->nic_state));
3872
3873 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
3874 return (USB_PIPE_ERROR);
3875 }
3876
3877 data = NULL;
3878 if (size > 0) {
3879 if ((data = allocb(size, 0)) == NULL) {
3880 return (USB_FAILURE);
3881 }
3882
3883 bcopy(bp, data->b_rptr, size);
3884 data->b_wptr = data->b_rptr + size;
3885 }
3886
3887 setup.bmRequestType = reqt;
3888 setup.bRequest = req;
3889 setup.wValue = val;
3890 setup.wIndex = ix;
3891 setup.wLength = len;
3892 setup.attrs = 0; /* attributes */
3893
3894 for (i = usbgem_ctrl_retry; i > 0; i--) {
3895 completion_reason = 0;
3896 cb_flags = 0;
3897
3898 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp),
3899 &setup, &data, &completion_reason, &cb_flags, 0);
3900
3901 if (ret == USB_SUCCESS) {
3902 break;
3903 }
3904 if (i == 1) {
3905 cmn_err(CE_WARN,
3906 "!%s: %s failed: "
3907 "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
3908 "ret:%d cr:%s(%d), cb_flags:0x%x %s",
3909 dp->name, __func__, reqt, req, val, ix, len,
3910 ret, usb_str_cr(completion_reason),
3911 completion_reason,
3912 cb_flags,
3913 (i > 1) ? "retrying..." : "fatal");
3914 }
3915 }
3916
3917 if (data != NULL) {
3918 freemsg(data);
3919 }
3920
3921 return (ret);
3922 }
3923
3924 int
usbgem_ctrl_in(struct usbgem_dev * dp,uint8_t reqt,uint8_t req,uint16_t val,uint16_t ix,uint16_t len,void * bp,int size)3925 usbgem_ctrl_in(struct usbgem_dev *dp,
3926 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
3927 void *bp, int size)
3928 {
3929 mblk_t *data;
3930 usb_ctrl_setup_t setup;
3931 usb_cr_t completion_reason;
3932 usb_cb_flags_t cb_flags;
3933 int i;
3934 int ret;
3935 int reclen;
3936
3937 DPRINTF(4, (CE_CONT,
3938 "!%s: %s:"
3939 " reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x"
3940 " bp:x%p mac_state:%d",
3941 dp->name, __func__, reqt, req, val, ix, len, bp, dp->mac_state));
3942
3943 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
3944 return (USB_PIPE_ERROR);
3945 }
3946
3947 data = NULL;
3948
3949 setup.bmRequestType = reqt;
3950 setup.bRequest = req;
3951 setup.wValue = val;
3952 setup.wIndex = ix;
3953 setup.wLength = len;
3954 setup.attrs = USB_ATTRS_AUTOCLEARING; /* XXX */
3955
3956 for (i = usbgem_ctrl_retry; i > 0; i--) {
3957 completion_reason = 0;
3958 cb_flags = 0;
3959 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp), &setup, &data,
3960 &completion_reason, &cb_flags, 0);
3961
3962 if (ret == USB_SUCCESS) {
3963 reclen = msgdsize(data);
3964 bcopy(data->b_rptr, bp, min(reclen, size));
3965 break;
3966 }
3967 if (i == 1) {
3968 cmn_err(CE_WARN,
3969 "!%s: %s failed: "
3970 "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
3971 "ret:%d cr:%s(%d) cb_flags:0x%x %s",
3972 dp->name, __func__,
3973 reqt, req, val, ix, len,
3974 ret, usb_str_cr(completion_reason),
3975 completion_reason,
3976 cb_flags,
3977 (i > 1) ? "retrying..." : "fatal");
3978 }
3979 }
3980
3981 if (data) {
3982 freemsg(data);
3983 }
3984
3985 return (ret);
3986 }
3987
3988 int
usbgem_ctrl_out_val(struct usbgem_dev * dp,uint8_t reqt,uint8_t req,uint16_t val,uint16_t ix,uint16_t len,uint32_t v)3989 usbgem_ctrl_out_val(struct usbgem_dev *dp,
3990 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
3991 uint32_t v)
3992 {
3993 uint8_t buf[4];
3994
3995 /* convert to little endian from native byte order */
3996 switch (len) {
3997 case 4:
3998 buf[3] = v >> 24;
3999 buf[2] = v >> 16;
4000 /* FALLTHROUGH */
4001 case 2:
4002 buf[1] = v >> 8;
4003 /* FALLTHROUGH */
4004 case 1:
4005 buf[0] = v;
4006 }
4007
4008 return (usbgem_ctrl_out(dp, reqt, req, val, ix, len, buf, len));
4009 }
4010
4011 int
usbgem_ctrl_in_val(struct usbgem_dev * dp,uint8_t reqt,uint8_t req,uint16_t val,uint16_t ix,uint16_t len,void * valp)4012 usbgem_ctrl_in_val(struct usbgem_dev *dp,
4013 uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
4014 void *valp)
4015 {
4016 uint8_t buf[4];
4017 uint_t v;
4018 int err;
4019
4020 #ifdef SANITY
4021 bzero(buf, sizeof (buf));
4022 #endif
4023 err = usbgem_ctrl_in(dp, reqt, req, val, ix, len, buf, len);
4024 if (err == USB_SUCCESS) {
4025 v = 0;
4026 switch (len) {
4027 case 4:
4028 v |= buf[3] << 24;
4029 v |= buf[2] << 16;
4030 /* FALLTHROUGH */
4031 case 2:
4032 v |= buf[1] << 8;
4033 /* FALLTHROUGH */
4034 case 1:
4035 v |= buf[0];
4036 }
4037
4038 switch (len) {
4039 case 4:
4040 *(uint32_t *)valp = v;
4041 break;
4042 case 2:
4043 *(uint16_t *)valp = v;
4044 break;
4045 case 1:
4046 *(uint8_t *)valp = v;
4047 break;
4048 }
4049 }
4050 return (err);
4051 }
4052
4053 /*
4054 * Attach / detach / disconnect / reconnect management
4055 */
4056 static int
usbgem_open_pipes(struct usbgem_dev * dp)4057 usbgem_open_pipes(struct usbgem_dev *dp)
4058 {
4059 int i;
4060 int ret;
4061 int ifnum;
4062 int alt;
4063 usb_client_dev_data_t *reg_data;
4064 usb_ep_data_t *ep_tree_node;
4065
4066 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4067
4068 ifnum = dp->ugc.usbgc_ifnum;
4069 alt = dp->ugc.usbgc_alt;
4070
4071 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
4072 0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
4073 if (ep_tree_node == NULL) {
4074 cmn_err(CE_WARN, "!%s: %s: ep_bulkin is NULL",
4075 dp->name, __func__);
4076 goto err;
4077 }
4078 dp->ep_bulkin = &ep_tree_node->ep_descr;
4079
4080 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
4081 0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
4082 if (ep_tree_node == NULL) {
4083 cmn_err(CE_WARN, "!%s: %s: ep_bulkout is NULL",
4084 dp->name, __func__);
4085 goto err;
4086 }
4087 dp->ep_bulkout = &ep_tree_node->ep_descr;
4088
4089 ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
4090 0, USB_EP_ATTR_INTR, USB_EP_DIR_IN);
4091 if (ep_tree_node) {
4092 dp->ep_intr = &ep_tree_node->ep_descr;
4093 } else {
4094 /* don't care */
4095 DPRINTF(1, (CE_CONT, "!%s: %s: ep_intr is NULL",
4096 dp->name, __func__));
4097 dp->ep_intr = NULL;
4098 }
4099
4100 /* XXX -- no need to open default pipe */
4101
4102 /* open bulk out pipe */
4103 bzero(&dp->policy_bulkout, sizeof (usb_pipe_policy_t));
4104 dp->policy_bulkout.pp_max_async_reqs = 1;
4105
4106 if ((ret = usb_pipe_open(dp->dip,
4107 dp->ep_bulkout, &dp->policy_bulkout, USB_FLAGS_SLEEP,
4108 &dp->bulkout_pipe)) != USB_SUCCESS) {
4109 cmn_err(CE_WARN,
4110 "!%s: %s: err:%x: failed to open bulk-out pipe",
4111 dp->name, __func__, ret);
4112 dp->bulkout_pipe = NULL;
4113 goto err;
4114 }
4115 DPRINTF(1, (CE_CONT, "!%s: %s: bulkout_pipe opened successfully",
4116 dp->name, __func__));
4117
4118 /* open bulk in pipe */
4119 bzero(&dp->policy_bulkin, sizeof (usb_pipe_policy_t));
4120 dp->policy_bulkin.pp_max_async_reqs = 1;
4121 if ((ret = usb_pipe_open(dp->dip,
4122 dp->ep_bulkin, &dp->policy_bulkin, USB_FLAGS_SLEEP,
4123 &dp->bulkin_pipe)) != USB_SUCCESS) {
4124 cmn_err(CE_WARN,
4125 "!%s: %s: ret:%x failed to open bulk-in pipe",
4126 dp->name, __func__, ret);
4127 dp->bulkin_pipe = NULL;
4128 goto err;
4129 }
4130 DPRINTF(1, (CE_CONT, "!%s: %s: bulkin_pipe opened successfully",
4131 dp->name, __func__));
4132
4133 if (dp->ep_intr) {
4134 /* open interrupt pipe */
4135 bzero(&dp->policy_interrupt, sizeof (usb_pipe_policy_t));
4136 dp->policy_interrupt.pp_max_async_reqs = 1;
4137 if ((ret = usb_pipe_open(dp->dip, dp->ep_intr,
4138 &dp->policy_interrupt, USB_FLAGS_SLEEP,
4139 &dp->intr_pipe)) != USB_SUCCESS) {
4140 cmn_err(CE_WARN,
4141 "!%s: %s: ret:%x failed to open interrupt pipe",
4142 dp->name, __func__, ret);
4143 dp->intr_pipe = NULL;
4144 goto err;
4145 }
4146 }
4147 DPRINTF(1, (CE_CONT, "!%s: %s: intr_pipe opened successfully",
4148 dp->name, __func__));
4149
4150 return (USB_SUCCESS);
4151
4152 err:
4153 if (dp->bulkin_pipe) {
4154 usb_pipe_close(dp->dip,
4155 dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
4156 dp->bulkin_pipe = NULL;
4157 }
4158 if (dp->bulkout_pipe) {
4159 usb_pipe_close(dp->dip,
4160 dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
4161 dp->bulkout_pipe = NULL;
4162 }
4163 if (dp->intr_pipe) {
4164 usb_pipe_close(dp->dip,
4165 dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
4166 dp->intr_pipe = NULL;
4167 }
4168
4169 return (USB_FAILURE);
4170 }
4171
4172 static int
usbgem_close_pipes(struct usbgem_dev * dp)4173 usbgem_close_pipes(struct usbgem_dev *dp)
4174 {
4175 DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4176
4177 if (dp->intr_pipe) {
4178 usb_pipe_close(dp->dip,
4179 dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
4180 dp->intr_pipe = NULL;
4181 }
4182 DPRINTF(1, (CE_CONT, "!%s: %s: 1", dp->name, __func__));
4183
4184 ASSERT(dp->bulkin_pipe);
4185 usb_pipe_close(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
4186 dp->bulkin_pipe = NULL;
4187 DPRINTF(1, (CE_CONT, "!%s: %s: 2", dp->name, __func__));
4188
4189 ASSERT(dp->bulkout_pipe);
4190 usb_pipe_close(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
4191 dp->bulkout_pipe = NULL;
4192 DPRINTF(1, (CE_CONT, "!%s: %s: 3", dp->name, __func__));
4193
4194 return (USB_SUCCESS);
4195 }
4196
4197 #define FREEZE_GRACEFUL (B_TRUE)
4198 #define FREEZE_NO_GRACEFUL (B_FALSE)
4199 static int
usbgem_freeze_device(struct usbgem_dev * dp,boolean_t graceful)4200 usbgem_freeze_device(struct usbgem_dev *dp, boolean_t graceful)
4201 {
4202 DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
4203
4204 /* stop nic activity */
4205 (void) usbgem_mac_stop(dp, MAC_STATE_DISCONNECTED, graceful);
4206
4207 /*
4208 * Here we free all memory resource allocated, because it will
4209 * cause to panic the system that we free usb_bulk_req objects
4210 * during the usb device is disconnected.
4211 */
4212 (void) usbgem_free_memory(dp);
4213
4214 return (USB_SUCCESS);
4215 }
4216
4217 static int
usbgem_disconnect_cb(dev_info_t * dip)4218 usbgem_disconnect_cb(dev_info_t *dip)
4219 {
4220 int ret;
4221 struct usbgem_dev *dp;
4222
4223 dp = USBGEM_GET_DEV(dip);
4224
4225 cmn_err(CE_NOTE, "!%s: the usb device was disconnected (dp=%p)",
4226 dp->name, (void *)dp);
4227
4228 /* start serialize */
4229 rw_enter(&dp->dev_state_lock, RW_WRITER);
4230
4231 ret = usbgem_freeze_device(dp, 0);
4232
4233 /* end of serialize */
4234 rw_exit(&dp->dev_state_lock);
4235
4236 return (ret);
4237 }
4238
4239 static int
usbgem_recover_device(struct usbgem_dev * dp)4240 usbgem_recover_device(struct usbgem_dev *dp)
4241 {
4242 int err;
4243
4244 DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
4245
4246 err = USB_SUCCESS;
4247
4248 /* reinitialize the usb connection */
4249 usbgem_close_pipes(dp);
4250 if ((err = usbgem_open_pipes(dp)) != USB_SUCCESS) {
4251 goto x;
4252 }
4253
4254 /* initialize nic state */
4255 dp->mac_state = MAC_STATE_STOPPED;
4256 dp->mii_state = MII_STATE_UNKNOWN;
4257
4258 /* allocate memory resources again */
4259 if ((err = usbgem_alloc_memory(dp)) != USB_SUCCESS) {
4260 goto x;
4261 }
4262
4263 /* restart nic and recover state */
4264 (void) usbgem_restart_nic(dp);
4265
4266 usbgem_mii_init(dp);
4267
4268 /* kick potentially stopped house keeping thread */
4269 cv_signal(&dp->link_watcher_wait_cv);
4270 x:
4271 return (err);
4272 }
4273
4274 static int
usbgem_reconnect_cb(dev_info_t * dip)4275 usbgem_reconnect_cb(dev_info_t *dip)
4276 {
4277 int err = USB_SUCCESS;
4278 struct usbgem_dev *dp;
4279
4280 dp = USBGEM_GET_DEV(dip);
4281 DPRINTF(0, (CE_CONT, "!%s: dp=%p", ddi_get_name(dip), dp));
4282 #ifdef notdef
4283 /* check device changes after disconnect */
4284 if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
4285 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
4286 cmn_err(CE_CONT,
4287 "!%s: no or different device installed", dp->name);
4288 return (DDI_SUCCESS);
4289 }
4290 #endif
4291 cmn_err(CE_NOTE, "%s: the usb device was reconnected", dp->name);
4292
4293 /* start serialize */
4294 rw_enter(&dp->dev_state_lock, RW_WRITER);
4295
4296 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4297 err = usbgem_recover_device(dp);
4298 }
4299
4300 /* end of serialize */
4301 rw_exit(&dp->dev_state_lock);
4302
4303 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
4304 }
4305
4306 int
usbgem_suspend(dev_info_t * dip)4307 usbgem_suspend(dev_info_t *dip)
4308 {
4309 int err = USB_SUCCESS;
4310 struct usbgem_dev *dp;
4311
4312 dp = USBGEM_GET_DEV(dip);
4313
4314 DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
4315
4316 /* start serialize */
4317 rw_enter(&dp->dev_state_lock, RW_WRITER);
4318
4319 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4320 err = usbgem_freeze_device(dp, STOP_GRACEFUL);
4321 }
4322
4323 /* end of serialize */
4324 rw_exit(&dp->dev_state_lock);
4325
4326 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
4327 }
4328
4329 int
usbgem_resume(dev_info_t * dip)4330 usbgem_resume(dev_info_t *dip)
4331 {
4332 int err = USB_SUCCESS;
4333 struct usbgem_dev *dp;
4334
4335 dp = USBGEM_GET_DEV(dip);
4336
4337 DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
4338 #ifdef notdef
4339 /* check device changes after disconnect */
4340 if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
4341 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
4342 cmn_err(CE_CONT,
4343 "!%s: no or different device installed", dp->name);
4344 return (DDI_SUCCESS);
4345 }
4346 #endif
4347 /* start serialize */
4348 rw_enter(&dp->dev_state_lock, RW_WRITER);
4349
4350 if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4351 err = usbgem_recover_device(dp);
4352 }
4353
4354 /* end of serialize */
4355 rw_exit(&dp->dev_state_lock);
4356
4357 return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
4358 }
4359
4360 #define USBGEM_LOCAL_DATA_SIZE(gc) \
4361 (sizeof (struct usbgem_dev) + USBGEM_MCALLOC)
4362
4363 struct usbgem_dev *
usbgem_do_attach(dev_info_t * dip,struct usbgem_conf * gc,void * lp,int lmsize)4364 usbgem_do_attach(dev_info_t *dip,
4365 struct usbgem_conf *gc, void *lp, int lmsize)
4366 {
4367 struct usbgem_dev *dp;
4368 int i;
4369 mac_register_t *macp = NULL;
4370 int ret;
4371 int unit;
4372 int err;
4373
4374 unit = ddi_get_instance(dip);
4375
4376 DPRINTF(2, (CE_CONT, "!usbgem%d: %s: called", unit, __func__));
4377
4378 /*
4379 * Allocate soft data structure
4380 */
4381 dp = kmem_zalloc(USBGEM_LOCAL_DATA_SIZE(gc), KM_SLEEP);
4382 if (dp == NULL) {
4383 return (NULL);
4384 }
4385
4386 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
4387 cmn_err(CE_WARN, "!gem%d: %s: mac_alloc failed",
4388 unit, __func__);
4389 return (NULL);
4390 }
4391
4392 /* link to private area */
4393 dp->private = lp;
4394 dp->priv_size = lmsize;
4395 dp->mc_list = (struct mcast_addr *)&dp[1];
4396
4397 dp->dip = dip;
4398 bcopy(gc->usbgc_name, dp->name, USBGEM_NAME_LEN);
4399
4400 /*
4401 * register with usb service
4402 */
4403 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
4404 cmn_err(CE_WARN,
4405 "%s: %s: usb_client_attach failed",
4406 dp->name, __func__);
4407 goto err_free_private;
4408 }
4409
4410 if (usb_get_dev_data(dip, &dp->reg_data,
4411 USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
4412 dp->reg_data = NULL;
4413 goto err_unregister_client;
4414 }
4415 #ifdef USBGEM_DEBUG_LEVEL
4416 usb_print_descr_tree(dp->dip, dp->reg_data);
4417 #endif
4418
4419 if (usbgem_open_pipes(dp) != USB_SUCCESS) {
4420 /* failed to open pipes */
4421 cmn_err(CE_WARN, "!%s: %s: failed to open pipes",
4422 dp->name, __func__);
4423 goto err_unregister_client;
4424 }
4425
4426 /*
4427 * Initialize mutexs and condition variables
4428 */
4429 mutex_init(&dp->rxlock, NULL, MUTEX_DRIVER, NULL);
4430 mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
4431 cv_init(&dp->rx_drain_cv, NULL, CV_DRIVER, NULL);
4432 cv_init(&dp->tx_drain_cv, NULL, CV_DRIVER, NULL);
4433 rw_init(&dp->dev_state_lock, NULL, RW_DRIVER, NULL);
4434 mutex_init(&dp->link_watcher_lock, NULL, MUTEX_DRIVER, NULL);
4435 cv_init(&dp->link_watcher_wait_cv, NULL, CV_DRIVER, NULL);
4436 sema_init(&dp->hal_op_lock, 1, NULL, SEMA_DRIVER, NULL);
4437 sema_init(&dp->rxfilter_lock, 1, NULL, SEMA_DRIVER, NULL);
4438
4439 /*
4440 * Initialize configuration
4441 */
4442 dp->ugc = *gc;
4443
4444 dp->mtu = ETHERMTU;
4445 dp->rxmode = 0;
4446 dp->speed = USBGEM_SPD_10; /* default is 10Mbps */
4447 dp->full_duplex = B_FALSE; /* default is half */
4448 dp->flow_control = FLOW_CONTROL_NONE;
4449
4450 dp->nic_state = NIC_STATE_STOPPED;
4451 dp->mac_state = MAC_STATE_STOPPED;
4452 dp->mii_state = MII_STATE_UNKNOWN;
4453
4454 /* performance tuning parameters */
4455 dp->txthr = ETHERMAX; /* tx fifo threshoold */
4456 dp->txmaxdma = 16*4; /* tx max dma burst size */
4457 dp->rxthr = 128; /* rx fifo threshoold */
4458 dp->rxmaxdma = 16*4; /* rx max dma burst size */
4459
4460 /*
4461 * Get media mode infomation from .conf file
4462 */
4463 usbgem_read_conf(dp);
4464
4465 /* rx_buf_len depend on MTU */
4466 dp->rx_buf_len = MAXPKTBUF(dp) + dp->ugc.usbgc_rx_header_len;
4467
4468 /*
4469 * Reset the chip
4470 */
4471 if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
4472 cmn_err(CE_WARN,
4473 "!%s: %s: failed to reset the usb device",
4474 dp->name, __func__);
4475 goto err_destroy_locks;
4476 }
4477
4478 /*
4479 * HW dependant paremeter initialization
4480 */
4481 if (usbgem_hal_attach_chip(dp) != USB_SUCCESS) {
4482 cmn_err(CE_WARN,
4483 "!%s: %s: failed to attach the usb device",
4484 dp->name, __func__);
4485 goto err_destroy_locks;
4486 }
4487
4488 /* allocate resources */
4489 if (usbgem_alloc_memory(dp) != USB_SUCCESS) {
4490 goto err_destroy_locks;
4491 }
4492
4493 DPRINTF(0, (CE_CONT,
4494 "!%s: %02x:%02x:%02x:%02x:%02x:%02x",
4495 dp->name,
4496 dp->dev_addr.ether_addr_octet[0],
4497 dp->dev_addr.ether_addr_octet[1],
4498 dp->dev_addr.ether_addr_octet[2],
4499 dp->dev_addr.ether_addr_octet[3],
4500 dp->dev_addr.ether_addr_octet[4],
4501 dp->dev_addr.ether_addr_octet[5]));
4502
4503 /* copy mac address */
4504 dp->cur_addr = dp->dev_addr;
4505
4506 /* pre-calculated tx timeout in second for performance */
4507 dp->bulkout_timeout =
4508 dp->ugc.usbgc_tx_timeout / drv_usectohz(1000*1000);
4509
4510 usbgem_gld3_init(dp, macp);
4511
4512 /* Probe MII phy (scan phy) */
4513 dp->mii_lpable = 0;
4514 dp->mii_advert = 0;
4515 dp->mii_exp = 0;
4516 dp->mii_ctl1000 = 0;
4517 dp->mii_stat1000 = 0;
4518
4519 dp->mii_status_ro = 0;
4520 dp->mii_xstatus_ro = 0;
4521
4522 if (usbgem_mii_probe(dp) != USB_SUCCESS) {
4523 cmn_err(CE_WARN, "!%s: %s: mii_probe failed",
4524 dp->name, __func__);
4525 goto err_free_memory;
4526 }
4527
4528 /* mask unsupported abilities */
4529 dp->anadv_autoneg &= BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
4530 dp->anadv_1000fdx &=
4531 BOOLEAN(dp->mii_xstatus &
4532 (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD));
4533 dp->anadv_1000hdx &=
4534 BOOLEAN(dp->mii_xstatus &
4535 (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET));
4536 dp->anadv_100t4 &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
4537 dp->anadv_100fdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
4538 dp->anadv_100hdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
4539 dp->anadv_10fdx &= BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
4540 dp->anadv_10hdx &= BOOLEAN(dp->mii_status & MII_STATUS_10);
4541
4542 if (usbgem_mii_init(dp) != USB_SUCCESS) {
4543 cmn_err(CE_WARN, "!%s: %s: mii_init failed",
4544 dp->name, __func__);
4545 goto err_free_memory;
4546 }
4547
4548 /*
4549 * Add interrupt to system.
4550 */
4551 if (ret = mac_register(macp, &dp->mh)) {
4552 cmn_err(CE_WARN, "!%s: mac_register failed, error:%d",
4553 dp->name, ret);
4554 goto err_release_stats;
4555 }
4556 mac_free(macp);
4557 macp = NULL;
4558
4559 if (usb_register_hotplug_cbs(dip,
4560 usbgem_suspend, usbgem_resume) != USB_SUCCESS) {
4561 cmn_err(CE_WARN,
4562 "!%s: %s: failed to register hotplug cbs",
4563 dp->name, __func__);
4564 goto err_unregister_gld;
4565 }
4566
4567 /* reset mii and start mii link watcher */
4568 if (usbgem_mii_start(dp) != USB_SUCCESS) {
4569 goto err_unregister_hotplug;
4570 }
4571
4572 /* start tx watchdow watcher */
4573 if (usbgem_tx_watcher_start(dp)) {
4574 goto err_usbgem_mii_stop;
4575 }
4576
4577 ddi_set_driver_private(dip, (caddr_t)dp);
4578
4579 DPRINTF(2, (CE_CONT, "!%s: %s: return: success", dp->name, __func__));
4580
4581 return (dp);
4582
4583 err_usbgem_mii_stop:
4584 usbgem_mii_stop(dp);
4585
4586 err_unregister_hotplug:
4587 usb_unregister_hotplug_cbs(dip);
4588
4589 err_unregister_gld:
4590 mac_unregister(dp->mh);
4591
4592 err_release_stats:
4593 err_free_memory:
4594 usbgem_free_memory(dp);
4595
4596 err_destroy_locks:
4597 cv_destroy(&dp->tx_drain_cv);
4598 cv_destroy(&dp->rx_drain_cv);
4599 mutex_destroy(&dp->txlock);
4600 mutex_destroy(&dp->rxlock);
4601 rw_destroy(&dp->dev_state_lock);
4602 mutex_destroy(&dp->link_watcher_lock);
4603 cv_destroy(&dp->link_watcher_wait_cv);
4604 sema_destroy(&dp->hal_op_lock);
4605 sema_destroy(&dp->rxfilter_lock);
4606
4607 err_close_pipes:
4608 (void) usbgem_close_pipes(dp);
4609
4610 err_unregister_client:
4611 usb_client_detach(dp->dip, dp->reg_data);
4612
4613 err_free_private:
4614 if (macp) {
4615 mac_free(macp);
4616 }
4617
4618 kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(gc));
4619
4620 return (NULL);
4621 }
4622
4623 int
usbgem_do_detach(dev_info_t * dip)4624 usbgem_do_detach(dev_info_t *dip)
4625 {
4626 struct usbgem_dev *dp;
4627
4628 dp = USBGEM_GET_DEV(dip);
4629
4630 /* unregister with gld v3 */
4631 if (mac_unregister(dp->mh) != DDI_SUCCESS) {
4632 return (DDI_FAILURE);
4633 }
4634
4635 /* unregister with hotplug service */
4636 usb_unregister_hotplug_cbs(dip);
4637
4638 /* stop tx watchdog watcher */
4639 usbgem_tx_watcher_stop(dp);
4640
4641 /* stop the link manager */
4642 usbgem_mii_stop(dp);
4643
4644 /* unregister with usb service */
4645 (void) usbgem_free_memory(dp);
4646 (void) usbgem_close_pipes(dp);
4647 usb_client_detach(dp->dip, dp->reg_data);
4648 dp->reg_data = NULL;
4649
4650 /* release locks and condition variables */
4651 mutex_destroy(&dp->txlock);
4652 mutex_destroy(&dp->rxlock);
4653 cv_destroy(&dp->tx_drain_cv);
4654 cv_destroy(&dp->rx_drain_cv);
4655 rw_destroy(&dp->dev_state_lock);
4656 mutex_destroy(&dp->link_watcher_lock);
4657 cv_destroy(&dp->link_watcher_wait_cv);
4658 sema_destroy(&dp->hal_op_lock);
4659 sema_destroy(&dp->rxfilter_lock);
4660
4661 /* release basic memory resources */
4662 kmem_free((caddr_t)(dp->private), dp->priv_size);
4663 kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(&dp->ugc));
4664
4665 DPRINTF(2, (CE_CONT, "!%s: %s: return: success",
4666 ddi_driver_name(dip), __func__));
4667
4668 return (DDI_SUCCESS);
4669 }
4670
4671 int
usbgem_mod_init(struct dev_ops * dop,char * name)4672 usbgem_mod_init(struct dev_ops *dop, char *name)
4673 {
4674 major_t major;
4675 major = ddi_name_to_major(name);
4676 if (major == DDI_MAJOR_T_NONE) {
4677 return (DDI_FAILURE);
4678 }
4679 mac_init_ops(dop, name);
4680
4681 return (DDI_SUCCESS);
4682 }
4683
4684 void
usbgem_mod_fini(struct dev_ops * dop)4685 usbgem_mod_fini(struct dev_ops *dop)
4686 {
4687 mac_fini_ops(dop);
4688 }
4689
4690 int
usbgem_quiesce(dev_info_t * dip)4691 usbgem_quiesce(dev_info_t *dip)
4692 {
4693 struct usbgem_dev *dp;
4694
4695 dp = USBGEM_GET_DEV(dip);
4696
4697 ASSERT(dp != NULL);
4698
4699 if (dp->mac_state != MAC_STATE_DISCONNECTED &&
4700 dp->mac_state != MAC_STATE_STOPPED) {
4701 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
4702 (void) usbgem_hal_reset_chip(dp);
4703 }
4704 }
4705
4706 /* devo_quiesce() must return DDI_SUCCESS always */
4707 return (DDI_SUCCESS);
4708 }
4709