xref: /illumos-gate/usr/src/uts/common/io/usbgem/usbgem.c (revision ceb6b962)
1 /*
2  * usbgem.c: General USB to Fast Ethernet mac driver framework
3  *
4  * Copyright (c) 2002-2012 Masayuki Murayama.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of the author nor the names of its contributors may be
17  *    used to endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  * DAMAGE.
32  */
33 
34 /*
35  * Copyright 2019 Joyent, Inc.
36  */
37 
38 /*
39  * Change log
40  */
41 
42 /*
43  * TODO:
44  *	implement DELAYED_START
45  */
46 
47 /*
48  * System Header files.
49  */
50 #include <sys/types.h>
51 #include <sys/conf.h>
52 #include <sys/debug.h>
53 #include <sys/kmem.h>
54 #include <sys/vtrace.h>
55 #include <sys/ethernet.h>
56 #include <sys/modctl.h>
57 #include <sys/errno.h>
58 #include <sys/ddi.h>
59 #include <sys/sunddi.h>
60 #include <sys/stream.h>		/* required for MBLK* */
61 #include <sys/strsun.h>		/* required for mionack() */
62 #include <sys/byteorder.h>
63 
64 #include <sys/usb/usba.h>
65 #include <inet/common.h>
66 #include <inet/led.h>
67 #include <inet/mi.h>
68 #include <inet/nd.h>
69 
70 /* supplement definitions */
71 extern const char *usb_str_cr(usb_cr_t);
72 
73 #include <sys/note.h>
74 
75 #include "usbgem_mii.h"
76 #include "usbgem.h"
77 
78 char	ident[] = "usb general ethernet mac driver v" VERSION;
79 
80 /* Debugging support */
81 #ifdef USBGEM_DEBUG_LEVEL
82 static int usbgem_debug = USBGEM_DEBUG_LEVEL;
83 #define	DPRINTF(n, args)	if (usbgem_debug > (n)) cmn_err args
84 #else
85 #define	DPRINTF(n, args)
86 #endif
87 
88 /*
89  * Useful macros and typedefs
90  */
91 #define	ROUNDUP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
92 #define	DEFAULT_PIPE(dp)	((dp)->reg_data->dev_default_ph)
93 #define	VTAG_SIZE	4
94 #define	BOOLEAN(x)	((x) != 0)
95 /*
96  * configuration parameters
97  */
98 #define	USBDRV_MAJOR_VER	2
99 #define	USBDRV_MINOR_VER	0
100 
101 #define	ETHERHEADERL	(sizeof (struct ether_header))
102 #define	MAXPKTLEN(dp)	((dp)->mtu + ETHERHEADERL)
103 #define	MAXPKTBUF(dp)	((dp)->mtu + ETHERHEADERL + ETHERFCSL)
104 
105 #define	WATCH_INTERVAL_FAST	drv_usectohz(100*1000)
106 
107 #define	STOP_GRACEFUL	B_TRUE
108 
109 /*
110  * Private functions
111  */
112 static int usbgem_open_pipes(struct usbgem_dev *dp);
113 static int usbgem_close_pipes(struct usbgem_dev *dp);
114 static void usbgem_intr_cb(usb_pipe_handle_t, usb_intr_req_t *);
115 static void usbgem_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
116 static void usbgem_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
117 
118 static int usbgem_mii_start(struct usbgem_dev *);
119 static void usbgem_mii_stop(struct usbgem_dev *);
120 
121 /* local buffer management */
122 static int usbgem_init_rx_buf(struct usbgem_dev *);
123 
124 /* internal mac interfaces */
125 static void usbgem_tx_timeout(struct usbgem_dev *);
126 static void usbgem_mii_link_watcher(struct usbgem_dev *);
127 static int usbgem_mac_init(struct usbgem_dev *);
128 static int usbgem_mac_start(struct usbgem_dev *);
129 static int usbgem_mac_stop(struct usbgem_dev *, int, boolean_t);
130 static void usbgem_mac_ioctl(struct usbgem_dev *, queue_t *, mblk_t *);
131 
132 int usbgem_speed_value[] = {10, 100, 1000};
133 
134 static int usbgem_ctrl_retry = 5;
135 
136 /* usb event support */
137 static int usbgem_disconnect_cb(dev_info_t *dip);
138 static int usbgem_reconnect_cb(dev_info_t *dip);
139 int usbgem_suspend(dev_info_t *dip);
140 int usbgem_resume(dev_info_t *dip);
141 
142 static uint8_t usbgem_bcastaddr[] = {
143 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
144 };
145 
146 extern struct mod_ops mod_miscops;
147 
148 static struct modlmisc modlmisc = {
149 	&mod_miscops,
150 	"usbgem v" VERSION,
151 };
152 
153 static struct modlinkage modlinkage = {
154 	MODREV_1, &modlmisc, NULL
155 };
156 
157 /*
158  * _init : done
159  */
160 int
_init(void)161 _init(void)
162 {
163 	int	status;
164 
165 	DPRINTF(2, (CE_CONT, "!usbgem: _init: called"));
166 	status = mod_install(&modlinkage);
167 
168 	return (status);
169 }
170 
171 /*
172  * _fini : done
173  */
174 int
_fini(void)175 _fini(void)
176 {
177 	int	status;
178 
179 	DPRINTF(2, (CE_CONT, "!usbgem: _fini: called"));
180 	status = mod_remove(&modlinkage);
181 	return (status);
182 }
183 
184 int
_info(struct modinfo * modinfop)185 _info(struct modinfo *modinfop)
186 {
187 	return (mod_info(&modlinkage, modinfop));
188 }
189 
190 /* ============================================================== */
191 /*
192  * Ether CRC calculation utilities
193  */
194 /* ============================================================== */
195 /*
196  * Ether CRC calculation according to 21143 data sheet
197  */
198 #define	CRC32_POLY_LE	0xedb88320
199 uint32_t
usbgem_ether_crc_le(const uint8_t * addr)200 usbgem_ether_crc_le(const uint8_t *addr)
201 {
202 	int		idx;
203 	int		bit;
204 	uint_t		data;
205 	uint32_t	crc = 0xffffffff;
206 
207 	crc = 0xffffffff;
208 	for (idx = 0; idx < ETHERADDRL; idx++) {
209 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
210 			crc = (crc >> 1) ^
211 			    (((crc ^ data) & 1) ? CRC32_POLY_LE : 0);
212 		}
213 	}
214 	return	(crc);
215 }
216 
217 #define	CRC32_POLY_BE	0x04c11db7
218 uint32_t
usbgem_ether_crc_be(const uint8_t * addr)219 usbgem_ether_crc_be(const uint8_t *addr)
220 {
221 	int		idx;
222 	int		bit;
223 	uint_t		data;
224 	uint32_t	crc;
225 
226 	crc = 0xffffffff;
227 	for (idx = 0; idx < ETHERADDRL; idx++) {
228 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
229 			crc = (crc << 1) ^
230 			    ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
231 		}
232 	}
233 	return (crc);
234 }
235 
236 int
usbgem_prop_get_int(struct usbgem_dev * dp,char * prop_template,int def_val)237 usbgem_prop_get_int(struct usbgem_dev *dp, char *prop_template, int def_val)
238 {
239 	char	propname[32];
240 
241 	(void) sprintf(propname, prop_template, dp->name);
242 
243 	return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
244 	    DDI_PROP_DONTPASS, propname, def_val));
245 }
246 
247 static int
usbgem_population(uint32_t x)248 usbgem_population(uint32_t x)
249 {
250 	int	i;
251 	int	cnt;
252 
253 	cnt = 0;
254 	for (i = 0; i < 32; i++) {
255 		if (x & (1 << i)) {
256 			cnt++;
257 		}
258 	}
259 	return (cnt);
260 }
261 
262 static clock_t
usbgem_timestamp_nz()263 usbgem_timestamp_nz()
264 {
265 	clock_t	now;
266 	now = ddi_get_lbolt();
267 	return (now ? now : (clock_t)1);
268 }
269 
270 #ifdef USBGEM_DEBUG_LEVEL
271 #ifdef USBGEM_DEBUG_VLAN
272 #ifdef notdef
273 #include <netinet/in.h>
274 #endif
275 static void
usbgem_dump_packet(struct usbgem_dev * dp,char * title,mblk_t * mp,boolean_t check_cksum)276 usbgem_dump_packet(struct usbgem_dev *dp, char *title, mblk_t *mp,
277     boolean_t check_cksum)
278 {
279 	char	msg[180];
280 	uint8_t	buf[18+20+20];
281 	uint8_t	*p;
282 	size_t	offset;
283 	uint_t	ethertype;
284 	uint_t	proto;
285 	uint_t	ipproto = 0;
286 	uint_t	iplen;
287 	uint_t	iphlen;
288 	uint_t	tcplen;
289 	uint_t	udplen;
290 	uint_t	cksum;
291 	int	rest;
292 	int	len;
293 	char	*bp;
294 	mblk_t	*tp;
295 	extern uint_t	ip_cksum(mblk_t *, int, uint32_t);
296 
297 	msg[0] = 0;
298 	bp = msg;
299 
300 	rest = sizeof (buf);
301 	offset = 0;
302 	for (tp = mp; tp; tp = tp->b_cont) {
303 		len = tp->b_wptr - tp->b_rptr;
304 		len = min(rest, len);
305 		bcopy(tp->b_rptr, &buf[offset], len);
306 		rest -= len;
307 		offset += len;
308 		if (rest == 0) {
309 			break;
310 		}
311 	}
312 
313 	offset = 0;
314 	p = &buf[offset];
315 
316 	/* ethernet address */
317 	sprintf(bp,
318 	    "ether: %02x:%02x:%02x:%02x:%02x:%02x"
319 	    " -> %02x:%02x:%02x:%02x:%02x:%02x",
320 	    p[6], p[7], p[8], p[9], p[10], p[11],
321 	    p[0], p[1], p[2], p[3], p[4], p[5]);
322 	bp = &msg[strlen(msg)];
323 
324 	/* vlag tag and etherrtype */
325 	ethertype = GET_ETHERTYPE(p);
326 	if (ethertype == VTAG_TPID) {
327 		sprintf(bp, " vtag:0x%04x", GET_NET16(&p[14]));
328 		bp = &msg[strlen(msg)];
329 
330 		offset += VTAG_SIZE;
331 		p = &buf[offset];
332 		ethertype = GET_ETHERTYPE(p);
333 	}
334 	sprintf(bp, " type:%04x", ethertype);
335 	bp = &msg[strlen(msg)];
336 
337 	/* ethernet packet length */
338 	sprintf(bp, " mblklen:%d", msgdsize(mp));
339 	bp = &msg[strlen(msg)];
340 	if (mp->b_cont) {
341 		sprintf(bp, "(");
342 		bp = &msg[strlen(msg)];
343 		for (tp = mp; tp; tp = tp->b_cont) {
344 			if (tp == mp) {
345 				sprintf(bp, "%d", tp->b_wptr - tp->b_rptr);
346 			} else {
347 				sprintf(bp, "+%d", tp->b_wptr - tp->b_rptr);
348 			}
349 			bp = &msg[strlen(msg)];
350 		}
351 		sprintf(bp, ")");
352 		bp = &msg[strlen(msg)];
353 	}
354 
355 	if (ethertype != ETHERTYPE_IP) {
356 		goto x;
357 	}
358 
359 	/* ip address */
360 	offset += sizeof (struct ether_header);
361 	p = &buf[offset];
362 	ipproto = p[9];
363 	iplen = GET_NET16(&p[2]);
364 	sprintf(bp, ", ip: %d.%d.%d.%d -> %d.%d.%d.%d proto:%d iplen:%d",
365 	    p[12], p[13], p[14], p[15],
366 	    p[16], p[17], p[18], p[19],
367 	    ipproto, iplen);
368 	bp = (void *)&msg[strlen(msg)];
369 
370 	iphlen = (p[0] & 0xf) * 4;
371 
372 	/* cksum for psuedo header */
373 	cksum = *(uint16_t *)&p[12];
374 	cksum += *(uint16_t *)&p[14];
375 	cksum += *(uint16_t *)&p[16];
376 	cksum += *(uint16_t *)&p[18];
377 	cksum += BE_16(ipproto);
378 
379 	/* tcp or udp protocol header */
380 	offset += iphlen;
381 	p = &buf[offset];
382 	if (ipproto == IPPROTO_TCP) {
383 		tcplen = iplen - iphlen;
384 		sprintf(bp, ", tcp: len:%d cksum:%x",
385 		    tcplen, GET_NET16(&p[16]));
386 		bp = (void *)&msg[strlen(msg)];
387 
388 		if (check_cksum) {
389 			cksum += BE_16(tcplen);
390 			cksum = (uint16_t)ip_cksum(mp, offset, cksum);
391 			sprintf(bp, " (%s)",
392 			    (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
393 			bp = (void *)&msg[strlen(msg)];
394 		}
395 	} else if (ipproto == IPPROTO_UDP) {
396 		udplen = GET_NET16(&p[4]);
397 		sprintf(bp, ", udp: len:%d cksum:%x",
398 		    udplen, GET_NET16(&p[6]));
399 		bp = (void *)&msg[strlen(msg)];
400 
401 		if (GET_NET16(&p[6]) && check_cksum) {
402 			cksum += *(uint16_t *)&p[4];
403 			cksum = (uint16_t)ip_cksum(mp, offset, cksum);
404 			sprintf(bp, " (%s)",
405 			    (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
406 			bp = (void *)&msg[strlen(msg)];
407 		}
408 	}
409 x:
410 	cmn_err(CE_CONT, "!%s: %s: %s", dp->name, title, msg);
411 }
412 #endif /* USBGEM_DEBUG_VLAN */
413 #endif /* USBGEM_DEBUG_LEVEL */
414 
415 /* ============================================================== */
416 /*
417  * hardware operations
418  */
419 /* ============================================================== */
420 static int
usbgem_hal_reset_chip(struct usbgem_dev * dp)421 usbgem_hal_reset_chip(struct usbgem_dev *dp)
422 {
423 	int	err;
424 
425 	sema_p(&dp->hal_op_lock);
426 	err = (*dp->ugc.usbgc_reset_chip)(dp);
427 	sema_v(&dp->hal_op_lock);
428 	return (err);
429 }
430 
431 static int
usbgem_hal_init_chip(struct usbgem_dev * dp)432 usbgem_hal_init_chip(struct usbgem_dev *dp)
433 {
434 	int	err;
435 
436 	sema_p(&dp->hal_op_lock);
437 	err = (*dp->ugc.usbgc_init_chip)(dp);
438 	sema_v(&dp->hal_op_lock);
439 	return (err);
440 }
441 
442 static int
usbgem_hal_attach_chip(struct usbgem_dev * dp)443 usbgem_hal_attach_chip(struct usbgem_dev *dp)
444 {
445 	int	err;
446 
447 	sema_p(&dp->hal_op_lock);
448 	err = (*dp->ugc.usbgc_attach_chip)(dp);
449 	sema_v(&dp->hal_op_lock);
450 	return (err);
451 }
452 
453 static int
usbgem_hal_set_rx_filter(struct usbgem_dev * dp)454 usbgem_hal_set_rx_filter(struct usbgem_dev *dp)
455 {
456 	int	err;
457 
458 	sema_p(&dp->hal_op_lock);
459 	err = (*dp->ugc.usbgc_set_rx_filter)(dp);
460 	sema_v(&dp->hal_op_lock);
461 	return (err);
462 }
463 
464 static int
usbgem_hal_set_media(struct usbgem_dev * dp)465 usbgem_hal_set_media(struct usbgem_dev *dp)
466 {
467 	int	err;
468 
469 	sema_p(&dp->hal_op_lock);
470 	err = (*dp->ugc.usbgc_set_media)(dp);
471 	sema_v(&dp->hal_op_lock);
472 	return (err);
473 }
474 
475 static int
usbgem_hal_start_chip(struct usbgem_dev * dp)476 usbgem_hal_start_chip(struct usbgem_dev *dp)
477 {
478 	int	err;
479 
480 	sema_p(&dp->hal_op_lock);
481 	err = (*dp->ugc.usbgc_start_chip)(dp);
482 	sema_v(&dp->hal_op_lock);
483 	return (err);
484 }
485 
486 static int
usbgem_hal_stop_chip(struct usbgem_dev * dp)487 usbgem_hal_stop_chip(struct usbgem_dev *dp)
488 {
489 	int	err;
490 
491 	sema_p(&dp->hal_op_lock);
492 	err = (*dp->ugc.usbgc_stop_chip)(dp);
493 	sema_v(&dp->hal_op_lock);
494 	return (err);
495 }
496 
497 static int
usbgem_hal_get_stats(struct usbgem_dev * dp)498 usbgem_hal_get_stats(struct usbgem_dev *dp)
499 {
500 	int	err;
501 
502 	sema_p(&dp->hal_op_lock);
503 	err = (*dp->ugc.usbgc_get_stats)(dp);
504 	sema_v(&dp->hal_op_lock);
505 	return (err);
506 }
507 
508 
509 /* ============================================================== */
510 /*
511  * USB pipe management
512  */
513 /* ============================================================== */
514 static boolean_t
usbgem_rx_start_unit(struct usbgem_dev * dp,usb_bulk_req_t * req)515 usbgem_rx_start_unit(struct usbgem_dev *dp, usb_bulk_req_t *req)
516 {
517 	mblk_t	*mp;
518 	int	err;
519 	usb_flags_t	flags;
520 
521 	ASSERT(req);
522 
523 	mp = allocb(dp->rx_buf_len, BPRI_MED);
524 	if (mp == NULL) {
525 		cmn_err(CE_WARN, "!%s: %s: failed to allocate mblk",
526 		    dp->name, __func__);
527 		goto err;
528 	}
529 
530 	req->bulk_len = dp->rx_buf_len;
531 	req->bulk_data = mp;
532 	req->bulk_client_private = (usb_opaque_t)dp;
533 	req->bulk_timeout = 0;
534 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
535 	req->bulk_cb = usbgem_bulkin_cb;
536 	req->bulk_exc_cb = usbgem_bulkin_cb;
537 	req->bulk_completion_reason = 0;
538 	req->bulk_cb_flags = 0;
539 
540 	flags = 0;
541 	err = usb_pipe_bulk_xfer(dp->bulkin_pipe, req, flags);
542 
543 	if (err != USB_SUCCESS) {
544 		cmn_err(CE_WARN, "%s: failed to bulk_xfer for rx, err:%d",
545 		    dp->name, err);
546 
547 		/* free req and mp */
548 		usb_free_bulk_req(req);
549 		goto err;
550 	}
551 	return (B_TRUE);
552 err:
553 	return (B_FALSE);
554 }
555 
556 /* ============================================================== */
557 /*
558  * Rx/Tx buffer management
559  */
560 /* ============================================================== */
561 static int
usbgem_init_rx_buf(struct usbgem_dev * dp)562 usbgem_init_rx_buf(struct usbgem_dev *dp)
563 {
564 	int	i;
565 	usb_bulk_req_t	*req;
566 
567 	ASSERT(dp->mac_state == MAC_STATE_ONLINE);
568 
569 	for (i = 0; i < dp->ugc.usbgc_rx_list_max; i++) {
570 		req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
571 		if (req == NULL) {
572 			cmn_err(CE_WARN,
573 			    "!%s: %s: failed to allocate bulkreq for rx",
574 			    dp->name, __func__);
575 			return (USB_FAILURE);
576 		}
577 		if (!usbgem_rx_start_unit(dp, req)) {
578 			return (USB_FAILURE);
579 		}
580 		mutex_enter(&dp->rxlock);
581 		dp->rx_busy_cnt++;
582 		mutex_exit(&dp->rxlock);
583 	}
584 	return (USB_SUCCESS);
585 }
586 
587 /* ============================================================== */
588 /*
589  * memory resource management
590  */
591 /* ============================================================== */
592 static int
usbgem_free_memory(struct usbgem_dev * dp)593 usbgem_free_memory(struct usbgem_dev *dp)
594 {
595 	usb_bulk_req_t	*req;
596 
597 	/* free all tx requst structure */
598 	while ((req = dp->tx_free_list) != NULL) {
599 		dp->tx_free_list =
600 		    (usb_bulk_req_t *)req->bulk_client_private;
601 		req->bulk_data = NULL;
602 		usb_free_bulk_req(req);
603 	}
604 	return (USB_SUCCESS);
605 }
606 
607 static int
usbgem_alloc_memory(struct usbgem_dev * dp)608 usbgem_alloc_memory(struct usbgem_dev *dp)
609 {
610 	int	i;
611 	usb_bulk_req_t	*req;
612 
613 	/* allocate tx requests */
614 	dp->tx_free_list = NULL;
615 	for (i = 0; i < dp->ugc.usbgc_tx_list_max; i++) {
616 		req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
617 		if (req == NULL) {
618 			cmn_err(CE_WARN,
619 			    "%s:%s failed to allocate tx requests",
620 			    dp->name, __func__);
621 
622 			/* free partially allocated tx requests */
623 			(void) usbgem_free_memory(dp);
624 			return (USB_FAILURE);
625 		}
626 
627 		/* add the new one allocated into tx free list */
628 		req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
629 		dp->tx_free_list = req;
630 	}
631 
632 	return (USB_SUCCESS);
633 }
634 
635 /* ========================================================== */
636 /*
637  * Start transmission.
638  * Return zero on success,
639  */
640 /* ========================================================== */
641 
642 #ifdef TXTIMEOUT_TEST
643 static int usbgem_send_cnt = 0;
644 #endif
645 
646 /*
647  * usbgem_send is used only to send data packet into ethernet line.
648  */
649 static mblk_t *
usbgem_send_common(struct usbgem_dev * dp,mblk_t * mp,uint32_t flags)650 usbgem_send_common(struct usbgem_dev *dp, mblk_t *mp, uint32_t flags)
651 {
652 	int		err;
653 	mblk_t		*new;
654 	usb_bulk_req_t	*req;
655 	int		mcast;
656 	int		bcast;
657 	int		len;
658 	boolean_t	intr;
659 	usb_flags_t	usb_flags = 0;
660 #ifdef USBGEM_DEBUG_LEVEL
661 	usb_pipe_state_t	p_state;
662 #endif
663 	DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
664 
665 	intr = (flags & 1) != 0;
666 	len = msgdsize(mp);
667 	bcast = 0;
668 	mcast = 0;
669 	if (mp->b_rptr[0] & 1) {
670 		if (bcmp(mp->b_rptr, &usbgem_bcastaddr, ETHERADDRL) == 0) {
671 			bcast = 1;
672 		} else {
673 			mcast = 1;
674 		}
675 	}
676 	new = (*dp->ugc.usbgc_tx_make_packet)(dp, mp);
677 	if (new == NULL) {
678 		/*
679 		 * no memory resource. we don't stop downstream,
680 		 * we just discard the packet.
681 		 */
682 		DPRINTF(0, (CE_CONT, "!%s: %s: no memory",
683 		    dp->name, __func__));
684 		freemsg(mp);
685 
686 		mutex_enter(&dp->txlock);
687 		dp->stats.noxmtbuf++;
688 		dp->stats.errxmt++;
689 		mutex_exit(&dp->txlock);
690 
691 		return (NULL);
692 	}
693 
694 	ASSERT(new->b_cont == NULL);
695 
696 	mutex_enter(&dp->txlock);
697 	if (dp->tx_free_list == NULL) {
698 		/*
699 		 * no tx free slot
700 		 */
701 		ASSERT(dp->tx_busy_cnt == dp->ugc.usbgc_tx_list_max);
702 		mutex_exit(&dp->txlock);
703 
704 		DPRINTF(4, (CE_CONT, "!%s: %s: no free slot",
705 		    dp->name, __func__));
706 		if (new && new != mp) {
707 			/* free reallocated message */
708 			freemsg(new);
709 		}
710 		return (mp);
711 	}
712 	req = dp->tx_free_list;
713 	dp->tx_free_list = (usb_bulk_req_t *)req->bulk_client_private;
714 	dp->tx_busy_cnt++;
715 
716 	if (dp->tx_free_list == NULL) {
717 		intr = B_TRUE;
718 	}
719 	if (intr) {
720 		dp->tx_intr_pended++;
721 	}
722 	DB_TCI(new) = intr;
723 #ifdef USBGEM_DEBUG_LEVEL
724 	new->b_datap->db_cksum32 = dp->tx_seq_num;
725 	dp->tx_seq_num++;
726 #endif
727 	dp->stats.obytes += len;
728 	dp->stats.opackets++;
729 	if (bcast | mcast) {
730 		dp->stats.obcast += bcast;
731 		dp->stats.omcast += mcast;
732 	}
733 	mutex_exit(&dp->txlock);
734 
735 	DPRINTF(2, (CE_CONT, "!%s: %s: sending", dp->name, __func__));
736 
737 	req->bulk_len = (long)new->b_wptr - (long)new->b_rptr;
738 	req->bulk_data = new;
739 	req->bulk_client_private = (usb_opaque_t)dp;
740 	req->bulk_timeout = dp->bulkout_timeout;	/* in second */
741 	req->bulk_attributes = 0;
742 	req->bulk_cb = usbgem_bulkout_cb;
743 	req->bulk_exc_cb = usbgem_bulkout_cb;
744 	req->bulk_completion_reason = 0;
745 	req->bulk_cb_flags = 0;
746 
747 	if (intr) {
748 		usb_flags = USB_FLAGS_SLEEP;
749 	}
750 	if ((err = usb_pipe_bulk_xfer(dp->bulkout_pipe, req, usb_flags))
751 	    != USB_SUCCESS) {
752 
753 		/* failed to transfer the packet, discard it. */
754 		freemsg(new);
755 		req->bulk_data = NULL;
756 
757 		/* recycle the request block */
758 		mutex_enter(&dp->txlock);
759 		dp->tx_busy_cnt--;
760 		req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
761 		dp->tx_free_list = req;
762 		mutex_exit(&dp->txlock);
763 
764 		cmn_err(CE_NOTE,
765 		    "%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
766 		    dp->name, __func__, err);
767 
768 		/* we use another flag to indicate error state. */
769 		if (dp->fatal_error == (clock_t)0) {
770 			dp->fatal_error = usbgem_timestamp_nz();
771 		}
772 	} else {
773 		/* record the start time */
774 		dp->tx_start_time = ddi_get_lbolt();
775 	}
776 
777 	if (err == USB_SUCCESS && (usb_flags & USB_FLAGS_SLEEP)) {
778 		usbgem_bulkout_cb(dp->bulkout_pipe, req);
779 	}
780 
781 	if (new != mp) {
782 		freemsg(mp);
783 	}
784 	return (NULL);
785 }
786 
787 int
usbgem_restart_nic(struct usbgem_dev * dp)788 usbgem_restart_nic(struct usbgem_dev *dp)
789 {
790 	int	ret;
791 	int	flags = 0;
792 
793 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
794 
795 	ASSERT(dp->mac_state != MAC_STATE_DISCONNECTED);
796 
797 	/*
798 	 * ensure to stop the nic
799 	 */
800 	if (dp->mac_state == MAC_STATE_ONLINE) {
801 		(void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
802 	}
803 
804 	/* now the nic become quiescent, reset the chip */
805 	if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
806 		cmn_err(CE_WARN, "%s: %s: failed to reset chip",
807 		    dp->name, __func__);
808 		goto err;
809 	}
810 
811 	/*
812 	 * restore the nic state step by step
813 	 */
814 	if (dp->nic_state < NIC_STATE_INITIALIZED) {
815 		goto done;
816 	}
817 
818 	if (usbgem_mac_init(dp) != USB_SUCCESS) {
819 		cmn_err(CE_WARN, "%s: %s: failed to initialize chip",
820 		    dp->name, __func__);
821 		goto err;
822 	}
823 
824 	/* setup mac address and enable rx filter */
825 	sema_p(&dp->rxfilter_lock);
826 	dp->rxmode |= RXMODE_ENABLE;
827 	ret = usbgem_hal_set_rx_filter(dp);
828 	sema_v(&dp->rxfilter_lock);
829 	if (ret != USB_SUCCESS) {
830 		goto err;
831 	}
832 
833 	/*
834 	 * update the link state asynchronously
835 	 */
836 	cv_signal(&dp->link_watcher_wait_cv);
837 
838 	/*
839 	 * XXX - a panic happened because of linkdown.
840 	 * We must check mii_state here, because the link can be down just
841 	 * before the restart event happen. If the link is down now,
842 	 * gem_mac_start() will be called from gem_mii_link_check() when
843 	 * the link become up later.
844 	 */
845 	if (dp->mii_state == MII_STATE_LINKUP) {
846 		if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
847 			goto err;
848 		}
849 		if (dp->nic_state < NIC_STATE_ONLINE) {
850 			goto done;
851 		}
852 
853 		(void) usbgem_mac_start(dp);
854 
855 	}
856 done:
857 	return (USB_SUCCESS);
858 err:
859 #ifdef GEM_CONFIG_FMA
860 	ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
861 #endif
862 	return (USB_FAILURE);
863 }
864 
865 static void
usbgem_tx_timeout(struct usbgem_dev * dp)866 usbgem_tx_timeout(struct usbgem_dev *dp)
867 {
868 	uint_t	rwlock;
869 	clock_t	now;
870 
871 	for (; ; ) {
872 		mutex_enter(&dp->tx_watcher_lock);
873 		(void) cv_timedwait(&dp->tx_watcher_cv, &dp->tx_watcher_lock,
874 		    dp->tx_watcher_interval + ddi_get_lbolt());
875 		mutex_exit(&dp->tx_watcher_lock);
876 
877 		if (dp->tx_watcher_stop) {
878 			break;
879 		}
880 
881 		now = ddi_get_lbolt();
882 
883 		rwlock = RW_READER;
884 again:
885 		rw_enter(&dp->dev_state_lock, rwlock);
886 
887 		if ((dp->mac_state != MAC_STATE_DISCONNECTED &&
888 		    dp->fatal_error &&
889 		    now - dp->fatal_error >= dp->ugc.usbgc_tx_timeout) ||
890 		    (dp->mac_state == MAC_STATE_ONLINE &&
891 		    dp->mii_state == MII_STATE_LINKUP &&
892 		    dp->tx_busy_cnt != 0 &&
893 		    now - dp->tx_start_time >= dp->ugc.usbgc_tx_timeout)) {
894 			if (rwlock == RW_READER) {
895 				/*
896 				 * Upgrade dev_state_lock from shared mode
897 				 * to exclusive mode to restart nic
898 				 */
899 				rwlock = RW_WRITER;
900 				rw_exit(&dp->dev_state_lock);
901 				goto again;
902 			}
903 			cmn_err(CE_WARN, "%s: %s: restarting the nic:"
904 			    " fatal_error:%ld nic_state:%d"
905 			    " mac_state:%d starttime:%ld",
906 			    dp->name, __func__,
907 			    dp->fatal_error ? now - dp->fatal_error: 0,
908 			    dp->nic_state, dp->mac_state,
909 			    dp->tx_busy_cnt ? now - dp->tx_start_time : 0);
910 
911 			(void) usbgem_restart_nic(dp);
912 		}
913 
914 		rw_exit(&dp->dev_state_lock);
915 	}
916 }
917 
918 static int
usbgem_tx_watcher_start(struct usbgem_dev * dp)919 usbgem_tx_watcher_start(struct usbgem_dev *dp)
920 {
921 	int	err;
922 	kthread_t	*wdth;
923 
924 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
925 
926 	/* make a first call of uwgem_lw_link_check() */
927 	dp->tx_watcher_stop = 0;
928 	dp->tx_watcher_interval = drv_usectohz(1000*1000);
929 
930 	wdth = thread_create(NULL, 0, usbgem_tx_timeout, dp, 0, &p0,
931 	    TS_RUN, minclsyspri);
932 	if (wdth == NULL) {
933 		cmn_err(CE_WARN,
934 		    "!%s: %s: failed to create a tx_watcher thread",
935 		    dp->name, __func__);
936 		return (USB_FAILURE);
937 	}
938 	dp->tx_watcher_did = wdth->t_did;
939 
940 	return (USB_SUCCESS);
941 }
942 
943 static void
usbgem_tx_watcher_stop(struct usbgem_dev * dp)944 usbgem_tx_watcher_stop(struct usbgem_dev *dp)
945 {
946 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
947 	if (dp->tx_watcher_did) {
948 		/* Ensure timer routine stopped */
949 		dp->tx_watcher_stop = 1;
950 		cv_signal(&dp->tx_watcher_cv);
951 		thread_join(dp->tx_watcher_did);
952 		dp->tx_watcher_did = 0;
953 	}
954 }
955 
956 /* ================================================================== */
957 /*
958  * Callback handlers
959  */
960 /* ================================================================== */
961 static void
usbgem_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)962 usbgem_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
963 {
964 	mblk_t	*newmp;
965 	mblk_t	*mp;
966 	mblk_t	*tp;
967 	uint64_t	len = 0;
968 	int	pkts = 0;
969 	int	bcast = 0;
970 	int	mcast = 0;
971 	boolean_t	busy;
972 	struct usbgem_dev	*dp;
973 
974 	dp = (struct usbgem_dev *)req->bulk_client_private;
975 	mp = req->bulk_data;
976 	req->bulk_data = NULL;
977 
978 	DPRINTF(2, (CE_CONT, "!%s: %s: mp:%p, cr:%s(%d)",
979 	    dp->name, __func__, mp,
980 	    usb_str_cr(req->bulk_completion_reason),
981 	    req->bulk_completion_reason));
982 
983 	/*
984 	 * we cannot acquire dev_state_lock because the routine
985 	 * must be executed during usbgem_mac_stop() to avoid
986 	 * dead lock.
987 	 * we use a simle membar operation to get the state correctly.
988 	 */
989 	membar_consumer();
990 
991 	if (req->bulk_completion_reason == USB_CR_OK &&
992 	    dp->nic_state == NIC_STATE_ONLINE) {
993 		newmp = (*dp->ugc.usbgc_rx_make_packet)(dp, mp);
994 
995 		if (newmp != mp) {
996 			/* the message has been reallocated, free old one */
997 			freemsg(mp);
998 		}
999 
1000 		/* the message may includes one or more ethernet packets */
1001 		for (tp = newmp; tp; tp = tp->b_next) {
1002 			len += (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
1003 			pkts++;
1004 			if (tp->b_rptr[0] & 1) {
1005 				if (bcmp(tp->b_rptr, &usbgem_bcastaddr,
1006 				    ETHERADDRL) == 0) {
1007 					bcast++;
1008 				} else {
1009 					mcast++;
1010 				}
1011 			}
1012 		}
1013 
1014 		/* send up if it is a valid packet */
1015 		mac_rx(dp->mh, NULL, newmp);
1016 	} else {
1017 		freemsg(mp);
1018 		len = 0;
1019 	}
1020 
1021 	mutex_enter(&dp->rxlock);
1022 	/* update rx_active */
1023 	if (dp->rx_active) {
1024 		dp->rx_active = dp->mac_state == MAC_STATE_ONLINE;
1025 	}
1026 
1027 	dp->stats.rbytes += len;
1028 	dp->stats.rpackets += pkts;
1029 	if (bcast | mcast) {
1030 		dp->stats.rbcast += bcast;
1031 		dp->stats.rmcast += mcast;
1032 	}
1033 	mutex_exit(&dp->rxlock);
1034 
1035 	if (dp->rx_active) {
1036 		/* prepare to receive the next packets */
1037 		if (usbgem_rx_start_unit(dp, req)) {
1038 			/* we successed */
1039 			goto done;
1040 		}
1041 		cmn_err(CE_WARN,
1042 		    "!%s: %s: failed to fill next rx packet",
1043 		    dp->name, __func__);
1044 		/*
1045 		 * we use another flag to indicate error state.
1046 		 * if we acquire dev_state_lock for RW_WRITER here,
1047 		 * usbgem_mac_stop() may hang.
1048 		 */
1049 		if (dp->fatal_error == (clock_t)0) {
1050 			dp->fatal_error = usbgem_timestamp_nz();
1051 		}
1052 	} else {
1053 		/* no need to prepare the next packets */
1054 		usb_free_bulk_req(req);
1055 	}
1056 
1057 	mutex_enter(&dp->rxlock);
1058 	dp->rx_active = B_FALSE;
1059 	dp->rx_busy_cnt--;
1060 	if (dp->rx_busy_cnt == 0) {
1061 		/* wake up someone waits for me */
1062 		cv_broadcast(&dp->rx_drain_cv);
1063 	}
1064 	mutex_exit(&dp->rxlock);
1065 done:
1066 	;
1067 }
1068 
1069 static void
usbgem_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)1070 usbgem_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1071 {
1072 	boolean_t	intr;
1073 	boolean_t	tx_sched;
1074 	struct usbgem_dev	*dp;
1075 
1076 	dp = (struct usbgem_dev *)req->bulk_client_private;
1077 	tx_sched = B_FALSE;
1078 
1079 	DPRINTF(2, (CE_CONT,
1080 	    "!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
1081 	    dp->name, __func__,
1082 	    usb_str_cr(req->bulk_completion_reason),
1083 	    req->bulk_completion_reason,
1084 	    req->bulk_cb_flags,
1085 	    dp->tx_busy_cnt));
1086 
1087 	/* we have finished to transfer the packet into tx fifo */
1088 	intr = DB_TCI(req->bulk_data);
1089 	freemsg(req->bulk_data);
1090 
1091 	if (req->bulk_completion_reason != USB_CR_OK &&
1092 	    dp->fatal_error == (clock_t)0) {
1093 		dp->fatal_error = usbgem_timestamp_nz();
1094 	}
1095 
1096 	mutex_enter(&dp->txlock);
1097 
1098 	if (intr) {
1099 		ASSERT(dp->tx_intr_pended > 0);
1100 		/* find the last interrupt we have scheduled */
1101 		if (--(dp->tx_intr_pended) == 0) {
1102 			tx_sched = B_TRUE;
1103 		}
1104 	}
1105 
1106 	ASSERT(dp->tx_busy_cnt > 0);
1107 	req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
1108 	dp->tx_free_list = req;
1109 	dp->tx_busy_cnt--;
1110 
1111 #ifdef CONFIG_TX_LIMITER
1112 	if (tx_sched) {
1113 		dp->tx_max_packets =
1114 		    min(dp->tx_max_packets + 1, dp->ugc.usbgc_tx_list_max);
1115 	}
1116 #endif
1117 	if (dp->mac_state != MAC_STATE_ONLINE && dp->tx_busy_cnt == 0) {
1118 		cv_broadcast(&dp->tx_drain_cv);
1119 	}
1120 
1121 	mutex_exit(&dp->txlock);
1122 
1123 	if (tx_sched) {
1124 		mac_tx_update(dp->mh);
1125 	}
1126 }
1127 
1128 static void
usbgem_intr_cb(usb_pipe_handle_t ph,usb_intr_req_t * req)1129 usbgem_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1130 {
1131 	struct usbgem_dev	*dp;
1132 
1133 	dp = (struct usbgem_dev *)req->intr_client_private;
1134 	dp->stats.intr++;
1135 
1136 	if (req->intr_completion_reason == USB_CR_OK) {
1137 		(*dp->ugc.usbgc_interrupt)(dp, req->intr_data);
1138 	}
1139 
1140 	/* free the request and data */
1141 	usb_free_intr_req(req);
1142 }
1143 
1144 /* ======================================================================== */
1145 /*
1146  * MII support routines
1147  */
1148 /* ======================================================================== */
1149 static void
usbgem_choose_forcedmode(struct usbgem_dev * dp)1150 usbgem_choose_forcedmode(struct usbgem_dev *dp)
1151 {
1152 	/* choose media mode */
1153 	if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
1154 		dp->speed = USBGEM_SPD_1000;
1155 		dp->full_duplex = dp->anadv_1000fdx;
1156 	} else if (dp->anadv_100fdx || dp->anadv_100t4) {
1157 		dp->speed = USBGEM_SPD_100;
1158 		dp->full_duplex = B_TRUE;
1159 	} else if (dp->anadv_100hdx) {
1160 		dp->speed = USBGEM_SPD_100;
1161 		dp->full_duplex = B_FALSE;
1162 	} else {
1163 		dp->speed = USBGEM_SPD_10;
1164 		dp->full_duplex = dp->anadv_10fdx;
1165 	}
1166 }
1167 
1168 static uint16_t
usbgem_mii_read(struct usbgem_dev * dp,uint_t reg,int * errp)1169 usbgem_mii_read(struct usbgem_dev *dp, uint_t reg, int *errp)
1170 {
1171 	uint16_t	val;
1172 
1173 	sema_p(&dp->hal_op_lock);
1174 	val = (*dp->ugc.usbgc_mii_read)(dp, reg, errp);
1175 	sema_v(&dp->hal_op_lock);
1176 
1177 	return (val);
1178 }
1179 
1180 static void
usbgem_mii_write(struct usbgem_dev * dp,uint_t reg,uint16_t val,int * errp)1181 usbgem_mii_write(struct usbgem_dev *dp, uint_t reg, uint16_t val, int *errp)
1182 {
1183 	sema_p(&dp->hal_op_lock);
1184 	(*dp->ugc.usbgc_mii_write)(dp, reg, val, errp);
1185 	sema_v(&dp->hal_op_lock);
1186 }
1187 
1188 static int
usbgem_mii_probe(struct usbgem_dev * dp)1189 usbgem_mii_probe(struct usbgem_dev *dp)
1190 {
1191 	int	err;
1192 
1193 	err = (*dp->ugc.usbgc_mii_probe)(dp);
1194 	return (err);
1195 }
1196 
1197 static int
usbgem_mii_init(struct usbgem_dev * dp)1198 usbgem_mii_init(struct usbgem_dev *dp)
1199 {
1200 	int	err;
1201 
1202 	err = (*dp->ugc.usbgc_mii_init)(dp);
1203 	return (err);
1204 }
1205 
1206 #define	fc_cap_decode(x)	\
1207 	((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) |	\
1208 	(((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
1209 
1210 int
usbgem_mii_config_default(struct usbgem_dev * dp,int * errp)1211 usbgem_mii_config_default(struct usbgem_dev *dp, int *errp)
1212 {
1213 	uint16_t	mii_stat;
1214 	uint16_t	val;
1215 
1216 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1217 
1218 	/*
1219 	 * Configure bits in advertisement register
1220 	 */
1221 	mii_stat = dp->mii_status;
1222 
1223 	DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
1224 	    dp->name, __func__, mii_stat, MII_STATUS_BITS));
1225 
1226 	if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
1227 		/* it's funny */
1228 		cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
1229 		    dp->name, mii_stat, MII_STATUS_BITS);
1230 		return (USB_FAILURE);
1231 	}
1232 
1233 	/* Do not change the rest of ability bits in advert reg */
1234 	val = usbgem_mii_read(dp, MII_AN_ADVERT, errp) & ~MII_ABILITY_ALL;
1235 	if (*errp != USB_SUCCESS) {
1236 		goto usberr;
1237 	}
1238 
1239 	DPRINTF(0, (CE_CONT,
1240 	    "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
1241 	    dp->name, __func__,
1242 	    dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
1243 	    dp->anadv_10fdx, dp->anadv_10hdx));
1244 
1245 	/* set technology bits */
1246 	if (dp->anadv_100t4) {
1247 		val |= MII_ABILITY_100BASE_T4;
1248 	}
1249 	if (dp->anadv_100fdx) {
1250 		val |= MII_ABILITY_100BASE_TX_FD;
1251 	}
1252 	if (dp->anadv_100hdx) {
1253 		val |= MII_ABILITY_100BASE_TX;
1254 	}
1255 	if (dp->anadv_10fdx) {
1256 		val |= MII_ABILITY_10BASE_T_FD;
1257 	}
1258 	if (dp->anadv_10hdx) {
1259 		val |= MII_ABILITY_10BASE_T;
1260 	}
1261 
1262 	/* set flow control capabilities */
1263 	if (dp->anadv_pause) {
1264 		val |= MII_ABILITY_PAUSE;
1265 	}
1266 	if (dp->anadv_asmpause) {
1267 		val |= MII_ABILITY_ASM_DIR;
1268 	}
1269 
1270 	DPRINTF(0, (CE_CONT,
1271 	    "!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
1272 	    dp->name, __func__, val, MII_ABILITY_BITS,
1273 	    dp->anadv_pause, dp->anadv_asmpause));
1274 
1275 	usbgem_mii_write(dp, MII_AN_ADVERT, val, errp);
1276 	if (*errp != USB_SUCCESS) {
1277 		goto usberr;
1278 	}
1279 
1280 	if (dp->mii_status & MII_STATUS_XSTATUS) {
1281 		/*
1282 		 * 1000Base-T GMII support
1283 		 */
1284 		if (!dp->anadv_autoneg) {
1285 			/* enable manual configuration */
1286 			val = MII_1000TC_CFG_EN;
1287 			if (dp->anadv_1000t_ms == 2) {
1288 				val |= MII_1000TC_CFG_VAL;
1289 			}
1290 		} else {
1291 			val = 0;
1292 			if (dp->anadv_1000fdx) {
1293 				val |= MII_1000TC_ADV_FULL;
1294 			}
1295 			if (dp->anadv_1000hdx) {
1296 				val |= MII_1000TC_ADV_HALF;
1297 			}
1298 			switch (dp->anadv_1000t_ms) {
1299 			case 1:
1300 				/* slave */
1301 				val |= MII_1000TC_CFG_EN;
1302 				break;
1303 
1304 			case 2:
1305 				/* master */
1306 				val |= MII_1000TC_CFG_EN | MII_1000TC_CFG_VAL;
1307 				break;
1308 
1309 			default:
1310 				/* auto: do nothing */
1311 				break;
1312 			}
1313 		}
1314 		DPRINTF(0, (CE_CONT,
1315 		    "!%s: %s: setting MII_1000TC reg:%b",
1316 		    dp->name, __func__, val, MII_1000TC_BITS));
1317 
1318 		usbgem_mii_write(dp, MII_1000TC, val, errp);
1319 		if (*errp != USB_SUCCESS) {
1320 			goto usberr;
1321 		}
1322 	}
1323 	return (USB_SUCCESS);
1324 
1325 usberr:
1326 	return (*errp);
1327 }
1328 
1329 static char *usbgem_fc_type[] = {
1330 	"without",
1331 	"with symmetric",
1332 	"with tx",
1333 	"with rx",
1334 };
1335 
1336 #define	USBGEM_LINKUP(dp)	mac_link_update((dp)->mh, LINK_STATE_UP)
1337 #define	USBGEM_LINKDOWN(dp)	mac_link_update((dp)->mh, LINK_STATE_DOWN)
1338 
1339 static uint8_t usbgem_fc_result[4 /* my cap */][4 /* lp cap */] = {
1340 /*	 none	symm	tx	rx/symm */
1341 /* none */
1342 	{FLOW_CONTROL_NONE,
1343 		FLOW_CONTROL_NONE,
1344 			FLOW_CONTROL_NONE,
1345 				FLOW_CONTROL_NONE},
1346 /* sym */
1347 	{FLOW_CONTROL_NONE,
1348 		FLOW_CONTROL_SYMMETRIC,
1349 			FLOW_CONTROL_NONE,
1350 				FLOW_CONTROL_SYMMETRIC},
1351 /* tx */
1352 	{FLOW_CONTROL_NONE,
1353 		FLOW_CONTROL_NONE,
1354 			FLOW_CONTROL_NONE,
1355 				FLOW_CONTROL_TX_PAUSE},
1356 /* rx/symm */
1357 	{FLOW_CONTROL_NONE,
1358 		FLOW_CONTROL_SYMMETRIC,
1359 			FLOW_CONTROL_RX_PAUSE,
1360 				FLOW_CONTROL_SYMMETRIC},
1361 };
1362 
1363 static boolean_t
usbgem_mii_link_check(struct usbgem_dev * dp,int * oldstatep,int * newstatep)1364 usbgem_mii_link_check(struct usbgem_dev *dp, int *oldstatep, int *newstatep)
1365 {
1366 	boolean_t	tx_sched = B_FALSE;
1367 	uint16_t	status;
1368 	uint16_t	advert;
1369 	uint16_t	lpable;
1370 	uint16_t	exp;
1371 	uint16_t	ctl1000;
1372 	uint16_t	stat1000;
1373 	uint16_t	val;
1374 	clock_t		now;
1375 	clock_t		diff;
1376 	int		linkdown_action;
1377 	boolean_t	fix_phy = B_FALSE;
1378 	int		err;
1379 	uint_t		rwlock;
1380 
1381 	DPRINTF(4, (CE_CONT, "!%s: %s: time:%d state:%d",
1382 	    dp->name, __func__, ddi_get_lbolt(), dp->mii_state));
1383 
1384 	if (dp->mii_state != MII_STATE_LINKUP) {
1385 		rwlock = RW_WRITER;
1386 	} else {
1387 		rwlock = RW_READER;
1388 	}
1389 again:
1390 	rw_enter(&dp->dev_state_lock, rwlock);
1391 
1392 	/* save old mii state */
1393 	*oldstatep = dp->mii_state;
1394 
1395 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
1396 		/* stop periodic execution of the link watcher */
1397 		dp->mii_interval = 0;
1398 		tx_sched = B_FALSE;
1399 		goto next;
1400 	}
1401 
1402 	now = ddi_get_lbolt();
1403 	diff = now - dp->mii_last_check;
1404 	dp->mii_last_check = now;
1405 
1406 	/*
1407 	 * For NWAM, don't show linkdown state right
1408 	 * when the device is attached.
1409 	 */
1410 	if (dp->linkup_delay > 0) {
1411 		if (dp->linkup_delay > diff) {
1412 			dp->linkup_delay -= diff;
1413 		} else {
1414 			/* link up timeout */
1415 			dp->linkup_delay = -1;
1416 		}
1417 	}
1418 
1419 next_nowait:
1420 	switch (dp->mii_state) {
1421 	case MII_STATE_UNKNOWN:
1422 		goto reset_phy;
1423 
1424 	case MII_STATE_RESETTING:
1425 		dp->mii_timer -= diff;
1426 		if (dp->mii_timer > 0) {
1427 			/* don't read phy registers in resetting */
1428 			dp->mii_interval = WATCH_INTERVAL_FAST;
1429 			goto next;
1430 		}
1431 
1432 		val = usbgem_mii_read(dp, MII_CONTROL, &err);
1433 		if (err != USB_SUCCESS) {
1434 			goto usberr;
1435 		}
1436 		if (val & MII_CONTROL_RESET) {
1437 			cmn_err(CE_NOTE,
1438 			    "!%s: time:%ld resetting phy not complete."
1439 			    " mii_control:0x%b",
1440 			    dp->name, ddi_get_lbolt(),
1441 			    val, MII_CONTROL_BITS);
1442 		}
1443 
1444 		/* ensure neither isolated nor pwrdown nor auto-nego mode */
1445 		usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1446 		if (err != USB_SUCCESS) {
1447 			goto usberr;
1448 		}
1449 #if USBGEM_DEBUG_LEVEL > 10
1450 		val = usbgem_mii_read(dp, MII_CONTROL, &err);
1451 		cmn_err(CE_CONT, "!%s: readback control %b",
1452 		    dp->name, val, MII_CONTROL_BITS);
1453 #endif
1454 		/* As resetting PHY has completed, configure PHY registers */
1455 		if ((*dp->ugc.usbgc_mii_config)(dp, &err) != USB_SUCCESS) {
1456 			/* we failed to configure PHY */
1457 			goto usberr;
1458 		}
1459 
1460 		/* prepare for forced mode */
1461 		usbgem_choose_forcedmode(dp);
1462 
1463 		dp->mii_lpable = 0;
1464 		dp->mii_advert = 0;
1465 		dp->mii_exp = 0;
1466 		dp->mii_ctl1000 = 0;
1467 		dp->mii_stat1000 = 0;
1468 
1469 		dp->flow_control = FLOW_CONTROL_NONE;
1470 
1471 		if (!dp->anadv_autoneg) {
1472 			/* skip auto-negotiation phase */
1473 			dp->mii_state = MII_STATE_MEDIA_SETUP;
1474 			dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1475 			goto next_nowait;
1476 		}
1477 
1478 		/* issue an auto-negotiation command */
1479 		goto autonego;
1480 
1481 	case MII_STATE_AUTONEGOTIATING:
1482 		/*
1483 		 * Autonegotiation in progress
1484 		 */
1485 		dp->mii_timer -= diff;
1486 		if (dp->mii_timer -
1487 		    (dp->ugc.usbgc_mii_an_timeout - dp->ugc.usbgc_mii_an_wait)
1488 		    > 0) {
1489 			/* wait for minimum time (2.3 - 2.5 sec) */
1490 			dp->mii_interval = WATCH_INTERVAL_FAST;
1491 			goto next;
1492 		}
1493 
1494 		/* read PHY status */
1495 		status = usbgem_mii_read(dp, MII_STATUS, &err);
1496 		if (err != USB_SUCCESS) {
1497 			goto usberr;
1498 		}
1499 		DPRINTF(4, (CE_CONT,
1500 		    "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
1501 		    dp->name, __func__, dp->mii_state,
1502 		    status, MII_STATUS_BITS));
1503 
1504 		if (status & MII_STATUS_REMFAULT) {
1505 			/*
1506 			 * The link parnert told me something wrong happend.
1507 			 * What do we do ?
1508 			 */
1509 			cmn_err(CE_CONT,
1510 			    "!%s: auto-negotiation failed: remote fault",
1511 			    dp->name);
1512 			goto autonego;
1513 		}
1514 
1515 		if ((status & MII_STATUS_ANDONE) == 0) {
1516 			if (dp->mii_timer <= 0) {
1517 				/*
1518 				 * Auto-negotiation has been timed out,
1519 				 * Reset PHY and try again.
1520 				 */
1521 				if (!dp->mii_supress_msg) {
1522 					cmn_err(CE_WARN,
1523 					    "!%s: auto-negotiation failed:"
1524 					    " timeout",
1525 					    dp->name);
1526 					dp->mii_supress_msg = B_TRUE;
1527 				}
1528 				goto autonego;
1529 			}
1530 			/*
1531 			 * Auto-negotiation is in progress. Wait for a while.
1532 			 */
1533 			dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1534 			goto next;
1535 		}
1536 
1537 		/*
1538 		 * Auto-negotiation has been completed. Let's go to AN_DONE.
1539 		 */
1540 		dp->mii_state = MII_STATE_AN_DONE;
1541 		dp->mii_supress_msg = B_FALSE;
1542 		DPRINTF(0, (CE_CONT,
1543 		    "!%s: auto-negotiation completed, MII_STATUS:%b",
1544 		    dp->name, status, MII_STATUS_BITS));
1545 
1546 		if (dp->ugc.usbgc_mii_an_delay > 0) {
1547 			dp->mii_timer = dp->ugc.usbgc_mii_an_delay;
1548 			dp->mii_interval = drv_usectohz(20*1000);
1549 			goto next;
1550 		}
1551 
1552 		dp->mii_timer = 0;
1553 		diff = 0;
1554 		goto next_nowait;
1555 
1556 	case MII_STATE_AN_DONE:
1557 		/*
1558 		 * Auto-negotiation has done. Now we can set up media.
1559 		 */
1560 		dp->mii_timer -= diff;
1561 		if (dp->mii_timer > 0) {
1562 			/* wait for a while */
1563 			dp->mii_interval = WATCH_INTERVAL_FAST;
1564 			goto next;
1565 		}
1566 
1567 		/*
1568 		 * Setup speed and duplex mode according with
1569 		 * the result of auto negotiation.
1570 		 */
1571 
1572 		/*
1573 		 * Read registers required to determin current
1574 		 * duplex mode and media speed.
1575 		 */
1576 		if (dp->ugc.usbgc_mii_an_delay > 0) {
1577 			/* the 'status' variable is not initialized yet */
1578 			status = usbgem_mii_read(dp, MII_STATUS, &err);
1579 			if (err != USB_SUCCESS) {
1580 				goto usberr;
1581 			}
1582 		}
1583 		advert = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
1584 		if (err != USB_SUCCESS) {
1585 			goto usberr;
1586 		}
1587 		lpable = usbgem_mii_read(dp, MII_AN_LPABLE, &err);
1588 		if (err != USB_SUCCESS) {
1589 			goto usberr;
1590 		}
1591 		exp = usbgem_mii_read(dp, MII_AN_EXPANSION, &err);
1592 		if (err != USB_SUCCESS) {
1593 			goto usberr;
1594 		}
1595 		if (exp == 0xffff) {
1596 			/* some phys don't have exp register */
1597 			exp = 0;
1598 		}
1599 
1600 		ctl1000 = 0;
1601 		stat1000 = 0;
1602 		if (dp->mii_status & MII_STATUS_XSTATUS) {
1603 			ctl1000 = usbgem_mii_read(dp, MII_1000TC, &err);
1604 			if (err != USB_SUCCESS) {
1605 				goto usberr;
1606 			}
1607 			stat1000 = usbgem_mii_read(dp, MII_1000TS, &err);
1608 			if (err != USB_SUCCESS) {
1609 				goto usberr;
1610 			}
1611 		}
1612 		dp->mii_lpable = lpable;
1613 		dp->mii_advert = advert;
1614 		dp->mii_exp = exp;
1615 		dp->mii_ctl1000 = ctl1000;
1616 		dp->mii_stat1000 = stat1000;
1617 
1618 		cmn_err(CE_CONT,
1619 		    "!%s: auto-negotiation done: "
1620 		    "status:%b, advert:%b, lpable:%b, exp:%b",
1621 		    dp->name,
1622 		    status, MII_STATUS_BITS,
1623 		    advert, MII_ABILITY_BITS,
1624 		    lpable, MII_ABILITY_BITS,
1625 		    exp, MII_AN_EXP_BITS);
1626 
1627 		DPRINTF(0, (CE_CONT, "!%s: MII_STATUS:%b",
1628 		    dp->name, status, MII_STATUS_BITS));
1629 
1630 		if (dp->mii_status & MII_STATUS_XSTATUS) {
1631 			cmn_err(CE_CONT,
1632 			    "! MII_1000TC reg:%b, MII_1000TS reg:%b",
1633 			    ctl1000, MII_1000TC_BITS,
1634 			    stat1000, MII_1000TS_BITS);
1635 		}
1636 
1637 		if (usbgem_population(lpable) <= 1 &&
1638 		    (exp & MII_AN_EXP_LPCANAN) == 0) {
1639 			if ((advert & MII_ABILITY_TECH) != lpable) {
1640 				cmn_err(CE_WARN,
1641 				    "!%s: but the link partner doesn't seem"
1642 				    " to have auto-negotiation capability."
1643 				    " please check the link configuration.",
1644 				    dp->name);
1645 			}
1646 			/*
1647 			 * it should be a result of pararell detection,
1648 			 * which cannot detect duplex mode.
1649 			 */
1650 			if ((advert & lpable) == 0 &&
1651 			    lpable & MII_ABILITY_10BASE_T) {
1652 				/* no common technology, try 10M half mode */
1653 				lpable |= advert & MII_ABILITY_10BASE_T;
1654 				fix_phy = B_TRUE;
1655 			}
1656 		} else if (lpable == 0) {
1657 			cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
1658 			goto reset_phy;
1659 		}
1660 		/*
1661 		 * configure current link mode according to AN priority.
1662 		 */
1663 		val = advert & lpable;
1664 		if ((ctl1000 & MII_1000TC_ADV_FULL) &&
1665 		    (stat1000 & MII_1000TS_LP_FULL)) {
1666 			/* 1000BaseT & full duplex */
1667 			dp->speed = USBGEM_SPD_1000;
1668 			dp->full_duplex = B_TRUE;
1669 		} else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
1670 		    (stat1000 & MII_1000TS_LP_HALF)) {
1671 			/* 1000BaseT & half duplex */
1672 			dp->speed = USBGEM_SPD_1000;
1673 			dp->full_duplex = B_FALSE;
1674 		} else if ((val & MII_ABILITY_100BASE_TX_FD)) {
1675 			/* 100BaseTx & fullduplex */
1676 			dp->speed = USBGEM_SPD_100;
1677 			dp->full_duplex = B_TRUE;
1678 		} else if ((val & MII_ABILITY_100BASE_T4)) {
1679 			/* 100BaseTx & fullduplex */
1680 			dp->speed = USBGEM_SPD_100;
1681 			dp->full_duplex = B_TRUE;
1682 		} else if ((val & MII_ABILITY_100BASE_TX)) {
1683 			/* 100BaseTx & half duplex */
1684 			dp->speed = USBGEM_SPD_100;
1685 			dp->full_duplex = B_FALSE;
1686 		} else if ((val & MII_ABILITY_10BASE_T_FD)) {
1687 			/* 10BaseT & full duplex */
1688 			dp->speed = USBGEM_SPD_10;
1689 			dp->full_duplex = B_TRUE;
1690 		} else if ((val & MII_ABILITY_10BASE_T)) {
1691 			/* 10BaseT & half duplex */
1692 			dp->speed = USBGEM_SPD_10;
1693 			dp->full_duplex = B_FALSE;
1694 		} else {
1695 			/*
1696 			 * the link partner doesn't seem to have
1697 			 * auto-negotiation capability and our PHY
1698 			 * could not report current mode correctly.
1699 			 * We guess current mode by mii_control register.
1700 			 */
1701 			val = usbgem_mii_read(dp, MII_CONTROL, &err);
1702 			if (err != USB_SUCCESS) {
1703 				goto usberr;
1704 			}
1705 
1706 			/* select 100m half or 10m half */
1707 			dp->speed = (val & MII_CONTROL_100MB) ?
1708 			    USBGEM_SPD_100 : USBGEM_SPD_10;
1709 			dp->full_duplex = B_FALSE;
1710 			fix_phy = B_TRUE;
1711 
1712 			cmn_err(CE_NOTE,
1713 			    "!%s: auto-negotiation done but "
1714 			    "common ability not found.\n"
1715 			    "PHY state: control:%b advert:%b lpable:%b\n"
1716 			    "guessing %d Mbps %s duplex mode",
1717 			    dp->name,
1718 			    val, MII_CONTROL_BITS,
1719 			    advert, MII_ABILITY_BITS,
1720 			    lpable, MII_ABILITY_BITS,
1721 			    usbgem_speed_value[dp->speed],
1722 			    dp->full_duplex ? "full" : "half");
1723 		}
1724 
1725 		if (dp->full_duplex) {
1726 			dp->flow_control =
1727 			    usbgem_fc_result[fc_cap_decode(advert)]
1728 			    [fc_cap_decode(lpable)];
1729 		} else {
1730 			dp->flow_control = FLOW_CONTROL_NONE;
1731 		}
1732 		dp->mii_state = MII_STATE_MEDIA_SETUP;
1733 		dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1734 		goto next_nowait;
1735 
1736 	case MII_STATE_MEDIA_SETUP:
1737 		DPRINTF(2, (CE_CONT, "!%s: setup midia mode", dp->name));
1738 
1739 		/* assume the link state is down */
1740 		dp->mii_state = MII_STATE_LINKDOWN;
1741 		dp->mii_supress_msg = B_FALSE;
1742 
1743 		/* use short interval */
1744 		dp->mii_interval = WATCH_INTERVAL_FAST;
1745 
1746 		if ((!dp->anadv_autoneg) ||
1747 		    dp->ugc.usbgc_mii_an_oneshot || fix_phy) {
1748 
1749 			/*
1750 			 * write the result of auto negotiation back.
1751 			 */
1752 			val = usbgem_mii_read(dp, MII_CONTROL, &err);
1753 			if (err != USB_SUCCESS) {
1754 				goto usberr;
1755 			}
1756 			val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
1757 			    MII_CONTROL_ANE   | MII_CONTROL_RSAN);
1758 
1759 			if (dp->full_duplex) {
1760 				val |= MII_CONTROL_FDUPLEX;
1761 			}
1762 
1763 			switch (dp->speed) {
1764 			case USBGEM_SPD_1000:
1765 				val |= MII_CONTROL_1000MB;
1766 				break;
1767 
1768 			case USBGEM_SPD_100:
1769 				val |= MII_CONTROL_100MB;
1770 				break;
1771 
1772 			default:
1773 				cmn_err(CE_WARN, "%s: unknown speed:%d",
1774 				    dp->name, dp->speed);
1775 				/* FALLTHROUGH */
1776 
1777 			case USBGEM_SPD_10:
1778 				/* for USBGEM_SPD_10, do nothing */
1779 				break;
1780 			}
1781 
1782 			if (dp->mii_status & MII_STATUS_XSTATUS) {
1783 				usbgem_mii_write(dp,
1784 				    MII_1000TC, MII_1000TC_CFG_EN, &err);
1785 				if (err != USB_SUCCESS) {
1786 					goto usberr;
1787 				}
1788 			}
1789 			usbgem_mii_write(dp, MII_CONTROL, val, &err);
1790 			if (err != USB_SUCCESS) {
1791 				goto usberr;
1792 			}
1793 		}
1794 		/*
1795 		 * XXX -- nic state should be one of
1796 		 * NIC_STATE_DISCONNECTED
1797 		 * NIC_STATE_STOPPED
1798 		 * NIC_STATE_INITIALIZED
1799 		 * NIC_STATE_ONLINE
1800 		 */
1801 		if (dp->nic_state >= NIC_STATE_INITIALIZED) {
1802 			/* notify the result of autonegotiation to mac */
1803 			if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
1804 				goto usberr;
1805 			}
1806 		}
1807 		goto next_nowait;
1808 
1809 	case MII_STATE_LINKDOWN:
1810 		status = usbgem_mii_read(dp, MII_STATUS, &err);
1811 		if (err != USB_SUCCESS) {
1812 			goto usberr;
1813 		}
1814 		if (status & MII_STATUS_LINKUP) {
1815 			/*
1816 			 * Link is going up
1817 			 */
1818 			dp->mii_state = MII_STATE_LINKUP;
1819 			dp->mii_supress_msg = B_FALSE;
1820 
1821 			DPRINTF(0, (CE_CONT,
1822 			    "!%s: link up detected: status:%b",
1823 			    dp->name, status, MII_STATUS_BITS));
1824 
1825 			/*
1826 			 * MII_CONTROL_100MB and  MII_CONTROL_FDUPLEX are
1827 			 * ignored when MII_CONTROL_ANE is set.
1828 			 */
1829 			cmn_err(CE_CONT,
1830 			    "!%s: Link up: %d Mbps %s duplex %s flow control",
1831 			    dp->name,
1832 			    usbgem_speed_value[dp->speed],
1833 			    dp->full_duplex ? "full" : "half",
1834 			    usbgem_fc_type[dp->flow_control]);
1835 
1836 			dp->mii_interval =
1837 			    dp->ugc.usbgc_mii_link_watch_interval;
1838 
1839 			if (dp->ugc.usbgc_mii_hw_link_detection &&
1840 			    dp->nic_state == NIC_STATE_ONLINE) {
1841 				dp->mii_interval = 0;
1842 			}
1843 
1844 			if (dp->nic_state == NIC_STATE_ONLINE) {
1845 				if (dp->mac_state == MAC_STATE_INITIALIZED) {
1846 					(void) usbgem_mac_start(dp);
1847 				}
1848 				tx_sched = B_TRUE;
1849 			}
1850 
1851 			goto next;
1852 		}
1853 
1854 		dp->mii_supress_msg = B_TRUE;
1855 		if (dp->anadv_autoneg) {
1856 			dp->mii_timer -= diff;
1857 			if (dp->mii_timer <= 0) {
1858 				/*
1859 				 * the link down timer expired.
1860 				 * need to restart auto-negotiation.
1861 				 */
1862 				linkdown_action =
1863 				    dp->ugc.usbgc_mii_linkdown_timeout_action;
1864 				goto restart_autonego;
1865 			}
1866 		}
1867 		/* don't change mii_state */
1868 		goto next;
1869 
1870 	case MII_STATE_LINKUP:
1871 		if (rwlock == RW_READER) {
1872 			/* first pass, read mii status */
1873 			status = usbgem_mii_read(dp, MII_STATUS, &err);
1874 			if (err != USB_SUCCESS) {
1875 				goto usberr;
1876 			}
1877 		}
1878 		if ((status & MII_STATUS_LINKUP) == 0) {
1879 			/*
1880 			 * Link is going down
1881 			 */
1882 			cmn_err(CE_NOTE,
1883 			    "!%s: link down detected: status:%b",
1884 			    dp->name, status, MII_STATUS_BITS);
1885 			/*
1886 			 * Acquire exclusive lock to change mii_state
1887 			 */
1888 			if (rwlock == RW_READER) {
1889 				rwlock = RW_WRITER;
1890 				rw_exit(&dp->dev_state_lock);
1891 				goto again;
1892 			}
1893 
1894 			dp->mii_state = MII_STATE_LINKDOWN;
1895 			dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1896 
1897 			/*
1898 			 * As we may change the state of the device,
1899 			 * let us acquire exclusive lock for the state.
1900 			 */
1901 			if (dp->nic_state == NIC_STATE_ONLINE &&
1902 			    dp->mac_state == MAC_STATE_ONLINE &&
1903 			    dp->ugc.usbgc_mii_stop_mac_on_linkdown) {
1904 				(void) usbgem_restart_nic(dp);
1905 				/* drain tx */
1906 				tx_sched = B_TRUE;
1907 			}
1908 
1909 			if (dp->anadv_autoneg) {
1910 				/* need to restart auto-negotiation */
1911 				linkdown_action =
1912 				    dp->ugc.usbgc_mii_linkdown_action;
1913 				goto restart_autonego;
1914 			}
1915 			/*
1916 			 * don't use hw link down detection until the link
1917 			 * status become stable for a while.
1918 			 */
1919 			dp->mii_interval =
1920 			    dp->ugc.usbgc_mii_link_watch_interval;
1921 
1922 			goto next;
1923 		}
1924 
1925 		/*
1926 		 * still link up, no need to change mii_state
1927 		 */
1928 		if (dp->ugc.usbgc_mii_hw_link_detection &&
1929 		    dp->nic_state == NIC_STATE_ONLINE) {
1930 			/*
1931 			 * no need to check link status periodicly
1932 			 * if nic can generate interrupts when link go down.
1933 			 */
1934 			dp->mii_interval = 0;
1935 		}
1936 		goto next;
1937 	}
1938 	/* NOTREACHED */
1939 	cmn_err(CE_PANIC, "!%s: %s: not reached", dp->name, __func__);
1940 
1941 	/*
1942 	 * Actions for new state.
1943 	 */
1944 restart_autonego:
1945 	switch (linkdown_action) {
1946 	case MII_ACTION_RESET:
1947 		if (!dp->mii_supress_msg) {
1948 			cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
1949 		}
1950 		dp->mii_supress_msg = B_TRUE;
1951 		goto reset_phy;
1952 
1953 	case MII_ACTION_NONE:
1954 		dp->mii_supress_msg = B_TRUE;
1955 		if (dp->ugc.usbgc_mii_an_oneshot) {
1956 			goto autonego;
1957 		}
1958 		/* PHY will restart autonego automatically */
1959 		dp->mii_state = MII_STATE_AUTONEGOTIATING;
1960 		dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
1961 		dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1962 		goto next;
1963 
1964 	case MII_ACTION_RSA:
1965 		if (!dp->mii_supress_msg) {
1966 			cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
1967 			    dp->name);
1968 		}
1969 		dp->mii_supress_msg = B_TRUE;
1970 		goto autonego;
1971 
1972 	default:
1973 		cmn_err(CE_PANIC, "!%s: unknowm linkdown action: %d",
1974 		    dp->name, dp->ugc.usbgc_mii_linkdown_action);
1975 	}
1976 	/* NOTREACHED */
1977 
1978 reset_phy:
1979 	if (!dp->mii_supress_msg) {
1980 		cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
1981 	}
1982 	dp->mii_state = MII_STATE_RESETTING;
1983 	dp->mii_timer = dp->ugc.usbgc_mii_reset_timeout;
1984 	if (!dp->ugc.usbgc_mii_dont_reset) {
1985 		usbgem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET, &err);
1986 		if (err != USB_SUCCESS) {
1987 			goto usberr;
1988 		}
1989 	}
1990 	dp->mii_interval = WATCH_INTERVAL_FAST;
1991 	goto next;
1992 
1993 autonego:
1994 	if (!dp->mii_supress_msg) {
1995 		cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
1996 	}
1997 	dp->mii_state = MII_STATE_AUTONEGOTIATING;
1998 	dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
1999 
2000 	/* start/restart autoneg */
2001 	val = usbgem_mii_read(dp, MII_CONTROL, &err) &
2002 	    ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
2003 	if (err != USB_SUCCESS) {
2004 		goto usberr;
2005 	}
2006 	if (val & MII_CONTROL_ANE) {
2007 		val |= MII_CONTROL_RSAN;
2008 	}
2009 	usbgem_mii_write(dp, MII_CONTROL,
2010 	    val | dp->ugc.usbgc_mii_an_cmd | MII_CONTROL_ANE, &err);
2011 	if (err != USB_SUCCESS) {
2012 		goto usberr;
2013 	}
2014 
2015 	dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2016 	goto next;
2017 
2018 usberr:
2019 	dp->mii_state = MII_STATE_UNKNOWN;
2020 	dp->mii_interval = dp->ugc.usbgc_mii_link_watch_interval;
2021 	tx_sched = B_TRUE;
2022 
2023 next:
2024 	*newstatep = dp->mii_state;
2025 	rw_exit(&dp->dev_state_lock);
2026 	return (tx_sched);
2027 }
2028 
2029 static void
usbgem_mii_link_watcher(struct usbgem_dev * dp)2030 usbgem_mii_link_watcher(struct usbgem_dev *dp)
2031 {
2032 	int		old_mii_state;
2033 	int		new_mii_state;
2034 	boolean_t	tx_sched;
2035 
2036 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2037 
2038 	for (; ; ) {
2039 
2040 		mutex_enter(&dp->link_watcher_lock);
2041 		if (dp->mii_interval) {
2042 			(void) cv_timedwait(&dp->link_watcher_wait_cv,
2043 			    &dp->link_watcher_lock,
2044 			    dp->mii_interval + ddi_get_lbolt());
2045 		} else {
2046 			cv_wait(&dp->link_watcher_wait_cv,
2047 			    &dp->link_watcher_lock);
2048 		}
2049 		mutex_exit(&dp->link_watcher_lock);
2050 
2051 		if (dp->link_watcher_stop) {
2052 			break;
2053 		}
2054 
2055 		/* we block callbacks from disconnect/suspend and restart */
2056 		tx_sched = usbgem_mii_link_check(dp,
2057 		    &old_mii_state, &new_mii_state);
2058 
2059 		/*
2060 		 * gld v2 notifier functions are not able to
2061 		 * be called with any locks in this layer.
2062 		 */
2063 		if (tx_sched) {
2064 			/* kick potentially stopped downstream */
2065 			mac_tx_update(dp->mh);
2066 		}
2067 
2068 		if (old_mii_state != new_mii_state) {
2069 			/* notify new mii link state */
2070 			if (new_mii_state == MII_STATE_LINKUP) {
2071 				dp->linkup_delay = 0;
2072 				USBGEM_LINKUP(dp);
2073 			} else if (dp->linkup_delay <= 0) {
2074 				USBGEM_LINKDOWN(dp);
2075 			}
2076 		} else if (dp->linkup_delay < 0) {
2077 			/* first linkup timeout */
2078 			dp->linkup_delay = 0;
2079 			USBGEM_LINKDOWN(dp);
2080 		}
2081 	}
2082 
2083 	thread_exit();
2084 }
2085 
2086 void
usbgem_mii_update_link(struct usbgem_dev * dp)2087 usbgem_mii_update_link(struct usbgem_dev *dp)
2088 {
2089 	cv_signal(&dp->link_watcher_wait_cv);
2090 }
2091 
2092 int
usbgem_mii_probe_default(struct usbgem_dev * dp)2093 usbgem_mii_probe_default(struct usbgem_dev *dp)
2094 {
2095 	int		phy;
2096 	uint16_t	status;
2097 	uint16_t	xstatus;
2098 	int		err;
2099 	uint16_t	adv;
2100 	uint16_t	adv_org;
2101 
2102 	DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2103 
2104 	/*
2105 	 * Scan PHY
2106 	 */
2107 	dp->mii_status = 0;
2108 
2109 	/* Try default phy first */
2110 	if (dp->mii_phy_addr) {
2111 		status = usbgem_mii_read(dp, MII_STATUS, &err);
2112 		if (err != USB_SUCCESS) {
2113 			goto usberr;
2114 		}
2115 		if (status != 0xffff && status != 0x0000) {
2116 			goto PHY_found;
2117 		}
2118 
2119 		if (dp->mii_phy_addr < 0) {
2120 			cmn_err(CE_NOTE,
2121 		    "!%s: failed to probe default internal and/or non-MII PHY",
2122 			    dp->name);
2123 			return (USB_FAILURE);
2124 		}
2125 
2126 		cmn_err(CE_NOTE,
2127 		    "!%s: failed to probe default MII PHY at %d",
2128 		    dp->name, dp->mii_phy_addr);
2129 	}
2130 
2131 	/* Try all possible address */
2132 	for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2133 		dp->mii_phy_addr = phy;
2134 		status = usbgem_mii_read(dp, MII_STATUS, &err);
2135 		if (err != USB_SUCCESS) {
2136 			DPRINTF(0, (CE_CONT,
2137 			    "!%s: %s: mii_read(status) failed",
2138 			    dp->name, __func__));
2139 			goto usberr;
2140 		}
2141 
2142 		if (status != 0xffff && status != 0x0000) {
2143 			usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2144 			if (err != USB_SUCCESS) {
2145 				DPRINTF(0, (CE_CONT,
2146 				    "!%s: %s: mii_write(control) failed",
2147 				    dp->name, __func__));
2148 				goto usberr;
2149 			}
2150 			goto PHY_found;
2151 		}
2152 	}
2153 	for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2154 		dp->mii_phy_addr = phy;
2155 		usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2156 		if (err != USB_SUCCESS) {
2157 			DPRINTF(0, (CE_CONT,
2158 			    "!%s: %s: mii_write(control) failed",
2159 			    dp->name, __func__));
2160 			goto usberr;
2161 		}
2162 		status = usbgem_mii_read(dp, MII_STATUS, &err);
2163 		if (err != USB_SUCCESS) {
2164 			DPRINTF(0, (CE_CONT,
2165 			    "!%s: %s: mii_read(status) failed",
2166 			    dp->name, __func__));
2167 			goto usberr;
2168 		}
2169 
2170 		if (status != 0xffff && status != 0) {
2171 			goto PHY_found;
2172 		}
2173 	}
2174 
2175 	cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
2176 	return (USB_FAILURE);
2177 
2178 PHY_found:
2179 	dp->mii_status = status;
2180 	dp->mii_status_ro = ~status;
2181 	dp->mii_phy_id = usbgem_mii_read(dp, MII_PHYIDH, &err) << 16;
2182 	if (err != USB_SUCCESS) {
2183 		DPRINTF(0, (CE_CONT,
2184 		    "!%s: %s: mii_read(PHYIDH) failed",
2185 		    dp->name, __func__));
2186 		goto usberr;
2187 	}
2188 	dp->mii_phy_id |= usbgem_mii_read(dp, MII_PHYIDL, &err);
2189 	if (err != USB_SUCCESS) {
2190 		DPRINTF(0, (CE_CONT,
2191 		    "!%s: %s: mii_read(PHYIDL) failed",
2192 		    dp->name, __func__));
2193 		goto usberr;
2194 	}
2195 
2196 	if (dp->mii_phy_addr < 0) {
2197 		cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
2198 		    dp->name, dp->mii_phy_id);
2199 	} else {
2200 		cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
2201 		    dp->name, dp->mii_phy_id, dp->mii_phy_addr);
2202 	}
2203 
2204 	cmn_err(CE_CONT,
2205 	    "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
2206 	    dp->name,
2207 	    usbgem_mii_read(dp, MII_CONTROL, &err), MII_CONTROL_BITS,
2208 	    status, MII_STATUS_BITS,
2209 	    usbgem_mii_read(dp, MII_AN_ADVERT, &err), MII_ABILITY_BITS,
2210 	    usbgem_mii_read(dp, MII_AN_LPABLE, &err), MII_ABILITY_BITS,
2211 	    usbgem_mii_read(dp, MII_AN_EXPANSION, &err), MII_AN_EXP_BITS);
2212 
2213 	dp->mii_xstatus = 0;
2214 	if (status & MII_STATUS_XSTATUS) {
2215 		dp->mii_xstatus = usbgem_mii_read(dp, MII_XSTATUS, &err);
2216 
2217 		cmn_err(CE_CONT, "!%s: xstatus:%b",
2218 		    dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
2219 	}
2220 	dp->mii_xstatus_ro = ~dp->mii_xstatus;
2221 
2222 	/* check if the phy can advertize pause abilities */
2223 	adv_org = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2224 	if (err != USB_SUCCESS) {
2225 		goto usberr;
2226 	}
2227 
2228 	usbgem_mii_write(dp, MII_AN_ADVERT,
2229 	    MII_ABILITY_PAUSE | MII_ABILITY_ASM_DIR, &err);
2230 	if (err != USB_SUCCESS) {
2231 		goto usberr;
2232 	}
2233 
2234 	adv = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2235 	if (err != USB_SUCCESS) {
2236 		goto usberr;
2237 	}
2238 
2239 	if ((adv & MII_ABILITY_PAUSE) == 0) {
2240 		dp->ugc.usbgc_flow_control &= ~1;
2241 	}
2242 
2243 	if ((adv & MII_ABILITY_ASM_DIR) == 0) {
2244 		dp->ugc.usbgc_flow_control &= ~2;
2245 	}
2246 
2247 	usbgem_mii_write(dp, MII_AN_ADVERT, adv_org, &err);
2248 	if (err != USB_SUCCESS) {
2249 		goto usberr;
2250 	}
2251 	return (USB_SUCCESS);
2252 
2253 usberr:
2254 	return (USB_FAILURE);
2255 }
2256 
2257 int
usbgem_mii_init_default(struct usbgem_dev * dp)2258 usbgem_mii_init_default(struct usbgem_dev *dp)
2259 {
2260 	/* ENPTY */
2261 	return (USB_SUCCESS);
2262 }
2263 
2264 static int
usbgem_mii_start(struct usbgem_dev * dp)2265 usbgem_mii_start(struct usbgem_dev *dp)
2266 {
2267 	int	err;
2268 	kthread_t	*lwth;
2269 
2270 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2271 
2272 	/* make a first call of usbgem_mii_link_check() */
2273 	dp->link_watcher_stop = 0;
2274 	dp->mii_state = MII_STATE_UNKNOWN;
2275 	dp->mii_interval = drv_usectohz(1000*1000); /* 1sec */
2276 	dp->mii_last_check = ddi_get_lbolt();
2277 	dp->linkup_delay = 600 * drv_usectohz(1000*1000); /* 10 minutes */
2278 
2279 	lwth = thread_create(NULL, 0, usbgem_mii_link_watcher, dp, 0, &p0,
2280 	    TS_RUN, minclsyspri);
2281 	if (lwth == NULL) {
2282 		cmn_err(CE_WARN,
2283 		    "!%s: %s: failed to create a link watcher thread",
2284 		    dp->name, __func__);
2285 		return (USB_FAILURE);
2286 	}
2287 	dp->link_watcher_did = lwth->t_did;
2288 
2289 	return (USB_SUCCESS);
2290 }
2291 
2292 static void
usbgem_mii_stop(struct usbgem_dev * dp)2293 usbgem_mii_stop(struct usbgem_dev *dp)
2294 {
2295 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2296 
2297 	/* Ensure timer routine stopped */
2298 	dp->link_watcher_stop = 1;
2299 	cv_signal(&dp->link_watcher_wait_cv);
2300 	thread_join(dp->link_watcher_did);
2301 }
2302 
2303 /* ============================================================== */
2304 /*
2305  * internal mac register operation interface
2306  */
2307 /* ============================================================== */
2308 /*
2309  * usbgem_mac_init: cold start
2310  */
2311 static int
usbgem_mac_init(struct usbgem_dev * dp)2312 usbgem_mac_init(struct usbgem_dev *dp)
2313 {
2314 	int	err;
2315 
2316 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2317 
2318 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2319 		/* pretend we succeeded */
2320 		return (USB_SUCCESS);
2321 	}
2322 
2323 	ASSERT(dp->mac_state == MAC_STATE_STOPPED);
2324 
2325 	/* reset fatal error timestamp */
2326 	dp->fatal_error = (clock_t)0;
2327 
2328 	/* reset tx side state */
2329 	mutex_enter(&dp->txlock);
2330 	dp->tx_busy_cnt = 0;
2331 	dp->tx_max_packets = dp->ugc.usbgc_tx_list_max;
2332 	mutex_exit(&dp->txlock);
2333 
2334 	/* reset rx side state */
2335 	mutex_enter(&dp->rxlock);
2336 	dp->rx_busy_cnt = 0;
2337 	mutex_exit(&dp->rxlock);
2338 
2339 	err = usbgem_hal_init_chip(dp);
2340 	if (err == USB_SUCCESS) {
2341 		dp->mac_state = MAC_STATE_INITIALIZED;
2342 	}
2343 
2344 	return (err);
2345 }
2346 
2347 /*
2348  * usbgem_mac_start: warm start
2349  */
2350 static int
usbgem_mac_start(struct usbgem_dev * dp)2351 usbgem_mac_start(struct usbgem_dev *dp)
2352 {
2353 	int	err;
2354 	int	i;
2355 	usb_flags_t	flags = 0;
2356 	usb_intr_req_t	*req;
2357 #ifdef USBGEM_DEBUG_LEVEL
2358 	usb_pipe_state_t	p_state;
2359 #endif
2360 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2361 
2362 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2363 		/* do nothing but don't return failure */
2364 		return (USB_SUCCESS);
2365 	}
2366 
2367 	if (dp->mac_state != MAC_STATE_INITIALIZED) {
2368 		/* don't return failer */
2369 		DPRINTF(0, (CE_CONT,
2370 		    "!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
2371 		    dp->name, __func__, dp->mac_state));
2372 		goto x;
2373 	}
2374 
2375 	dp->mac_state = MAC_STATE_ONLINE;
2376 
2377 	if (usbgem_hal_start_chip(dp) != USB_SUCCESS) {
2378 		cmn_err(CE_NOTE,
2379 		    "!%s: %s: usb error was detected during start_chip",
2380 		    dp->name, __func__);
2381 		goto x;
2382 	}
2383 
2384 #ifdef USBGEM_DEBUG_LEVEL
2385 	usb_pipe_get_state(dp->intr_pipe, &p_state, 0);
2386 	ASSERT(p_state == USB_PIPE_STATE_IDLE);
2387 #endif /* USBGEM_DEBUG_LEVEL */
2388 
2389 	if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2390 
2391 		/* make a request for interrupt */
2392 
2393 		req = usb_alloc_intr_req(dp->dip, 0, USB_FLAGS_SLEEP);
2394 		if (req == NULL) {
2395 			cmn_err(CE_WARN, "!%s: %s: failed to allocate intreq",
2396 			    dp->name, __func__);
2397 			goto x;
2398 		}
2399 		req->intr_data = NULL;
2400 		req->intr_client_private = (usb_opaque_t)dp;
2401 		req->intr_timeout = 0;
2402 		req->intr_attributes =
2403 		    USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
2404 		req->intr_len = dp->ep_intr->wMaxPacketSize;
2405 		req->intr_cb = usbgem_intr_cb;
2406 		req->intr_exc_cb = usbgem_intr_cb;
2407 		req->intr_completion_reason = 0;
2408 		req->intr_cb_flags = 0;
2409 
2410 		err = usb_pipe_intr_xfer(dp->intr_pipe, req, flags);
2411 		if (err != USB_SUCCESS) {
2412 			cmn_err(CE_WARN,
2413 			    "%s: err:%d failed to start polling of intr pipe",
2414 			    dp->name, err);
2415 			goto x;
2416 		}
2417 	}
2418 
2419 	/* kick to receive the first packet */
2420 	if (usbgem_init_rx_buf(dp) != USB_SUCCESS) {
2421 		goto err_stop_intr;
2422 	}
2423 	dp->rx_active = B_TRUE;
2424 
2425 	return (USB_SUCCESS);
2426 
2427 err_stop_intr:
2428 	/* stop the interrupt pipe */
2429 	DPRINTF(0, (CE_CONT, "!%s: %s: FAULURE", dp->name, __func__));
2430 	if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2431 		usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2432 	}
2433 x:
2434 	ASSERT(dp->mac_state == MAC_STATE_ONLINE);
2435 	/* we use another flag to indicate error state. */
2436 	if (dp->fatal_error == (clock_t)0) {
2437 		dp->fatal_error = usbgem_timestamp_nz();
2438 	}
2439 	return (USB_FAILURE);
2440 }
2441 
2442 static int
usbgem_mac_stop(struct usbgem_dev * dp,int new_state,boolean_t graceful)2443 usbgem_mac_stop(struct usbgem_dev *dp, int new_state, boolean_t graceful)
2444 {
2445 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2446 
2447 	/*
2448 	 * we must have writer lock for dev_state_lock
2449 	 */
2450 	ASSERT(new_state == MAC_STATE_STOPPED ||
2451 	    new_state == MAC_STATE_DISCONNECTED);
2452 
2453 	/* stop polling interrupt pipe */
2454 	if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2455 		usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2456 	}
2457 
2458 	if (new_state == MAC_STATE_STOPPED || graceful) {
2459 		/* stop the nic hardware completely */
2460 		if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
2461 			(void) usbgem_hal_reset_chip(dp);
2462 		}
2463 	}
2464 
2465 	/* stop preparing new rx packets and sending new packets */
2466 	dp->mac_state = new_state;
2467 
2468 	/* other processors must get mac_state correctly after here */
2469 	membar_producer();
2470 
2471 	/* cancel all requests we have sent */
2472 	usb_pipe_reset(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
2473 	usb_pipe_reset(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
2474 
2475 	DPRINTF(0, (CE_CONT,
2476 	    "!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
2477 	    dp->name, __func__, dp->rx_busy_cnt, dp->tx_busy_cnt));
2478 
2479 	/*
2480 	 * Here all rx packets has been cancelled and their call back
2481 	 * function has been exeuted, because we called usb_pipe_reset
2482 	 * synchronously.
2483 	 * So actually we just ensure rx_busy_cnt == 0.
2484 	 */
2485 	mutex_enter(&dp->rxlock);
2486 	while (dp->rx_busy_cnt > 0) {
2487 		cv_wait(&dp->rx_drain_cv, &dp->rxlock);
2488 	}
2489 	mutex_exit(&dp->rxlock);
2490 
2491 	DPRINTF(0, (CE_CONT, "!%s: %s: rx_busy_cnt is %d now",
2492 	    dp->name, __func__, dp->rx_busy_cnt));
2493 
2494 	mutex_enter(&dp->txlock);
2495 	while (dp->tx_busy_cnt > 0) {
2496 		cv_wait(&dp->tx_drain_cv, &dp->txlock);
2497 	}
2498 	mutex_exit(&dp->txlock);
2499 
2500 	DPRINTF(0, (CE_CONT, "!%s: %s: tx_busy_cnt is %d now",
2501 	    dp->name, __func__, dp->tx_busy_cnt));
2502 
2503 	return (USB_SUCCESS);
2504 }
2505 
2506 static int
usbgem_add_multicast(struct usbgem_dev * dp,const uint8_t * ep)2507 usbgem_add_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2508 {
2509 	int	cnt;
2510 	int	err;
2511 
2512 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2513 
2514 	sema_p(&dp->rxfilter_lock);
2515 	if (dp->mc_count_req++ < USBGEM_MAXMC) {
2516 		/* append the new address at the end of the mclist */
2517 		cnt = dp->mc_count;
2518 		bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
2519 		    ETHERADDRL);
2520 		if (dp->ugc.usbgc_multicast_hash) {
2521 			dp->mc_list[cnt].hash =
2522 			    (*dp->ugc.usbgc_multicast_hash)(dp, ep);
2523 		}
2524 		dp->mc_count = cnt + 1;
2525 	}
2526 
2527 	if (dp->mc_count_req != dp->mc_count) {
2528 		/* multicast address list overflow */
2529 		dp->rxmode |= RXMODE_MULTI_OVF;
2530 	} else {
2531 		dp->rxmode &= ~RXMODE_MULTI_OVF;
2532 	}
2533 
2534 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2535 		/* tell new multicast list to the hardware */
2536 		err = usbgem_hal_set_rx_filter(dp);
2537 	}
2538 	sema_v(&dp->rxfilter_lock);
2539 
2540 	return (err);
2541 }
2542 
2543 static int
usbgem_remove_multicast(struct usbgem_dev * dp,const uint8_t * ep)2544 usbgem_remove_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2545 {
2546 	size_t		len;
2547 	int		i;
2548 	int		cnt;
2549 	int		err;
2550 
2551 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2552 
2553 	sema_p(&dp->rxfilter_lock);
2554 	dp->mc_count_req--;
2555 	cnt = dp->mc_count;
2556 	for (i = 0; i < cnt; i++) {
2557 		if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
2558 			continue;
2559 		}
2560 		/* shrink the mclist by copying forward */
2561 		len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
2562 		if (len > 0) {
2563 			bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
2564 		}
2565 		dp->mc_count--;
2566 		break;
2567 	}
2568 
2569 	if (dp->mc_count_req != dp->mc_count) {
2570 		/* multicast address list overflow */
2571 		dp->rxmode |= RXMODE_MULTI_OVF;
2572 	} else {
2573 		dp->rxmode &= ~RXMODE_MULTI_OVF;
2574 	}
2575 
2576 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2577 		err = usbgem_hal_set_rx_filter(dp);
2578 	}
2579 	sema_v(&dp->rxfilter_lock);
2580 
2581 	return (err);
2582 }
2583 
2584 
2585 /* ============================================================== */
2586 /*
2587  * ioctl
2588  */
2589 /* ============================================================== */
2590 enum ioc_reply {
2591 	IOC_INVAL = -1,				/* bad, NAK with EINVAL	*/
2592 	IOC_DONE,				/* OK, reply sent	*/
2593 	IOC_ACK,				/* OK, just send ACK	*/
2594 	IOC_REPLY,				/* OK, just send reply	*/
2595 	IOC_RESTART_ACK,			/* OK, restart & ACK	*/
2596 	IOC_RESTART_REPLY			/* OK, restart & reply	*/
2597 };
2598 
2599 
2600 #ifdef USBGEM_CONFIG_MAC_PROP
2601 static int
usbgem_get_def_val(struct usbgem_dev * dp,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)2602 usbgem_get_def_val(struct usbgem_dev *dp, mac_prop_id_t pr_num,
2603     uint_t pr_valsize, void *pr_val)
2604 {
2605 	link_flowctrl_t fl;
2606 	int err = 0;
2607 
2608 	ASSERT(pr_valsize > 0);
2609 	switch (pr_num) {
2610 	case MAC_PROP_AUTONEG:
2611 		*(uint8_t *)pr_val =
2612 		    BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
2613 		break;
2614 
2615 	case MAC_PROP_FLOWCTRL:
2616 		if (pr_valsize < sizeof (link_flowctrl_t)) {
2617 			return (EINVAL);
2618 		}
2619 		switch (dp->ugc.usbgc_flow_control) {
2620 		case FLOW_CONTROL_NONE:
2621 			fl = LINK_FLOWCTRL_NONE;
2622 			break;
2623 		case FLOW_CONTROL_SYMMETRIC:
2624 			fl = LINK_FLOWCTRL_BI;
2625 			break;
2626 		case FLOW_CONTROL_TX_PAUSE:
2627 			fl = LINK_FLOWCTRL_TX;
2628 			break;
2629 		case FLOW_CONTROL_RX_PAUSE:
2630 			fl = LINK_FLOWCTRL_RX;
2631 			break;
2632 		}
2633 		bcopy(&fl, pr_val, sizeof (fl));
2634 		break;
2635 
2636 	case MAC_PROP_ADV_1000FDX_CAP:
2637 	case MAC_PROP_EN_1000FDX_CAP:
2638 		*(uint8_t *)pr_val =
2639 		    (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
2640 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
2641 		break;
2642 
2643 	case MAC_PROP_ADV_1000HDX_CAP:
2644 	case MAC_PROP_EN_1000HDX_CAP:
2645 		*(uint8_t *)pr_val =
2646 		    (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
2647 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
2648 		break;
2649 
2650 	case MAC_PROP_ADV_100T4_CAP:
2651 	case MAC_PROP_EN_100T4_CAP:
2652 		*(uint8_t *)pr_val =
2653 		    BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
2654 		break;
2655 
2656 	case MAC_PROP_ADV_100FDX_CAP:
2657 	case MAC_PROP_EN_100FDX_CAP:
2658 		*(uint8_t *)pr_val =
2659 		    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
2660 		break;
2661 
2662 	case MAC_PROP_ADV_100HDX_CAP:
2663 	case MAC_PROP_EN_100HDX_CAP:
2664 		*(uint8_t *)pr_val =
2665 		    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
2666 		break;
2667 
2668 	case MAC_PROP_ADV_10FDX_CAP:
2669 	case MAC_PROP_EN_10FDX_CAP:
2670 		*(uint8_t *)pr_val =
2671 		    BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
2672 		break;
2673 
2674 	case MAC_PROP_ADV_10HDX_CAP:
2675 	case MAC_PROP_EN_10HDX_CAP:
2676 		*(uint8_t *)pr_val =
2677 		    BOOLEAN(dp->mii_status & MII_STATUS_10);
2678 		break;
2679 
2680 	default:
2681 		err = ENOTSUP;
2682 		break;
2683 	}
2684 	return (err);
2685 }
2686 
2687 static void
usbgem_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)2688 usbgem_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2689     mac_prop_info_handle_t prh)
2690 {
2691 	struct usbgem_dev *dp = arg;
2692 	link_flowctrl_t fl;
2693 
2694 	/*
2695 	 * By default permissions are read/write unless specified
2696 	 * otherwise by the driver.
2697 	 */
2698 
2699 	switch (pr_num) {
2700 	case MAC_PROP_DUPLEX:
2701 	case MAC_PROP_SPEED:
2702 	case MAC_PROP_STATUS:
2703 	case MAC_PROP_ADV_1000FDX_CAP:
2704 	case MAC_PROP_ADV_1000HDX_CAP:
2705 	case MAC_PROP_ADV_100FDX_CAP:
2706 	case MAC_PROP_ADV_100HDX_CAP:
2707 	case MAC_PROP_ADV_10FDX_CAP:
2708 	case MAC_PROP_ADV_10HDX_CAP:
2709 	case MAC_PROP_ADV_100T4_CAP:
2710 	case MAC_PROP_EN_100T4_CAP:
2711 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2712 		break;
2713 
2714 	case MAC_PROP_EN_1000FDX_CAP:
2715 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0) {
2716 			mac_prop_info_set_default_uint8(prh,
2717 			    BOOLEAN(
2718 			    dp->mii_xstatus & MII_XSTATUS_1000BASET_FD));
2719 		} else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)
2720 		    == 0) {
2721 			mac_prop_info_set_default_uint8(prh,
2722 			    BOOLEAN(
2723 			    dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD));
2724 		} else {
2725 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2726 		}
2727 		break;
2728 
2729 	case MAC_PROP_EN_1000HDX_CAP:
2730 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0) {
2731 			mac_prop_info_set_default_uint8(prh,
2732 			    BOOLEAN(
2733 			    dp->mii_xstatus & MII_XSTATUS_1000BASET));
2734 		} else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2735 			mac_prop_info_set_default_uint8(prh,
2736 			    BOOLEAN(
2737 			    dp->mii_xstatus & MII_XSTATUS_1000BASEX));
2738 		} else {
2739 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2740 		}
2741 		break;
2742 
2743 	case MAC_PROP_EN_100FDX_CAP:
2744 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2745 			mac_prop_info_set_default_uint8(prh,
2746 			    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD));
2747 		} else {
2748 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2749 		}
2750 		break;
2751 
2752 	case MAC_PROP_EN_100HDX_CAP:
2753 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2754 			mac_prop_info_set_default_uint8(prh,
2755 			    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX));
2756 		} else {
2757 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2758 		}
2759 		break;
2760 
2761 	case MAC_PROP_EN_10FDX_CAP:
2762 		if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2763 			mac_prop_info_set_default_uint8(prh,
2764 			    BOOLEAN(dp->mii_status & MII_STATUS_10_FD));
2765 		} else {
2766 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2767 		}
2768 		break;
2769 
2770 	case MAC_PROP_EN_10HDX_CAP:
2771 		if ((dp->mii_status_ro & MII_STATUS_10) == 0) {
2772 			mac_prop_info_set_default_uint8(prh,
2773 			    BOOLEAN(dp->mii_status & MII_STATUS_10));
2774 		} else {
2775 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2776 		}
2777 		break;
2778 
2779 	case MAC_PROP_AUTONEG:
2780 		if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2781 			mac_prop_info_set_default_uint8(prh,
2782 			    BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG));
2783 		} else {
2784 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2785 		}
2786 		break;
2787 
2788 	case MAC_PROP_FLOWCTRL:
2789 		switch (dp->ugc.usbgc_flow_control) {
2790 		case FLOW_CONTROL_NONE:
2791 			fl = LINK_FLOWCTRL_NONE;
2792 			break;
2793 		case FLOW_CONTROL_SYMMETRIC:
2794 			fl = LINK_FLOWCTRL_BI;
2795 			break;
2796 		case FLOW_CONTROL_TX_PAUSE:
2797 			fl = LINK_FLOWCTRL_TX;
2798 			break;
2799 		case FLOW_CONTROL_RX_PAUSE:
2800 			fl = LINK_FLOWCTRL_RX;
2801 			break;
2802 		}
2803 		mac_prop_info_set_default_link_flowctrl(prh, fl);
2804 		break;
2805 
2806 	case MAC_PROP_MTU:
2807 		mac_prop_info_set_range_uint32(prh,
2808 		    dp->ugc.usbgc_min_mtu, dp->ugc.usbgc_max_mtu);
2809 		break;
2810 
2811 	case MAC_PROP_PRIVATE:
2812 		break;
2813 	}
2814 }
2815 
2816 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)2817 usbgem_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2818     uint_t pr_valsize, const void *pr_val)
2819 {
2820 	struct usbgem_dev *dp = arg;
2821 	int err = 0;
2822 	boolean_t	update = B_FALSE;
2823 	link_flowctrl_t flowctrl;
2824 	uint32_t cur_mtu, new_mtu;
2825 
2826 	rw_enter(&dp->dev_state_lock, RW_WRITER);
2827 	switch (pr_num) {
2828 	case MAC_PROP_EN_1000FDX_CAP:
2829 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0 ||
2830 		    (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD) == 0) {
2831 			if (dp->anadv_1000fdx != *(uint8_t *)pr_val) {
2832 				dp->anadv_1000fdx = *(uint8_t *)pr_val;
2833 				update = B_TRUE;
2834 			}
2835 		} else {
2836 			err = ENOTSUP;
2837 		}
2838 		break;
2839 
2840 	case MAC_PROP_EN_1000HDX_CAP:
2841 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0 ||
2842 		    (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2843 			if (dp->anadv_1000hdx != *(uint8_t *)pr_val) {
2844 				dp->anadv_1000hdx = *(uint8_t *)pr_val;
2845 				update = B_TRUE;
2846 			}
2847 		} else {
2848 			err = ENOTSUP;
2849 		}
2850 		break;
2851 
2852 	case MAC_PROP_EN_100FDX_CAP:
2853 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2854 			if (dp->anadv_100fdx != *(uint8_t *)pr_val) {
2855 				dp->anadv_100fdx = *(uint8_t *)pr_val;
2856 				update = B_TRUE;
2857 			}
2858 		} else {
2859 			err = ENOTSUP;
2860 		}
2861 		break;
2862 
2863 	case MAC_PROP_EN_100HDX_CAP:
2864 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2865 			if (dp->anadv_100hdx != *(uint8_t *)pr_val) {
2866 				dp->anadv_100hdx = *(uint8_t *)pr_val;
2867 				update = B_TRUE;
2868 			}
2869 		} else {
2870 			err = ENOTSUP;
2871 		}
2872 		break;
2873 
2874 	case MAC_PROP_EN_10FDX_CAP:
2875 		if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2876 			if (dp->anadv_10fdx != *(uint8_t *)pr_val) {
2877 				dp->anadv_10fdx = *(uint8_t *)pr_val;
2878 				update = B_TRUE;
2879 			}
2880 		} else {
2881 			err = ENOTSUP;
2882 		}
2883 		break;
2884 
2885 	case MAC_PROP_EN_10HDX_CAP:
2886 		if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2887 			if (dp->anadv_10hdx != *(uint8_t *)pr_val) {
2888 				dp->anadv_10hdx = *(uint8_t *)pr_val;
2889 				update = B_TRUE;
2890 			}
2891 		} else {
2892 			err = ENOTSUP;
2893 		}
2894 		break;
2895 
2896 	case MAC_PROP_AUTONEG:
2897 		if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2898 			if (dp->anadv_autoneg != *(uint8_t *)pr_val) {
2899 				dp->anadv_autoneg = *(uint8_t *)pr_val;
2900 				update = B_TRUE;
2901 			}
2902 		} else {
2903 			err = ENOTSUP;
2904 		}
2905 		break;
2906 
2907 	case MAC_PROP_FLOWCTRL:
2908 		bcopy(pr_val, &flowctrl, sizeof (flowctrl));
2909 
2910 		switch (flowctrl) {
2911 		default:
2912 			err = EINVAL;
2913 			break;
2914 
2915 		case LINK_FLOWCTRL_NONE:
2916 			if (dp->flow_control != FLOW_CONTROL_NONE) {
2917 				dp->flow_control = FLOW_CONTROL_NONE;
2918 				update = B_TRUE;
2919 			}
2920 			break;
2921 
2922 		case LINK_FLOWCTRL_RX:
2923 			if (dp->flow_control != FLOW_CONTROL_RX_PAUSE) {
2924 				dp->flow_control = FLOW_CONTROL_RX_PAUSE;
2925 				update = B_TRUE;
2926 			}
2927 			break;
2928 
2929 		case LINK_FLOWCTRL_TX:
2930 			if (dp->flow_control != FLOW_CONTROL_TX_PAUSE) {
2931 				dp->flow_control = FLOW_CONTROL_TX_PAUSE;
2932 				update = B_TRUE;
2933 			}
2934 			break;
2935 
2936 		case LINK_FLOWCTRL_BI:
2937 			if (dp->flow_control != FLOW_CONTROL_SYMMETRIC) {
2938 				dp->flow_control = FLOW_CONTROL_SYMMETRIC;
2939 				update = B_TRUE;
2940 			}
2941 			break;
2942 		}
2943 		break;
2944 
2945 	case MAC_PROP_ADV_1000FDX_CAP:
2946 	case MAC_PROP_ADV_1000HDX_CAP:
2947 	case MAC_PROP_ADV_100FDX_CAP:
2948 	case MAC_PROP_ADV_100HDX_CAP:
2949 	case MAC_PROP_ADV_10FDX_CAP:
2950 	case MAC_PROP_ADV_10HDX_CAP:
2951 	case MAC_PROP_STATUS:
2952 	case MAC_PROP_SPEED:
2953 	case MAC_PROP_DUPLEX:
2954 		err = ENOTSUP; /* read-only prop. Can't set this. */
2955 		break;
2956 
2957 	case MAC_PROP_MTU:
2958 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
2959 		if (new_mtu != dp->mtu) {
2960 			err = EINVAL;
2961 		}
2962 		break;
2963 
2964 	case MAC_PROP_PRIVATE:
2965 		err = ENOTSUP;
2966 		break;
2967 
2968 	default:
2969 		err = ENOTSUP;
2970 		break;
2971 	}
2972 
2973 	if (update) {
2974 		/* sync with PHY */
2975 		usbgem_choose_forcedmode(dp);
2976 		dp->mii_state = MII_STATE_UNKNOWN;
2977 		cv_signal(&dp->link_watcher_wait_cv);
2978 	}
2979 	rw_exit(&dp->dev_state_lock);
2980 	return (err);
2981 }
2982 
2983 static int
usbgem_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)2984 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2985     uint_t pr_valsize, void *pr_val)
2986 {
2987 	struct usbgem_dev *dp = arg;
2988 	int err = 0;
2989 	link_flowctrl_t flowctrl;
2990 	uint64_t tmp = 0;
2991 
2992 	if (pr_valsize == 0) {
2993 		return (EINVAL);
2994 	}
2995 
2996 	bzero(pr_val, pr_valsize);
2997 	rw_enter(&dp->dev_state_lock, RW_READER);
2998 	switch (pr_num) {
2999 	case MAC_PROP_DUPLEX:
3000 		if (pr_valsize >= sizeof (link_duplex_t)) {
3001 			if (dp->mii_state != MII_STATE_LINKUP) {
3002 				*(link_duplex_t *)pr_val = LINK_DUPLEX_UNKNOWN;
3003 			} else if (dp->full_duplex) {
3004 				*(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
3005 			} else {
3006 				*(link_duplex_t *)pr_val = LINK_DUPLEX_HALF;
3007 			}
3008 		} else {
3009 			err = EINVAL;
3010 		}
3011 		break;
3012 	case MAC_PROP_SPEED:
3013 		if (pr_valsize >= sizeof (uint64_t)) {
3014 			switch (dp->speed) {
3015 			case USBGEM_SPD_1000:
3016 				tmp = 1000000000;
3017 				break;
3018 			case USBGEM_SPD_100:
3019 				tmp = 100000000;
3020 				break;
3021 			case USBGEM_SPD_10:
3022 				tmp = 10000000;
3023 				break;
3024 			default:
3025 				tmp = 0;
3026 			}
3027 			bcopy(&tmp, pr_val, sizeof (tmp));
3028 		} else {
3029 			err = EINVAL;
3030 		}
3031 		break;
3032 
3033 	case MAC_PROP_AUTONEG:
3034 		*(uint8_t *)pr_val = dp->anadv_autoneg;
3035 		break;
3036 
3037 	case MAC_PROP_FLOWCTRL:
3038 		if (pr_valsize >= sizeof (link_flowctrl_t)) {
3039 			switch (dp->flow_control) {
3040 			case FLOW_CONTROL_NONE:
3041 				flowctrl = LINK_FLOWCTRL_NONE;
3042 				break;
3043 			case FLOW_CONTROL_RX_PAUSE:
3044 				flowctrl = LINK_FLOWCTRL_RX;
3045 				break;
3046 			case FLOW_CONTROL_TX_PAUSE:
3047 				flowctrl = LINK_FLOWCTRL_TX;
3048 				break;
3049 			case FLOW_CONTROL_SYMMETRIC:
3050 				flowctrl = LINK_FLOWCTRL_BI;
3051 				break;
3052 			}
3053 			bcopy(&flowctrl, pr_val, sizeof (flowctrl));
3054 		} else {
3055 			err = EINVAL;
3056 		}
3057 		break;
3058 
3059 	case MAC_PROP_ADV_1000FDX_CAP:
3060 	case MAC_PROP_ADV_1000HDX_CAP:
3061 	case MAC_PROP_ADV_100FDX_CAP:
3062 	case MAC_PROP_ADV_100HDX_CAP:
3063 	case MAC_PROP_ADV_10FDX_CAP:
3064 	case MAC_PROP_ADV_10HDX_CAP:
3065 	case MAC_PROP_ADV_100T4_CAP:
3066 		usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val);
3067 		break;
3068 
3069 	case MAC_PROP_EN_1000FDX_CAP:
3070 		*(uint8_t *)pr_val = dp->anadv_1000fdx;
3071 		break;
3072 
3073 	case MAC_PROP_EN_1000HDX_CAP:
3074 		*(uint8_t *)pr_val = dp->anadv_1000hdx;
3075 		break;
3076 
3077 	case MAC_PROP_EN_100FDX_CAP:
3078 		*(uint8_t *)pr_val = dp->anadv_100fdx;
3079 		break;
3080 
3081 	case MAC_PROP_EN_100HDX_CAP:
3082 		*(uint8_t *)pr_val = dp->anadv_100hdx;
3083 		break;
3084 
3085 	case MAC_PROP_EN_10FDX_CAP:
3086 		*(uint8_t *)pr_val = dp->anadv_10fdx;
3087 		break;
3088 
3089 	case MAC_PROP_EN_10HDX_CAP:
3090 		*(uint8_t *)pr_val = dp->anadv_10hdx;
3091 		break;
3092 
3093 	case MAC_PROP_EN_100T4_CAP:
3094 		*(uint8_t *)pr_val = dp->anadv_100t4;
3095 		break;
3096 
3097 	case MAC_PROP_PRIVATE:
3098 		err = ENOTSUP;
3099 		break;
3100 
3101 	default:
3102 		err = ENOTSUP;
3103 		break;
3104 	}
3105 
3106 	rw_exit(&dp->dev_state_lock);
3107 	return (err);
3108 }
3109 #endif /* USBGEM_CONFIG_MAC_PROP */
3110 
3111 static void
usbgem_mac_ioctl(struct usbgem_dev * dp,queue_t * wq,mblk_t * mp)3112 usbgem_mac_ioctl(struct usbgem_dev *dp, queue_t *wq, mblk_t *mp)
3113 {
3114 	struct iocblk	*iocp;
3115 	enum ioc_reply	status;
3116 
3117 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3118 
3119 	/*
3120 	 * Validate the command before bothering with the mutex ...
3121 	 */
3122 	iocp = (void *)mp->b_rptr;
3123 	iocp->ioc_error = 0;
3124 
3125 	DPRINTF(1, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__,
3126 	    iocp->ioc_cmd));
3127 
3128 	miocnak(wq, mp, 0, EINVAL);
3129 }
3130 
3131 #ifndef SYS_MAC_H
3132 #define	XCVR_UNDEFINED	0
3133 #define	XCVR_NONE	1
3134 #define	XCVR_10		2
3135 #define	XCVR_100T4	3
3136 #define	XCVR_100X	4
3137 #define	XCVR_100T2	5
3138 #define	XCVR_1000X	6
3139 #define	XCVR_1000T	7
3140 #endif
3141 static int
usbgem_mac_xcvr_inuse(struct usbgem_dev * dp)3142 usbgem_mac_xcvr_inuse(struct usbgem_dev *dp)
3143 {
3144 	int	val = XCVR_UNDEFINED;
3145 
3146 	if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
3147 		if (dp->mii_status & MII_STATUS_100_BASE_T4) {
3148 			val = XCVR_100T4;
3149 		} else if (dp->mii_status &
3150 		    (MII_STATUS_100_BASEX_FD |
3151 		    MII_STATUS_100_BASEX)) {
3152 			val = XCVR_100X;
3153 		} else if (dp->mii_status &
3154 		    (MII_STATUS_100_BASE_T2_FD |
3155 		    MII_STATUS_100_BASE_T2)) {
3156 			val = XCVR_100T2;
3157 		} else if (dp->mii_status &
3158 		    (MII_STATUS_10_FD | MII_STATUS_10)) {
3159 			val = XCVR_10;
3160 		}
3161 	} else if (dp->mii_xstatus &
3162 	    (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
3163 		val = XCVR_1000T;
3164 	} else if (dp->mii_xstatus &
3165 	    (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
3166 		val = XCVR_1000X;
3167 	}
3168 
3169 	return (val);
3170 }
3171 
3172 /* ============================================================== */
3173 /*
3174  * GLDv3 interface
3175  */
3176 /* ============================================================== */
3177 static int	usbgem_m_getstat(void *, uint_t, uint64_t *);
3178 static int	usbgem_m_start(void *);
3179 static void	usbgem_m_stop(void *);
3180 static int	usbgem_m_setpromisc(void *, boolean_t);
3181 static int	usbgem_m_multicst(void *, boolean_t, const uint8_t *);
3182 static int	usbgem_m_unicst(void *, const uint8_t *);
3183 static mblk_t	*usbgem_m_tx(void *, mblk_t *);
3184 static void	usbgem_m_ioctl(void *, queue_t *, mblk_t *);
3185 static int	usbgem_m_setprop(void *, const char *, mac_prop_id_t,
3186     uint_t, const void *);
3187 static int	usbgem_m_getprop(void *, const char *, mac_prop_id_t,
3188     uint_t, void *);
3189 
3190 static mac_callbacks_t gem_m_callbacks = {
3191 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
3192 	usbgem_m_getstat,
3193 	usbgem_m_start,
3194 	usbgem_m_stop,
3195 	usbgem_m_setpromisc,
3196 	usbgem_m_multicst,
3197 	usbgem_m_unicst,
3198 	usbgem_m_tx,
3199 	NULL,
3200 	usbgem_m_ioctl,
3201 	NULL, /* m_getcapab */
3202 	NULL,
3203 	NULL,
3204 	usbgem_m_setprop,
3205 	usbgem_m_getprop,
3206 	usbgem_m_propinfo,
3207 };
3208 
3209 static int
usbgem_m_start(void * arg)3210 usbgem_m_start(void *arg)
3211 {
3212 	int	ret;
3213 	int	err;
3214 	struct usbgem_dev *dp = arg;
3215 
3216 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3217 
3218 	err = EIO;
3219 
3220 	rw_enter(&dp->dev_state_lock, RW_WRITER);
3221 	dp->nic_state = NIC_STATE_ONLINE;
3222 
3223 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
3224 		err = 0;
3225 		goto x;
3226 	}
3227 	if (usbgem_mac_init(dp) != USB_SUCCESS) {
3228 		goto x;
3229 	}
3230 
3231 	/* initialize rx filter state */
3232 	sema_p(&dp->rxfilter_lock);
3233 	dp->mc_count = 0;
3234 	dp->mc_count_req = 0;
3235 
3236 	bcopy(dp->dev_addr.ether_addr_octet,
3237 	    dp->cur_addr.ether_addr_octet, ETHERADDRL);
3238 	dp->rxmode |= RXMODE_ENABLE;
3239 
3240 	ret = usbgem_hal_set_rx_filter(dp);
3241 	sema_v(&dp->rxfilter_lock);
3242 
3243 	if (ret != USB_SUCCESS) {
3244 		goto x;
3245 	}
3246 
3247 	if (dp->mii_state == MII_STATE_LINKUP) {
3248 		/* setup media mode if the link have been up */
3249 		if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
3250 			goto x;
3251 		}
3252 		if (usbgem_mac_start(dp) != USB_SUCCESS) {
3253 			goto x;
3254 		}
3255 	}
3256 
3257 	err = 0;
3258 x:
3259 	rw_exit(&dp->dev_state_lock);
3260 	return (err);
3261 }
3262 
3263 static void
usbgem_m_stop(void * arg)3264 usbgem_m_stop(void *arg)
3265 {
3266 	struct usbgem_dev	*dp = arg;
3267 
3268 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3269 
3270 	/* stop rx gracefully */
3271 	rw_enter(&dp->dev_state_lock, RW_READER);
3272 	sema_p(&dp->rxfilter_lock);
3273 	dp->rxmode &= ~RXMODE_ENABLE;
3274 
3275 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3276 		(void) usbgem_hal_set_rx_filter(dp);
3277 	}
3278 	sema_v(&dp->rxfilter_lock);
3279 	rw_exit(&dp->dev_state_lock);
3280 
3281 	/* make the nic state inactive */
3282 	rw_enter(&dp->dev_state_lock, RW_WRITER);
3283 	dp->nic_state = NIC_STATE_STOPPED;
3284 
3285 	/* stop mac completely */
3286 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3287 		(void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
3288 	}
3289 	rw_exit(&dp->dev_state_lock);
3290 }
3291 
3292 static int
usbgem_m_multicst(void * arg,boolean_t add,const uint8_t * ep)3293 usbgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
3294 {
3295 	int	err;
3296 	int	ret;
3297 	struct usbgem_dev	*dp = arg;
3298 
3299 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3300 
3301 	rw_enter(&dp->dev_state_lock, RW_READER);
3302 	if (add) {
3303 		ret = usbgem_add_multicast(dp, ep);
3304 	} else {
3305 		ret = usbgem_remove_multicast(dp, ep);
3306 	}
3307 	rw_exit(&dp->dev_state_lock);
3308 
3309 	err = 0;
3310 	if (ret != USB_SUCCESS) {
3311 #ifdef GEM_CONFIG_FMA
3312 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
3313 #endif
3314 		err = EIO;
3315 	}
3316 
3317 	return (err);
3318 }
3319 
3320 static int
usbgem_m_setpromisc(void * arg,boolean_t on)3321 usbgem_m_setpromisc(void *arg, boolean_t on)
3322 {
3323 	int	err;
3324 	struct usbgem_dev	*dp = arg;
3325 
3326 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3327 
3328 	rw_enter(&dp->dev_state_lock, RW_READER);
3329 
3330 	sema_p(&dp->rxfilter_lock);
3331 	if (on) {
3332 		dp->rxmode |= RXMODE_PROMISC;
3333 	} else {
3334 		dp->rxmode &= ~RXMODE_PROMISC;
3335 	}
3336 
3337 	err = 0;
3338 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
3339 		if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
3340 			err = EIO;
3341 		}
3342 	}
3343 	sema_v(&dp->rxfilter_lock);
3344 
3345 	rw_exit(&dp->dev_state_lock);
3346 
3347 #ifdef GEM_CONFIG_FMA
3348 	if (err != 0) {
3349 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
3350 	}
3351 #endif
3352 	return (err);
3353 }
3354 
3355 int
usbgem_m_getstat(void * arg,uint_t stat,uint64_t * valp)3356 usbgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
3357 {
3358 	uint64_t	val;
3359 	struct usbgem_dev	*dp = arg;
3360 	struct usbgem_stats	*gstp = &dp->stats;
3361 
3362 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3363 
3364 	rw_enter(&dp->dev_state_lock, RW_READER);
3365 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
3366 		rw_exit(&dp->dev_state_lock);
3367 		return (0);
3368 	}
3369 
3370 	/* LINTED */
3371 	if (usbgem_hal_get_stats(dp) != USB_SUCCESS) {
3372 #ifdef GEM_CONFIG_FMA
3373 		rw_exit(&dp->dev_state_lock);
3374 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
3375 		return (EIO);
3376 #endif
3377 	}
3378 	rw_exit(&dp->dev_state_lock);
3379 
3380 	switch (stat) {
3381 	case MAC_STAT_IFSPEED:
3382 		val = usbgem_speed_value[dp->speed] *1000000ull;
3383 		break;
3384 
3385 	case MAC_STAT_MULTIRCV:
3386 		val = gstp->rmcast;
3387 		break;
3388 
3389 	case MAC_STAT_BRDCSTRCV:
3390 		val = gstp->rbcast;
3391 		break;
3392 
3393 	case MAC_STAT_MULTIXMT:
3394 		val = gstp->omcast;
3395 		break;
3396 
3397 	case MAC_STAT_BRDCSTXMT:
3398 		val = gstp->obcast;
3399 		break;
3400 
3401 	case MAC_STAT_NORCVBUF:
3402 		val = gstp->norcvbuf + gstp->missed;
3403 		break;
3404 
3405 	case MAC_STAT_IERRORS:
3406 		val = gstp->errrcv;
3407 		break;
3408 
3409 	case MAC_STAT_NOXMTBUF:
3410 		val = gstp->noxmtbuf;
3411 		break;
3412 
3413 	case MAC_STAT_OERRORS:
3414 		val = gstp->errxmt;
3415 		break;
3416 
3417 	case MAC_STAT_COLLISIONS:
3418 		val = gstp->collisions;
3419 		break;
3420 
3421 	case MAC_STAT_RBYTES:
3422 		val = gstp->rbytes;
3423 		break;
3424 
3425 	case MAC_STAT_IPACKETS:
3426 		val = gstp->rpackets;
3427 		break;
3428 
3429 	case MAC_STAT_OBYTES:
3430 		val = gstp->obytes;
3431 		break;
3432 
3433 	case MAC_STAT_OPACKETS:
3434 		val = gstp->opackets;
3435 		break;
3436 
3437 	case MAC_STAT_UNDERFLOWS:
3438 		val = gstp->underflow;
3439 		break;
3440 
3441 	case MAC_STAT_OVERFLOWS:
3442 		val = gstp->overflow;
3443 		break;
3444 
3445 	case ETHER_STAT_ALIGN_ERRORS:
3446 		val = gstp->frame;
3447 		break;
3448 
3449 	case ETHER_STAT_FCS_ERRORS:
3450 		val = gstp->crc;
3451 		break;
3452 
3453 	case ETHER_STAT_FIRST_COLLISIONS:
3454 		val = gstp->first_coll;
3455 		break;
3456 
3457 	case ETHER_STAT_MULTI_COLLISIONS:
3458 		val = gstp->multi_coll;
3459 		break;
3460 
3461 	case ETHER_STAT_SQE_ERRORS:
3462