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