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