xref: /illumos-gate/usr/src/uts/common/io/usbgem/usbgem.c (revision 7089fa466827d55e61d76b970fc9837cd1aea9ee)
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