1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * mii - MII/PHY support for MAC drivers 28 * 29 * Utility module to provide a consistent interface to a MAC driver accross 30 * different implementations of PHY devices 31 */ 32 33 #include <sys/types.h> 34 #include <sys/debug.h> 35 #include <sys/errno.h> 36 #include <sys/param.h> 37 #include <sys/sysmacros.h> 38 #include <sys/stropts.h> 39 #include <sys/stream.h> 40 #include <sys/kmem.h> 41 #include <sys/conf.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/devops.h> 45 #include <sys/modctl.h> 46 #include <sys/cmn_err.h> 47 #include <sys/miiregs.h> 48 #include "dnet_mii.h" 49 50 51 #ifdef DEBUG 52 #define MIIDEBUG 53 int miidebug = 0; 54 #define MIITRACE 1 55 #define MIIDUMP 2 56 #define MIIPROBE 4 57 #define MIICOMPAT 8 58 #endif 59 60 /* Local functions */ 61 static struct phydata *mii_get_valid_phydata(mii_handle_t mac, int phy); 62 static void mii_portmon(mii_handle_t mac); 63 64 /* Vendor specific callback function prototypes */ 65 static void dump_NS83840(mii_handle_t, int); 66 static void dump_ICS1890(struct mii_info *, int); 67 static int getspeed_NS83840(mii_handle_t, int, int *, int *); 68 static int getspeed_82553(mii_handle_t, int, int *, int *); 69 static int getspeed_ICS1890(mii_handle_t, int, int *, int *); 70 static int getspeed_generic(mii_handle_t, int, int *, int *); 71 static void postreset_ICS1890(mii_handle_t mac, int phy); 72 static void postreset_NS83840(mii_handle_t mac, int phy); 73 74 /* 75 * MII Interface functions 76 */ 77 78 /* 79 * Register an instance of an MII interface user 80 */ 81 82 int 83 mii_create(dev_info_t *dip, /* Passed to read/write functions */ 84 mii_writefunc_t writefunc, /* How to write to a MII register */ 85 mii_readfunc_t readfunc, /* How to read from a MII regster */ 86 mii_handle_t *macp) 87 { 88 mii_handle_t mac; 89 90 /* Allocate space for the mii structure */ 91 if ((mac = (mii_handle_t) 92 kmem_zalloc(sizeof (struct mii_info), KM_NOSLEEP)) == NULL) 93 return (MII_NOMEM); 94 95 mac->mii_write = writefunc; 96 mac->mii_read = readfunc; 97 mac->mii_dip = dip; 98 *macp = mac; 99 return (MII_SUCCESS); 100 } 101 102 /* 103 * Returns true if PHY at address phy is accessible. This should be 104 * considered the only function that takes a PHY address that can be called 105 * before mii_init_phy. There should be at least one bit set in the status 106 * register, and at least one clear 107 */ 108 int 109 mii_probe_phy(mii_handle_t mac, int phy) 110 { 111 ushort_t status; 112 dev_info_t *dip; 113 114 if (!mac || phy < 0 || phy > 31) 115 return (MII_PARAM); 116 117 dip = mac->mii_dip; 118 119 /* Clear any latched bits by reading twice */ 120 mac->mii_read(dip, phy, MII_STATUS); 121 status = mac->mii_read(dip, phy, MII_STATUS); 122 123 #ifdef MIIDEBUG 124 mac->mii_read(dip, phy, MII_CONTROL); 125 if (miidebug & MIIPROBE) 126 cmn_err(CE_NOTE, "PHY Probe: Control=%x, Status=%x", 127 mac->mii_read(dip, phy, MII_CONTROL), status); 128 #endif 129 /* 130 * At least one bit in status should be clear (one of the error 131 * bits), and there must be at least one bit set for the device 132 * capabilities. Unconnected devices tend to show 0xffff, but 0x0000 133 * has been seen. 134 */ 135 136 if (status == 0xffff || status == 0x0000) 137 return (MII_PHYNOTPRESENT); 138 return (MII_SUCCESS); 139 } 140 141 /* 142 * Initialise PHY, and store info about it in the handle for future 143 * reference when the MAC calls us. PHY Vendor-specific code here isolates 144 * the LAN driver from worrying about different PHY implementations 145 */ 146 147 int 148 mii_init_phy(mii_handle_t mac, int phy) 149 { 150 ushort_t status; 151 void *dip; 152 struct phydata *phydata; 153 154 if ((mac == (mii_handle_t)NULL) || phy < 0 || phy > 31) 155 return (MII_PARAM); 156 157 dip = mac->mii_dip; 158 159 /* Create a phydata structure for this new phy */ 160 if (mac->phys[phy]) 161 return (MII_PHYPRESENT); 162 163 mac->phys[phy] = phydata = (struct phydata *) 164 kmem_zalloc(sizeof (struct phydata), KM_NOSLEEP); 165 166 if (!phydata) 167 return (MII_NOMEM); 168 169 phydata->id = (ulong_t)mac->mii_read(dip, phy, MII_PHYIDH) << 16; 170 phydata->id |= (ulong_t)mac->mii_read(dip, phy, MII_PHYIDL); 171 phydata->state = phy_state_unknown; 172 173 /* Override speed and duplex mode from conf-file if present */ 174 phydata->fix_duplex = 175 ddi_getprop(DDI_DEV_T_NONE, 176 mac->mii_dip, DDI_PROP_DONTPASS, "full-duplex", 0); 177 178 phydata->fix_speed = 179 ddi_getprop(DDI_DEV_T_NONE, 180 mac->mii_dip, DDI_PROP_DONTPASS, "speed", 0); 181 182 status = mac->mii_read(dip, phy, MII_STATUS); 183 184 /* 185 * when explicitly setting speed or duplex, we must 186 * disable autonegotiation 187 */ 188 if (!(status & MII_STATUS_CANAUTONEG) || 189 phydata->fix_speed || phydata->fix_duplex) { 190 /* 191 * If local side cannot autonegotiate, we can't try to enable 192 * full duplex without the user's consent, because we cannot 193 * tell without AN if the partner can support it 194 */ 195 if ((status & (MII_STATUS_100_BASEX | MII_STATUS_100_BASEX_FD | 196 MII_STATUS_100_BASE_T4)) && phydata->fix_speed == 0) { 197 phydata->fix_speed = 100; 198 } else if ((status & (MII_STATUS_10 | MII_STATUS_10_FD)) && 199 phydata->fix_speed == 0) { 200 phydata->fix_speed = 10; 201 } else if (phydata->fix_speed == 0) { 202 /* A very stupid PHY would not be supported */ 203 kmem_free(mac->phys[phy], sizeof (struct phydata)); 204 mac->phys[phy] = NULL; 205 return (MII_NOTSUPPORTED); 206 } 207 /* mii_sync will sort out the speed selection on the PHY */ 208 } else 209 phydata->control = MII_CONTROL_ANE; 210 211 switch (MII_PHY_MFG(phydata->id)) { 212 case OUI_NATIONAL_SEMICONDUCTOR: 213 switch (MII_PHY_MODEL(phydata->id)) { 214 case NS_DP83840: 215 phydata->phy_postreset = postreset_NS83840; 216 phydata->phy_dump = dump_NS83840; 217 phydata->description = 218 "National Semiconductor DP-83840"; 219 phydata->phy_getspeed = getspeed_NS83840; 220 break; 221 default: 222 phydata->description = "Unknown NS"; 223 break; 224 } 225 break; 226 227 case OUI_INTEL: 228 switch (MII_PHY_MODEL(phydata->id)) { 229 case INTEL_82553_CSTEP: 230 phydata->description = "Intel 82553 C-step"; 231 phydata->phy_getspeed = getspeed_82553; 232 break; 233 case INTEL_82555: 234 phydata->description = "Intel 82555"; 235 phydata->phy_getspeed = getspeed_82553; 236 break; 237 case INTEL_82562_EH: 238 phydata->description = "Intel 82562 EH"; 239 phydata->phy_getspeed = getspeed_82553; 240 break; 241 case INTEL_82562_ET: 242 phydata->description = "Intel 82562 ET"; 243 phydata->phy_getspeed = getspeed_82553; 244 break; 245 case INTEL_82562_EM: 246 phydata->description = "Intel 82562 EM"; 247 phydata->phy_getspeed = getspeed_82553; 248 break; 249 default: 250 phydata->description = "Unknown INTEL"; 251 break; 252 } 253 break; 254 255 case OUI_ICS: 256 switch (MII_PHY_MODEL(phydata->id)) { 257 case ICS_1890: 258 case ICS_1889: 259 phydata->phy_postreset = postreset_ICS1890; 260 phydata->description = "ICS 1890/1889 PHY"; 261 phydata->phy_getspeed = getspeed_ICS1890; 262 phydata->phy_dump = dump_ICS1890; 263 break; 264 default: 265 phydata->description = "ICS Unknown PHY"; 266 break; 267 } 268 break; 269 270 default: /* Non-standard PHYs, that encode weird IDs */ 271 phydata->description = "Unknown PHY"; 272 phydata->phy_dump = NULL; 273 phydata->phy_getspeed = getspeed_generic; 274 break; 275 } 276 277 /* Do all post-reset hacks and user settings */ 278 (void) mii_sync(mac, phy); 279 280 if (ddi_getprop(DDI_DEV_T_NONE, mac->mii_dip, DDI_PROP_DONTPASS, 281 "dump-phy", 0)) 282 (void) mii_dump_phy(mac, phy); 283 284 return (MII_SUCCESS); 285 } 286 287 /* 288 * Cause a reset on a PHY 289 */ 290 291 int 292 mii_reset_phy(mii_handle_t mac, int phy, enum mii_wait_type wait) 293 { 294 int i; 295 struct phydata *phyd; 296 ushort_t control; 297 if (!(phyd = mii_get_valid_phydata(mac, phy))) 298 return (MII_PARAM); 299 300 /* Strobe the reset bit in the control register */ 301 mac->mii_write(mac->mii_dip, phy, MII_CONTROL, 302 phyd->control | MII_CONTROL_RESET); 303 304 phyd->state = phy_state_unknown; 305 306 /* 307 * This is likely to be very fast (ie, by the time we read the 308 * control register once, the devices we have seen can have already 309 * reset), but according to 802.3u 22.2.4.1.1, it could be up to .5 sec. 310 */ 311 if (wait == mii_wait_interrupt || wait == mii_wait_user) { 312 for (i = 100; i--; ) { 313 control = mac->mii_read(mac->mii_dip, phy, MII_CONTROL); 314 if (!(control & MII_CONTROL_RESET)) 315 break; 316 drv_usecwait(10); 317 } 318 if (i) 319 goto reset_completed; 320 } 321 322 if (wait == mii_wait_user) { 323 for (i = 50; i--; ) { 324 control = mac->mii_read(mac->mii_dip, phy, MII_CONTROL); 325 if (!(control & MII_CONTROL_RESET)) 326 break; 327 delay(drv_usectohz(10000)); 328 } 329 if (i) 330 goto reset_completed; 331 return (MII_HARDFAIL); /* It MUST reset within this time */ 332 333 } 334 return (MII_TIMEOUT); 335 336 reset_completed: 337 (void) mii_sync(mac, phy); 338 return (MII_SUCCESS); 339 } 340 341 /* 342 * This routine is called to synchronise the software and the PHY. It should 343 * be called after the PHY is reset, and after initialising the PHY. This 344 * routine is external because devices (DNET) can reset the PHY in ways beyond 345 * the control of the mii interface. Should this happen, the driver is 346 * required to call mii_sync(). 347 * If the PHY is resetting still when this is called, it will do nothing, 348 * but, it will be retriggered when the portmon timer expires. 349 */ 350 351 int 352 mii_sync(mii_handle_t mac, int phy) 353 { 354 struct phydata *phyd = mac->phys[phy]; 355 int len, i, numprop; 356 struct regprop { 357 int reg; 358 int value; 359 } *regprop; 360 361 #ifdef MIIDEBUG 362 if (miidebug & MIITRACE) 363 cmn_err(CE_NOTE, "mii_sync (phy addr %d)", phy); 364 #endif 365 366 len = 0; 367 /* 368 * Conf file can specify a sequence of values to write to 369 * the PHY registers if required 370 */ 371 if (ddi_getlongprop(DDI_DEV_T_ANY, mac->mii_dip, 372 DDI_PROP_DONTPASS, "phy-registers", (caddr_t)®prop, 373 &len) == DDI_PROP_SUCCESS) { 374 numprop = len / sizeof (struct regprop); 375 for (i = 0; i < numprop; i++) { 376 mac->mii_write(mac->mii_dip, phy, 377 regprop[i].reg, regprop[i].value); 378 #ifdef MIIDEBUG 379 if (miidebug & MIITRACE) 380 cmn_err(CE_NOTE, "PHY Write reg %d=%x", 381 regprop[i].reg, regprop[i].value); 382 #endif 383 } 384 kmem_free(regprop, len); 385 } else { 386 mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control); 387 if (phyd->phy_postreset) 388 phyd->phy_postreset(mac, phy); 389 if (phyd->fix_speed || phyd->fix_duplex) { 390 /* XXX function return value ignored */ 391 (void) mii_fixspeed(mac, phy, phyd->fix_speed, 392 phyd->fix_duplex); 393 } 394 } 395 return (MII_SUCCESS); 396 } 397 398 /* 399 * Disable full-duplex negotiation on the PHY. This is useful if the 400 * driver or link-partner is advertising full duplex, but does not support 401 * it properly (as some previous solaris drivers didn't) 402 */ 403 404 int 405 mii_disable_fullduplex(mii_handle_t mac, int phy) 406 { 407 void *dip = mac->mii_dip; 408 ushort_t expansion, miiadvert; 409 /* dont advertise full duplex capabilites */ 410 const int fullduplex = MII_ABILITY_10BASE_T_FD 411 | MII_ABILITY_100BASE_TX_FD; 412 413 if (!(mac->mii_read(dip, phy, MII_STATUS) & MII_STATUS_CANAUTONEG)) { 414 /* 415 * Local side cannot autonegotiate, so full duplex should 416 * never be negotiated. Consider it as a success 417 */ 418 return (MII_SUCCESS); 419 } 420 421 /* Change what we advertise if it includes full duplex */ 422 423 miiadvert = mac->mii_read(dip, phy, MII_AN_ADVERT); 424 if (miiadvert & fullduplex) 425 mac->mii_write(dip, phy, MII_AN_ADVERT, 426 miiadvert & ~fullduplex); 427 428 /* See what other end is able to do. */ 429 430 expansion = mac->mii_read(dip, phy, MII_AN_EXPANSION); 431 432 /* 433 * Renegotiate if the link partner supports autonegotiation 434 * If it doesn't, we will never have auto-negotiated full duplex 435 * anyway 436 */ 437 438 if (expansion & MII_AN_EXP_LPCANAN) 439 return (mii_rsan(mac, phy, mii_wait_none)); 440 else 441 return (MII_SUCCESS); 442 } 443 444 /* 445 * (re)enable autonegotiation on a PHY. 446 */ 447 448 int 449 mii_autoneg_enab(mii_handle_t mac, int phy) 450 { 451 struct phydata *phyd; 452 if (!(phyd = mii_get_valid_phydata(mac, phy))) 453 return (MII_PARAM); 454 phyd->control |= MII_CONTROL_ANE; 455 mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control); 456 return (MII_SUCCESS); 457 } 458 459 /* 460 * Check the link status of a PHY connection 461 */ 462 int 463 mii_linkup(mii_handle_t mac, int phy) 464 { 465 ushort_t status; 466 467 /* 468 * Link status latches, so we need to read it twice, to make sure we 469 * get its current status 470 */ 471 mac->mii_read(mac->mii_dip, phy, MII_STATUS); 472 status = mac->mii_read(mac->mii_dip, phy, MII_STATUS); 473 474 if (status != 0xffff && (status & MII_STATUS_LINKUP)) 475 return (1); 476 else 477 return (0); 478 } 479 480 /* 481 * Discover what speed the PHY is running at, irrespective of wheather it 482 * autonegotiated this, or was fixed at that rate. 483 */ 484 485 int 486 mii_getspeed(mii_handle_t mac, int phy, int *speed, int *fulld) 487 { 488 struct phydata *phyd; 489 490 if (!(phyd = mii_get_valid_phydata(mac, phy))) 491 return (MII_PARAM); 492 if (!(phyd->control & MII_CONTROL_ANE)) { 493 /* 494 * user has requested fixed speed operation, return what we 495 * wrote to the control registerfrom control register 496 */ 497 498 *speed = phyd->control & MII_CONTROL_100MB ? 100:10; 499 *fulld = phyd->control & MII_CONTROL_FDUPLEX ? 1:0; 500 return (MII_SUCCESS); 501 } 502 503 if (!phyd->phy_getspeed) /* No standard way to do this(!) */ 504 return (MII_NOTSUPPORTED); 505 506 return (phyd->phy_getspeed(mac, phy, speed, fulld)); 507 } 508 509 /* 510 * Fix the speed and duplex mode of a PHY 511 */ 512 513 int 514 mii_fixspeed(mii_handle_t mac, int phy, int speed, int fullduplex) 515 { 516 struct phydata *phyd; 517 518 #ifdef MIIDEBUG 519 cmn_err(CE_CONT, "!%s: setting speed to %d, %s duplex", 520 ddi_get_name(mac->mii_dip), speed, 521 fullduplex ? "full" : "half"); 522 #endif 523 524 if (!(phyd = mii_get_valid_phydata(mac, phy))) 525 return (MII_PARAM); 526 phyd->control &= ~MII_CONTROL_ANE; 527 528 if (speed == 100) 529 phyd->control |= MII_CONTROL_100MB; 530 else if (speed == 10) 531 phyd->control &= ~MII_CONTROL_100MB; 532 else 533 cmn_err(CE_NOTE, "%s: mii does not support %d Mb/s speed", 534 ddi_get_name(mac->mii_dip), speed); 535 536 if (fullduplex) 537 phyd->control |= MII_CONTROL_FDUPLEX; 538 else 539 phyd->control &= ~MII_CONTROL_FDUPLEX; 540 541 mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control); 542 phyd->fix_speed = speed; 543 phyd->fix_duplex = fullduplex; 544 return (MII_SUCCESS); 545 } 546 /* 547 * Electrically isolate/unisolate the PHY 548 */ 549 550 int 551 mii_isolate(mii_handle_t mac, int phy) 552 { 553 struct phydata *phyd; 554 555 if (!(phyd = mii_get_valid_phydata(mac, phy))) 556 return (MII_PARAM); 557 558 phyd->control |= MII_CONTROL_ISOLATE; 559 mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control); 560 561 /* Wait for device to settle */ 562 drv_usecwait(50); 563 return (MII_SUCCESS); 564 } 565 566 int 567 mii_unisolate(mii_handle_t mac, int phy) 568 { 569 struct phydata *phyd; 570 571 if (!(phyd = mii_get_valid_phydata(mac, phy))) 572 return (MII_PARAM); 573 574 phyd->control &= ~MII_CONTROL_ISOLATE; 575 mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control); 576 return (MII_SUCCESS); 577 } 578 579 /* 580 * Restart autonegotiation on a PHY 581 */ 582 583 int 584 mii_rsan(mii_handle_t mac, int phy, enum mii_wait_type wait) 585 { 586 int i; 587 void *dip; 588 struct phydata *phyd; 589 590 if (wait == mii_wait_interrupt || 591 !(phyd = mii_get_valid_phydata(mac, phy))) 592 return (MII_PARAM); 593 594 if (phyd->fix_speed) 595 return (MII_STATE); 596 597 dip = mac->mii_dip; 598 599 phyd->control |= MII_CONTROL_ANE; 600 mac->mii_write(dip, phy, MII_CONTROL, phyd->control|MII_CONTROL_RSAN); 601 602 /* 603 * This can take ages (a second or so). It makes more sense to use 604 * the port monitor rather than waiting for completion of this on the 605 * PHY. It is pointless doing a busy wait here 606 */ 607 608 if (wait == mii_wait_user) { 609 for (i = 200; i--; ) { 610 delay(drv_usectohz(10000)); 611 if (mac->mii_read(dip, phy, MII_STATUS) & 612 MII_STATUS_ANDONE) 613 return (MII_SUCCESS); 614 } 615 cmn_err(CE_NOTE, 616 "!%s:Timed out waiting for autonegotiation", 617 ddi_get_name(mac->mii_dip)); 618 return (MII_TIMEOUT); 619 } 620 return (MII_TIMEOUT); 621 } 622 623 /* 624 * Debuging function to dump contents of PHY registers 625 */ 626 int 627 mii_dump_phy(mii_handle_t mac, int phy) 628 { 629 struct phydata *phydat; 630 631 char *miiregs[] = { 632 "Control ", 633 "Status ", 634 "PHY Id(H) ", 635 "PHY Id(L) ", 636 "Advertisement ", 637 "Link Partner Ability", 638 "Expansion ", 639 "Next Page Transmit ", 640 0 641 }; 642 int i; 643 644 if (!(phydat = mii_get_valid_phydata(mac, phy))) 645 return (MII_PARAM); 646 647 cmn_err(CE_NOTE, "%s: PHY %d, type %s", ddi_get_name(mac->mii_dip), phy, 648 phydat->description ? phydat->description: "Unknown"); 649 650 for (i = 0; miiregs[i]; i++) 651 cmn_err(CE_NOTE, "%s:\t%x", 652 miiregs[i], mac->mii_read(mac->mii_dip, phy, i)); 653 654 if (phydat->phy_dump) 655 phydat->phy_dump((struct mii_info *)mac, phy); 656 657 return (MII_SUCCESS); 658 } 659 660 /* 661 * Start a periodic check to monitor the MII devices attached, and callback 662 * to the MAC driver when the state on a device changes 663 */ 664 665 int 666 mii_start_portmon(mii_handle_t mac, mii_linkfunc_t notify, kmutex_t *lock) 667 { 668 if (mac->mii_linknotify || mac->portmon_timer) 669 return (MII_STATE); 670 mac->mii_linknotify = notify; 671 /* 672 * NOTE: Portmon is normally called through a timeout. In the case 673 * of starting off, we assume that the lock is already held 674 */ 675 mac->lock = NULL; /* portmon wont try to aquire any lock this time */ 676 mii_portmon(mac); 677 mac->lock = lock; 678 return (MII_SUCCESS); 679 } 680 681 int 682 mii_stop_portmon(mii_handle_t mac) 683 { 684 if (!mac->mii_linknotify || !mac->portmon_timer) 685 return (MII_STATE); 686 687 mac->mii_linknotify = NULL; 688 mac->lock = NULL; 689 (void) untimeout(mac->portmon_timer); 690 mac->portmon_timer = 0; 691 return (MII_SUCCESS); 692 } 693 694 static void 695 mii_portmon(mii_handle_t mac) 696 { 697 int i; 698 enum mii_phy_state state; 699 struct phydata *phydata; 700 701 /* 702 * There is a potential deadlock between this test and the 703 * mutex_enter 704 */ 705 if (!mac->mii_linknotify) /* Exiting */ 706 return; 707 708 if (mac->lock) 709 mutex_enter(mac->lock); 710 711 /* 712 * For each initialised phy, see if the link state has changed, and 713 * callback to the mac driver if it has 714 */ 715 for (i = 0; i < 32; i++) { 716 if ((phydata = mac->phys[i]) != 0) { 717 state = mii_linkup(mac, i) ? 718 phy_state_linkup : phy_state_linkdown; 719 if (state != phydata->state) { 720 #ifdef MIIDEBUG 721 if (miidebug) 722 cmn_err(CE_NOTE, "%s: PHY %d link %s", 723 ddi_get_name(mac->mii_dip), i, 724 state == phy_state_linkup ? 725 "up" : "down"); 726 #endif 727 phydata->state = state; 728 mac->mii_linknotify(mac->mii_dip, i, state); 729 } 730 } 731 } 732 /* Check the ports every 5 seconds */ 733 mac->portmon_timer = timeout((void (*)(void*))mii_portmon, (void *)mac, 734 (clock_t)(5 * drv_usectohz(1000000))); 735 if (mac->lock) 736 mutex_exit(mac->lock); 737 } 738 739 /* 740 * Close a handle to the MII interface from a registered user 741 */ 742 743 void 744 mii_destroy(mii_handle_t mac) 745 { 746 /* Free per-PHY information */ 747 int i; 748 749 (void) mii_stop_portmon(mac); 750 751 for (i = 0; i < 32; i++) 752 if (mac->phys[i]) 753 kmem_free(mac->phys[i], sizeof (struct phydata)); 754 755 kmem_free(mac, sizeof (*mac)); 756 } 757 758 /* 759 * Get a PHY data structure from an MII handle, and validate the common 760 * parameters to the MII functions. Used to verify parameters in most MII 761 * functions 762 */ 763 static struct phydata * 764 mii_get_valid_phydata(mii_handle_t mac, int phy) 765 { 766 if (!mac || phy > 31 || phy < 0 || !mac->phys[phy]) { 767 ASSERT(!"MII: Bad invocation"); 768 return (NULL); 769 } 770 return (mac->phys[phy]); 771 } 772 /* 773 * Device-specific routines - National Semiconductor 774 */ 775 776 #define BIT(bit, value) ((value) & (1<<(bit))) 777 static void 778 dump_NS83840(mii_handle_t mac, int phy) 779 { 780 ushort_t reg; 781 void *dip; 782 783 dip = mac->mii_dip; 784 cmn_err(CE_NOTE, "Disconnect count: %x", 785 mac->mii_read(dip, phy, 0x12)); 786 cmn_err(CE_NOTE, "False Carrier detect count: %x", 787 mac->mii_read(dip, phy, 0x13)); 788 cmn_err(CE_NOTE, "Receive error count: %x", 789 mac->mii_read(dip, phy, 0x15)); 790 cmn_err(CE_NOTE, "Silicon revision: %x", 791 mac->mii_read(dip, phy, 0x16)); 792 cmn_err(CE_NOTE, "PCS Configuration : %x", 793 mac->mii_read(dip, phy, 0x17)); 794 795 cmn_err(CE_NOTE, "Loopback, Bypass and Receiver error mask: %x", 796 mac->mii_read(dip, phy, 0x18)); 797 cmn_err(CE_NOTE, "Wired phy address: %x", 798 mac->mii_read(dip, phy, 0x19)&0xf); 799 800 reg = mac->mii_read(dip, phy, 0x1b); 801 cmn_err(CE_NOTE, "10 Base T in %s mode", 802 BIT(9, reg) ? "serial":"nibble"); 803 804 cmn_err(CE_NOTE, "%slink pulses, %sheartbeat, %s,%s squelch,jabber %s", 805 BIT(reg, 5) ? "" : "no ", 806 BIT(reg, 4) ? "" : "no ", 807 BIT(reg, 3) ? "UTP" : "STP", 808 BIT(reg, 2) ? "low" : "normal", 809 BIT(reg, 0) ? "enabled" : "disabled"); 810 } 811 812 static int 813 getspeed_NS83840(mii_handle_t mac, int phy, int *speed, int *fulld) 814 { 815 int exten = mac->mii_read(mac->mii_dip, phy, MII_AN_EXPANSION); 816 if (exten & MII_AN_EXP_LPCANAN) { 817 /* 818 * Link partner can auto-neg, take speed from LP Ability 819 * register 820 */ 821 int lpable, anadv, mask; 822 823 lpable = mac->mii_read(mac->mii_dip, phy, MII_AN_LPABLE); 824 anadv = mac->mii_read(mac->mii_dip, phy, MII_AN_ADVERT); 825 mask = anadv & lpable; 826 827 if (mask & MII_ABILITY_100BASE_TX_FD) { 828 *speed = 100; 829 *fulld = 1; 830 } else if (mask & MII_ABILITY_100BASE_T4) { 831 *speed = 100; 832 *fulld = 0; 833 } else if (mask & MII_ABILITY_100BASE_TX) { 834 *speed = 100; 835 *fulld = 0; 836 } else if (mask & MII_ABILITY_10BASE_T_FD) { 837 *speed = 10; 838 *fulld = 1; 839 } else if (mask & MII_ABILITY_10BASE_T) { 840 *speed = 10; 841 *fulld = 0; 842 } 843 } else { 844 int addr = mac->mii_read(mac->mii_dip, phy, MII_83840_ADDR); 845 *speed = (addr & NS83840_ADDR_SPEED10) ? 10:100; 846 /* No fullduplex without autonegotiation on link partner */ 847 *fulld = 0; 848 } 849 return (0); 850 } 851 852 /* 853 * Device-specific routines - INTEL 854 */ 855 856 static int 857 getspeed_82553(mii_handle_t mac, int phy, int *speed, int *fulld) 858 { 859 int ex0 = mac->mii_read(mac->mii_dip, phy, MII_82553_EX0); 860 *fulld = (ex0 & I82553_EX0_FDUPLEX) ? 1:0; 861 *speed = (ex0 & I82553_EX0_100MB) ? 100:10; 862 return (0); 863 } 864 865 /* 866 * Device-specific routines - ICS 867 */ 868 869 static int 870 getspeed_ICS1890(mii_handle_t mac, int phy, int *speed, int *fulld) 871 { 872 ushort_t quickpoll = mac->mii_read(mac->mii_dip, phy, ICS_QUICKPOLL); 873 *speed = (quickpoll & ICS_QUICKPOLL_100MB) ? 100 : 10; 874 *fulld = (quickpoll & ICS_QUICKPOLL_FDUPLEX) ? 1 : 0; 875 return (0); 876 } 877 878 static void 879 dump_ICS1890(mii_handle_t mac, int phy) 880 { 881 ushort_t quickpoll = mac->mii_read(mac->mii_dip, phy, ICS_QUICKPOLL); 882 cmn_err(CE_NOTE, "QuickPoll:%x (Speed:%d FullDuplex:%c) ", 883 quickpoll, 884 quickpoll & ICS_QUICKPOLL_100MB ? 100:10, 885 quickpoll & ICS_QUICKPOLL_FDUPLEX ? 'Y' : 'N'); 886 } 887 888 static void 889 postreset_NS83840(mii_handle_t mac, int phy) 890 { 891 ushort_t reg; 892 struct phydata *phyd = mac->phys[phy]; 893 /* 894 * As per INTEL "PRO/100B Adapter Software Technical 895 * Reference Manual", set bit 10 of MII register 23. 896 * National Semiconductor documentation shows this as 897 * "reserved, write to as zero". We also set the 898 * "f_connect" bit, also as requested by the PRO/100B 899 * doc 900 */ 901 902 reg = mac->mii_read(mac->mii_dip, phy, 23) | (1<<10) | (1<<5); 903 mac->mii_write(mac->mii_dip, phy, 23, reg); 904 905 /* 906 * Some of thses PHYs seem to reset with the wrong value in the 907 * AN advertisment register. It should containt 1e1, indicating that 908 * the device can do 802.3 10BASE-T, 10BASE-T Full duplex, 100BASE-TX, 909 * and 100 BASE-TX full duplex. Instead it seems to advertise only 910 * 100BASE-TX Full duplex. The result of this is that the device will 911 * NOT autonegotiate at all against a 10MB only or 100MB/Half duplex 912 * autonegotiating hub 913 * NEEDSWORK: 914 * There is possibly a time-dependancy here. 915 * If the autonegotiation has completed BEFORE we get to here 916 * (after the reset) then this could possibly have not effect 917 */ 918 if (!phyd->fix_speed) { 919 #ifdef MIIDEBUG 920 if (miidebug & MIICOMPAT) 921 cmn_err(CE_NOTE, "Reset value of AN_ADV reg:%x", 922 mac->mii_read(mac->mii_dip, phy, MII_AN_ADVERT)); 923 #endif 924 mac->mii_write(mac->mii_dip, phy, MII_AN_ADVERT, 0x1e1); 925 } 926 } 927 928 void 929 postreset_ICS1890(mii_handle_t mac, int phy) 930 { 931 /* This device comes up isolated if no link is found */ 932 (void) mii_unisolate(mac, phy); 933 } 934 935 /* 936 * generic getspeed routine 937 */ 938 static int 939 getspeed_generic(mii_handle_t mac, int phy, int *speed, int *fulld) 940 { 941 int exten = mac->mii_read(mac->mii_dip, phy, MII_AN_EXPANSION); 942 if (exten & MII_AN_EXP_LPCANAN) { 943 /* 944 * Link partner can auto-neg, take speed from LP Ability 945 * register 946 */ 947 int lpable, anadv, mask; 948 949 lpable = mac->mii_read(mac->mii_dip, phy, MII_AN_LPABLE); 950 anadv = mac->mii_read(mac->mii_dip, phy, MII_AN_ADVERT); 951 mask = anadv & lpable; 952 953 if (mask & MII_ABILITY_100BASE_TX_FD) { 954 *speed = 100; 955 *fulld = 1; 956 } else if (mask & MII_ABILITY_100BASE_T4) { 957 *speed = 100; 958 *fulld = 0; 959 } else if (mask & MII_ABILITY_100BASE_TX) { 960 *speed = 100; 961 *fulld = 0; 962 } else if (mask & MII_ABILITY_10BASE_T_FD) { 963 *speed = 10; 964 *fulld = 1; 965 } else if (mask & MII_ABILITY_10BASE_T) { 966 *speed = 10; 967 *fulld = 0; 968 } 969 } else { 970 /* 971 * Link partner cannot auto-neg, it would be nice if we 972 * could figure out what the device selected. (NWay?) 973 */ 974 *speed = 0; 975 *fulld = 0; 976 } 977 return (MII_SUCCESS); 978 }