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