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