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